mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-12-20 11:59:40 -06:00
Compare commits
68 Commits
vbsd
...
feature/k8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
166a283c70 | ||
|
|
1941679d27 | ||
|
|
85672e060a | ||
|
|
18feea5fed | ||
|
|
e54faa3820 | ||
|
|
4ecb6ae30e | ||
|
|
c708246f73 | ||
|
|
295ba628c2 | ||
|
|
d8f74f008f | ||
|
|
42a71bbeab | ||
|
|
98d2f25af2 | ||
|
|
dd9d94f75f | ||
|
|
f08df25085 | ||
| 1bdce8384f | |||
| 15954413ae | |||
| fddf99946f | |||
|
|
ef6f2f133e | ||
|
|
46ac039a3b | ||
|
|
ffa2f9986c | ||
|
|
d2d67384a7 | ||
|
|
dbf37c2d2b | ||
|
|
81dc4e2216 | ||
|
|
6de224a2fa | ||
|
|
5e9355b1ff | ||
|
|
6b9798595e | ||
|
|
e58218cfbc | ||
|
|
fcf4d6c6fa | ||
|
|
c1e8546d48 | ||
|
|
c07c909a57 | ||
| 42ffd00478 | |||
|
|
799269c79e | ||
|
|
e2391665b9 | ||
|
|
24c2361248 | ||
|
|
511672c5cb | ||
|
|
c0b969e3f0 | ||
| 1f399a7277 | |||
| 3d85f6639e | |||
|
|
731b828c12 | ||
|
|
eca87c7257 | ||
|
|
0b9dbaedbf | ||
| 7de07a7722 | |||
|
|
62a1e135c3 | ||
|
|
de0b560a8c | ||
| e8a0f50ec9 | |||
| b3564cb9ea | |||
|
|
3df3552467 | ||
|
|
a1f8ab763d | ||
|
|
0c32be01ba | ||
|
|
8a15906885 | ||
|
|
af70f871cb | ||
|
|
fd20baaf09 | ||
|
|
0217f88c44 | ||
|
|
198b3371c5 | ||
|
|
4e5facd0c5 | ||
|
|
c931f5d456 | ||
| df83f0d847 | |||
|
|
9c5388c70e | ||
|
|
1a199151da | ||
|
|
98dc291b57 | ||
|
|
1001e41528 | ||
|
|
59bf91b14f | ||
|
|
50ad2a29ec | ||
|
|
81b1b73f04 | ||
|
|
12ea2dfb2e | ||
|
|
d193fe61be | ||
|
|
511407c8ea | ||
|
|
df3515f474 | ||
|
|
a19bead268 |
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -17,3 +17,9 @@
|
||||
[submodule "thirdparty/AccountManager"]
|
||||
path = thirdparty/AccountManager
|
||||
url = https://github.com/DarkflameUniverse/AccountManager
|
||||
[submodule "thirdparty/magic_enum"]
|
||||
path = thirdparty/magic_enum
|
||||
url = https://github.com/Neargye/magic_enum.git
|
||||
[submodule "thirdparty/kubernetes-client-c"]
|
||||
path = thirdparty/kubernetes-client-c
|
||||
url = https://github.com/kubernetes-client/c
|
||||
|
||||
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.18)
|
||||
project(Darkflame)
|
||||
include(CTest)
|
||||
|
||||
set (CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
# Read variables from file
|
||||
FILE(READ "${CMAKE_SOURCE_DIR}/CMakeVariables.txt" variables)
|
||||
@@ -28,16 +28,13 @@ foreach(variable ${variables})
|
||||
# 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}")
|
||||
@@ -53,19 +50,21 @@ 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)
|
||||
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")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17 -O2 -Wuninitialized -fPIC")
|
||||
add_compile_definitions(_GLIBCXX_USE_CXX11_ABI=0 _GLIBCXX_USE_CXX17_ABI=0)
|
||||
if(NOT APPLE)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libgcc -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
|
||||
@@ -154,10 +153,7 @@ if (NOT EXISTS ${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
|
||||
)
|
||||
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)
|
||||
@@ -173,24 +169,14 @@ 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)
|
||||
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()
|
||||
configure_file(${CMAKE_SOURCE_DIR}/migrations/dlu/${file} ${PROJECT_BINARY_DIR}/migrations/dlu/${file})
|
||||
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)
|
||||
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()
|
||||
configure_file(${CMAKE_SOURCE_DIR}/migrations/cdserver/${file} ${PROJECT_BINARY_DIR}/migrations/cdserver/${file})
|
||||
endforeach()
|
||||
|
||||
# Create our list of include directories
|
||||
@@ -198,7 +184,9 @@ set(INCLUDED_DIRECTORIES
|
||||
"dCommon"
|
||||
"dCommon/dClient"
|
||||
"dCommon/dEnums"
|
||||
|
||||
"dChatFilter"
|
||||
|
||||
"dGame"
|
||||
"dGame/dBehaviors"
|
||||
"dGame/dComponents"
|
||||
@@ -209,10 +197,14 @@ set(INCLUDED_DIRECTORIES
|
||||
"dGame/dPropertyBehaviors"
|
||||
"dGame/dPropertyBehaviors/ControlBehaviorMessages"
|
||||
"dGame/dUtilities"
|
||||
|
||||
"dPhysics"
|
||||
|
||||
"dNavigation"
|
||||
"dNavigation/dTerrain"
|
||||
|
||||
"dZoneManager"
|
||||
|
||||
"dDatabase"
|
||||
"dDatabase/CDClientDatabase"
|
||||
"dDatabase/CDClientDatabase/CDClientTables"
|
||||
@@ -220,7 +212,9 @@ set(INCLUDED_DIRECTORIES
|
||||
"dDatabase/GameDatabase/ITables"
|
||||
"dDatabase/GameDatabase/MySQL"
|
||||
"dDatabase/GameDatabase/MySQL/Tables"
|
||||
|
||||
"dNet"
|
||||
|
||||
"dScripts"
|
||||
"dScripts/02_server"
|
||||
"dScripts/ai"
|
||||
@@ -269,6 +263,7 @@ set(INCLUDED_DIRECTORIES
|
||||
"dScripts/ai/GENERAL"
|
||||
"dScripts/ai/GF"
|
||||
"dScripts/ai/MINIGAME"
|
||||
"dScripts/ai/MINIGAME/Objects"
|
||||
"dScripts/ai/NP"
|
||||
"dScripts/ai/NS"
|
||||
"dScripts/ai/PETS"
|
||||
@@ -292,6 +287,7 @@ set(INCLUDED_DIRECTORIES
|
||||
"dScripts/zone/PROPERTY/GF"
|
||||
"dScripts/zone/PROPERTY/NS"
|
||||
|
||||
"thirdparty/magic_enum/include/magic_enum"
|
||||
"thirdparty/raknet/Source"
|
||||
"thirdparty/tinyxml2"
|
||||
"thirdparty/recastnavigation"
|
||||
@@ -302,28 +298,24 @@ set(INCLUDED_DIRECTORIES
|
||||
"tests/dCommonTests"
|
||||
"tests/dGameTests"
|
||||
"tests/dGameTests/dComponentsTests"
|
||||
)
|
||||
)
|
||||
|
||||
# Add system specfic includes for Apple, Windows and Other Unix OS' (including Linux)
|
||||
if (APPLE)
|
||||
include_directories("/usr/local/include/")
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include")
|
||||
elseif (UNIX)
|
||||
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt")
|
||||
set(INCLUDED_DIRECTORIES ${INCLUDED_DIRECTORIES} "thirdparty/libbcrypt/include/bcrypt")
|
||||
endif()
|
||||
|
||||
# Add binary directory as an include directory
|
||||
include_directories(${PROJECT_BINARY_DIR})
|
||||
|
||||
# Actually include the directories from our list
|
||||
foreach (dir ${INCLUDED_DIRECTORIES})
|
||||
include_directories(${PROJECT_SOURCE_DIR}/${dir})
|
||||
endforeach()
|
||||
|
||||
if (NOT WIN32)
|
||||
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include/bcrypt")
|
||||
endif()
|
||||
include_directories("${PROJECT_SOURCE_DIR}/thirdparty/libbcrypt/include")
|
||||
|
||||
|
||||
# Add linking directories:
|
||||
link_directories(${PROJECT_BINARY_DIR})
|
||||
|
||||
@@ -373,13 +365,13 @@ add_subdirectory(dNavigation)
|
||||
add_subdirectory(dPhysics)
|
||||
|
||||
# Create a list of common libraries shared between all binaries
|
||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp")
|
||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "mariadbConnCpp" "magic_enum")
|
||||
|
||||
# Add platform specific common libraries
|
||||
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()
|
||||
@@ -417,6 +409,6 @@ target_precompile_headers(
|
||||
"$<$<COMPILE_LANGUAGE:CXX>:${PROJECT_SOURCE_DIR}/thirdparty/tinyxml2/tinyxml2.h>"
|
||||
)
|
||||
|
||||
if (${__enable_testing__} MATCHES "1")
|
||||
if (${ENABLE_TESTING})
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
@@ -1,22 +1,32 @@
|
||||
PROJECT_VERSION_MAJOR=1
|
||||
PROJECT_VERSION_MINOR=1
|
||||
PROJECT_VERSION_PATCH=1
|
||||
# LICENSE
|
||||
LICENSE=AGPL-3.0
|
||||
|
||||
# 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.
|
||||
# __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 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 to the number of jobs (make -j equivalent) to compile the mariadbconn files with.
|
||||
__maria_db_connector_compile_jobs__=1
|
||||
MARIADB_CONNECTOR_COMPILE_JOBS=1
|
||||
|
||||
# When set to 1 and uncommented, compiling and linking testing folders and libraries will be done.
|
||||
__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/
|
||||
# Uncomment the below line to cache the entire CDClient into memory
|
||||
# CDCLIENT_CACHE_ALL=1
|
||||
|
||||
# Whether or not to cache the entire CDClient Database into memory instead of lazy loading.
|
||||
# 0 means to lazy load, all other values mean load the entire database.
|
||||
CDCLIENT_CACHE_ALL=0
|
||||
|
||||
@@ -23,6 +23,9 @@ 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)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <ctime>
|
||||
#include <csignal>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
@@ -28,7 +29,7 @@ namespace Game {
|
||||
Logger* logger = nullptr;
|
||||
dServer* server = nullptr;
|
||||
dConfig* config = nullptr;
|
||||
bool shouldShutdown = false;
|
||||
Game::signal_t lastSignal = 0;
|
||||
std::mt19937 randomEngine;
|
||||
}
|
||||
|
||||
@@ -42,17 +43,20 @@ int main(int argc, char** argv) {
|
||||
Diagnostics::SetProcessFileName(argv[0]);
|
||||
Diagnostics::Initialize();
|
||||
|
||||
std::signal(SIGINT, Game::OnSignal);
|
||||
std::signal(SIGTERM, Game::OnSignal);
|
||||
|
||||
//Create all the objects we need to run our service:
|
||||
Game::logger = SetupLogger();
|
||||
if (!Game::logger) return EXIT_FAILURE;
|
||||
|
||||
//Read our config:
|
||||
Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "authconfig.ini").string());
|
||||
Game::config = new dConfig("authconfig.ini");
|
||||
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
|
||||
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
|
||||
|
||||
LOG("Starting Auth server...");
|
||||
LOG("Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
|
||||
LOG("Version: %s", PROJECT_VERSION);
|
||||
LOG("Compiled on: %s", __TIMESTAMP__);
|
||||
|
||||
try {
|
||||
@@ -74,6 +78,7 @@ int main(int argc, char** argv) {
|
||||
masterIP = masterInfo->ip;
|
||||
masterPort = masterInfo->port;
|
||||
}
|
||||
LOG("Master is at %s:%d", masterIP.c_str(), masterPort);
|
||||
|
||||
Game::randomEngine = std::mt19937(time(0));
|
||||
|
||||
@@ -83,7 +88,7 @@ int main(int argc, char** argv) {
|
||||
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(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::shouldShutdown);
|
||||
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::lastSignal);
|
||||
|
||||
//Run it until server gets a kill message from Master:
|
||||
auto t = std::chrono::high_resolution_clock::now();
|
||||
@@ -94,13 +99,18 @@ int main(int argc, char** argv) {
|
||||
uint32_t framesSinceMasterDisconnect = 0;
|
||||
uint32_t framesSinceLastSQLPing = 0;
|
||||
|
||||
while (!Game::shouldShutdown) {
|
||||
AuthPackets::LoadClaimCodes();
|
||||
|
||||
Game::logger->Flush(); // once immediately before main loop
|
||||
while (!Game::ShouldShutdown()) {
|
||||
//Check if we're still connected to master:
|
||||
if (!Game::server->GetIsConnectedToMaster()) {
|
||||
framesSinceMasterDisconnect++;
|
||||
|
||||
if (framesSinceMasterDisconnect >= authFramerate)
|
||||
if (framesSinceMasterDisconnect >= authFramerate) {
|
||||
LOG("No connection to master!");
|
||||
break; //Exit our loop, shut down.
|
||||
}
|
||||
} else framesSinceMasterDisconnect = 0;
|
||||
|
||||
//In world we'd update our other systems here.
|
||||
@@ -139,6 +149,7 @@ 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;
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
add_executable(AuthServer "AuthServer.cpp")
|
||||
target_link_libraries(AuthServer ${COMMON_LIBRARIES})
|
||||
add_compile_definitions(AuthServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
set(DCHATSERVER_SOURCES
|
||||
"ChatIgnoreList.cpp"
|
||||
"ChatPacketHandler.cpp"
|
||||
"PlayerContainer.cpp"
|
||||
)
|
||||
|
||||
add_executable(ChatServer "ChatServer.cpp")
|
||||
add_library(dChatServer ${DCHATSERVER_SOURCES})
|
||||
add_compile_definitions(ChatServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
|
||||
|
||||
target_link_libraries(dChatServer ${COMMON_LIBRARIES} dChatFilter)
|
||||
target_link_libraries(ChatServer ${COMMON_LIBRARIES} dChatFilter dChatServer)
|
||||
|
||||
173
dChatServer/ChatIgnoreList.cpp
Normal file
173
dChatServer/ChatIgnoreList.cpp
Normal file
@@ -0,0 +1,173 @@
|
||||
#include "ChatIgnoreList.h"
|
||||
#include "PlayerContainer.h"
|
||||
#include "eChatInternalMessageType.h"
|
||||
#include "BitStreamUtils.h"
|
||||
#include "PacketUtils.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.GetPlayerData(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", playerId);
|
||||
return;
|
||||
}
|
||||
|
||||
auto ignoreList = Database::Get()->GetIgnoreList(static_cast<uint32_t>(playerId));
|
||||
if (ignoreList.empty()) {
|
||||
LOG_DEBUG("Player %llu has no ignores", playerId);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& ignoredPlayer : ignoreList) {
|
||||
receiver->ignoredPlayers.push_back(IgnoreData{ ignoredPlayer.id, ignoredPlayer.name });
|
||||
GeneralUtils::SetBit(receiver->ignoredPlayers.back().playerId, eObjectBits::CHARACTER);
|
||||
GeneralUtils::SetBit(receiver->ignoredPlayers.back().playerId, eObjectBits::PERSISTENT);
|
||||
}
|
||||
|
||||
CBITSTREAM;
|
||||
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.GetPlayerData(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(33);
|
||||
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
|
||||
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.push_back(IgnoreData{ ignoredPlayerId, toIgnoreStr });
|
||||
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.GetPlayerData(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(33);
|
||||
inStream.Read(removedIgnoreName);
|
||||
std::string removedIgnoreStr = removedIgnoreName.GetAsString();
|
||||
|
||||
auto toRemove = std::remove(receiver->ignoredPlayers.begin(), receiver->ignoredPlayers.end(), removedIgnoreStr);
|
||||
if (toRemove == receiver->ignoredPlayers.end()) {
|
||||
LOG_DEBUG("Player %llu is not ignoring %s", playerId, removedIgnoreStr.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
Database::Get()->RemoveIgnore(static_cast<uint32_t>(playerId), static_cast<uint32_t>(toRemove->playerId));
|
||||
receiver->ignoredPlayers.erase(toRemove, receiver->ignoredPlayers.end());
|
||||
|
||||
CBITSTREAM;
|
||||
WriteOutgoingReplyHeader(bitStream, receiver->playerID, ChatIgnoreList::Response::REMOVE_IGNORE);
|
||||
|
||||
bitStream.Write<int8_t>(0);
|
||||
LUWString playerNameSend(removedIgnoreStr, 33);
|
||||
bitStream.Write(playerNameSend);
|
||||
|
||||
Game::server->Send(&bitStream, packet->systemAddress, false);
|
||||
}
|
||||
27
dChatServer/ChatIgnoreList.h
Normal file
27
dChatServer/ChatIgnoreList.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef __CHATIGNORELIST__H__
|
||||
#define __CHATIGNORELIST__H__
|
||||
|
||||
struct Packet;
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace ChatIgnoreList {
|
||||
void GetIgnoreList(Packet* packet);
|
||||
void AddIgnore(Packet* packet);
|
||||
void RemoveIgnore(Packet* packet);
|
||||
|
||||
enum class Response : uint8_t {
|
||||
ADD_IGNORE = 32,
|
||||
REMOVE_IGNORE = 33,
|
||||
GET_IGNORE = 34,
|
||||
};
|
||||
|
||||
enum class AddResponse : uint8_t {
|
||||
SUCCESS,
|
||||
ALREADY_IGNORED,
|
||||
PLAYER_NOT_FOUND,
|
||||
GENERAL_ERROR,
|
||||
};
|
||||
};
|
||||
|
||||
#endif //!__CHATIGNORELIST__H__
|
||||
@@ -19,15 +19,13 @@
|
||||
#include "eClientMessageType.h"
|
||||
#include "eGameMessageType.h"
|
||||
|
||||
extern PlayerContainer playerContainer;
|
||||
|
||||
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
//Get from the packet which player we want to do something with:
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
LWOOBJID playerID = 0;
|
||||
inStream.Read(playerID);
|
||||
|
||||
auto player = playerContainer.GetPlayerData(playerID);
|
||||
auto player = Game::playerContainer.GetPlayerData(playerID);
|
||||
if (!player) return;
|
||||
|
||||
auto friendsList = Database::Get()->GetFriendsList(playerID);
|
||||
@@ -43,7 +41,7 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
fd.friendName = friendData.friendName;
|
||||
|
||||
//Now check if they're online:
|
||||
auto fr = playerContainer.GetPlayerData(fd.friendID);
|
||||
auto fr = Game::playerContainer.GetPlayerData(fd.friendID);
|
||||
|
||||
if (fr) {
|
||||
fd.isOnline = true;
|
||||
@@ -68,7 +66,7 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GET_FRIENDS_LIST_RESPONSE);
|
||||
bitStream.Write<uint8_t>(0);
|
||||
bitStream.Write<uint16_t>(1); //Length of packet -- just writing one as it doesn't matter, client skips it.
|
||||
bitStream.Write((uint16_t)player->friends.size());
|
||||
bitStream.Write<uint16_t>(player->friends.size());
|
||||
|
||||
for (auto& data : player->friends) {
|
||||
data.Serialize(bitStream);
|
||||
@@ -97,7 +95,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
char isBestFriendRequest{};
|
||||
inStream.Read(isBestFriendRequest);
|
||||
|
||||
auto requestor = playerContainer.GetPlayerData(requestorPlayerID);
|
||||
auto requestor = Game::playerContainer.GetPlayerData(requestorPlayerID);
|
||||
if (!requestor) {
|
||||
LOG("No requestor player %llu sent to %s found.", requestorPlayerID, playerName.c_str());
|
||||
return;
|
||||
@@ -107,7 +105,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN);
|
||||
return;
|
||||
};
|
||||
std::unique_ptr<PlayerData> requestee(playerContainer.GetPlayerData(playerName));
|
||||
std::unique_ptr<PlayerData> requestee(Game::playerContainer.GetPlayerData(playerName));
|
||||
|
||||
// Check if player is online first
|
||||
if (isBestFriendRequest && !requestee) {
|
||||
@@ -175,7 +173,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
|
||||
// Only do updates if there was a change in the bff status.
|
||||
if (oldBestFriendStatus != bestFriendStatus) {
|
||||
auto maxBestFriends = playerContainer.GetMaxNumberOfBestFriends();
|
||||
auto maxBestFriends = Game::playerContainer.GetMaxNumberOfBestFriends();
|
||||
if (requestee->countOfBestFriends >= maxBestFriends || requestor->countOfBestFriends >= maxBestFriends) {
|
||||
if (requestee->countOfBestFriends >= maxBestFriends) {
|
||||
SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false);
|
||||
@@ -208,7 +206,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::WAITINGAPPROVAL, true, true);
|
||||
}
|
||||
} else {
|
||||
auto maxFriends = playerContainer.GetMaxNumberOfFriends();
|
||||
auto maxFriends = Game::playerContainer.GetMaxNumberOfFriends();
|
||||
if (requestee->friends.size() >= maxFriends) {
|
||||
SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false);
|
||||
} else if (requestor->friends.size() >= maxFriends) {
|
||||
@@ -232,8 +230,8 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
|
||||
std::string friendName = PacketUtils::ReadString(0x15, packet, true);
|
||||
|
||||
//Now to try and find both of these:
|
||||
auto requestor = playerContainer.GetPlayerData(playerID);
|
||||
auto requestee = playerContainer.GetPlayerData(friendName);
|
||||
auto requestor = Game::playerContainer.GetPlayerData(playerID);
|
||||
auto requestee = Game::playerContainer.GetPlayerData(friendName);
|
||||
if (!requestor || !requestee) return;
|
||||
|
||||
eAddFriendResponseType serverResponseCode{};
|
||||
@@ -315,7 +313,7 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
||||
Database::Get()->RemoveFriend(playerID, friendID);
|
||||
|
||||
//Now, we need to send an update to notify the sender (and possibly, receiver) that their friendship has been ended:
|
||||
auto goonA = playerContainer.GetPlayerData(playerID);
|
||||
auto goonA = Game::playerContainer.GetPlayerData(playerID);
|
||||
if (goonA) {
|
||||
// Remove the friend from our list of friends
|
||||
for (auto friendData = goonA->friends.begin(); friendData != goonA->friends.end(); friendData++) {
|
||||
@@ -328,7 +326,7 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
||||
SendRemoveFriend(goonA, friendName, true);
|
||||
}
|
||||
|
||||
auto goonB = playerContainer.GetPlayerData(friendID);
|
||||
auto goonB = Game::playerContainer.GetPlayerData(friendID);
|
||||
if (!goonB) return;
|
||||
// Do it again for other person
|
||||
for (auto friendData = goonB->friends.begin(); friendData != goonB->friends.end(); friendData++) {
|
||||
@@ -339,7 +337,7 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
||||
}
|
||||
}
|
||||
|
||||
std::string goonAName = GeneralUtils::UTF16ToWTF8(playerContainer.GetName(playerID));
|
||||
std::string goonAName = GeneralUtils::UTF16ToWTF8(Game::playerContainer.GetName(playerID));
|
||||
SendRemoveFriend(goonB, goonAName, true);
|
||||
}
|
||||
|
||||
@@ -348,11 +346,11 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||
inStream.Read(playerID);
|
||||
|
||||
auto* sender = playerContainer.GetPlayerData(playerID);
|
||||
auto* sender = Game::playerContainer.GetPlayerData(playerID);
|
||||
|
||||
if (sender == nullptr) return;
|
||||
|
||||
if (playerContainer.GetIsMuted(sender)) return;
|
||||
if (Game::playerContainer.GetIsMuted(sender)) return;
|
||||
|
||||
const auto senderName = std::string(sender->playerName.c_str());
|
||||
|
||||
@@ -367,12 +365,12 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
||||
|
||||
if (channel != 8) return;
|
||||
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||
|
||||
if (team == nullptr) return;
|
||||
|
||||
for (const auto memberId : team->memberIDs) {
|
||||
auto* otherMember = playerContainer.GetPlayerData(memberId);
|
||||
auto* otherMember = Game::playerContainer.GetPlayerData(memberId);
|
||||
|
||||
if (otherMember == nullptr) return;
|
||||
|
||||
@@ -406,11 +404,11 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
|
||||
std::string message = PacketUtils::ReadString(0xAA, packet, true, 512);
|
||||
|
||||
//Get the bois:
|
||||
auto goonA = playerContainer.GetPlayerData(senderID);
|
||||
auto goonB = playerContainer.GetPlayerData(receiverName);
|
||||
auto goonA = Game::playerContainer.GetPlayerData(senderID);
|
||||
auto goonB = Game::playerContainer.GetPlayerData(receiverName);
|
||||
if (!goonA || !goonB) return;
|
||||
|
||||
if (playerContainer.GetIsMuted(goonA)) return;
|
||||
if (Game::playerContainer.GetIsMuted(goonA)) return;
|
||||
|
||||
std::string goonAName = goonA->playerName.c_str();
|
||||
std::string goonBName = goonB->playerName.c_str();
|
||||
@@ -468,25 +466,25 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
|
||||
inStream.Read(playerID);
|
||||
std::string invitedPlayer = PacketUtils::ReadString(0x14, packet, true);
|
||||
|
||||
auto* player = playerContainer.GetPlayerData(playerID);
|
||||
auto* player = Game::playerContainer.GetPlayerData(playerID);
|
||||
|
||||
if (player == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||
|
||||
if (team == nullptr) {
|
||||
team = playerContainer.CreateTeam(playerID);
|
||||
team = Game::playerContainer.CreateTeam(playerID);
|
||||
}
|
||||
|
||||
auto* other = playerContainer.GetPlayerData(invitedPlayer);
|
||||
auto* other = Game::playerContainer.GetPlayerData(invitedPlayer);
|
||||
|
||||
if (other == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (playerContainer.GetTeam(other->playerID) != nullptr) {
|
||||
if (Game::playerContainer.GetTeam(other->playerID) != nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -519,12 +517,12 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* team = playerContainer.GetTeam(leaderID);
|
||||
auto* team = Game::playerContainer.GetTeam(leaderID);
|
||||
|
||||
if (team == nullptr) {
|
||||
LOG("Failed to find team for leader (%llu)", leaderID);
|
||||
|
||||
team = playerContainer.GetTeam(playerID);
|
||||
team = Game::playerContainer.GetTeam(playerID);
|
||||
}
|
||||
|
||||
if (team == nullptr) {
|
||||
@@ -532,7 +530,7 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
playerContainer.AddMember(team, playerID);
|
||||
Game::playerContainer.AddMember(team, playerID);
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
|
||||
@@ -542,12 +540,12 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
|
||||
uint32_t size = 0;
|
||||
inStream.Read(size);
|
||||
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||
|
||||
LOG("(%llu) leaving team", playerID);
|
||||
|
||||
if (team != nullptr) {
|
||||
playerContainer.RemoveMember(team, playerID, false, false, true);
|
||||
Game::playerContainer.RemoveMember(team, playerID, false, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -560,24 +558,24 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet) {
|
||||
|
||||
LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str());
|
||||
|
||||
auto* kicked = playerContainer.GetPlayerData(kickedPlayer);
|
||||
auto* kicked = Game::playerContainer.GetPlayerData(kickedPlayer);
|
||||
|
||||
LWOOBJID kickedId = LWOOBJID_EMPTY;
|
||||
|
||||
if (kicked != nullptr) {
|
||||
kickedId = kicked->playerID;
|
||||
} else {
|
||||
kickedId = playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer));
|
||||
kickedId = Game::playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer));
|
||||
}
|
||||
|
||||
if (kickedId == LWOOBJID_EMPTY) return;
|
||||
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||
|
||||
if (team != nullptr) {
|
||||
if (team->leaderID != playerID || team->leaderID == kickedId) return;
|
||||
|
||||
playerContainer.RemoveMember(team, kickedId, false, true, false);
|
||||
Game::playerContainer.RemoveMember(team, kickedId, false, true, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -590,16 +588,16 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet) {
|
||||
|
||||
LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str());
|
||||
|
||||
auto* promoted = playerContainer.GetPlayerData(promotedPlayer);
|
||||
auto* promoted = Game::playerContainer.GetPlayerData(promotedPlayer);
|
||||
|
||||
if (promoted == nullptr) return;
|
||||
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||
|
||||
if (team != nullptr) {
|
||||
if (team->leaderID != playerID) return;
|
||||
|
||||
playerContainer.PromoteMember(team, promoted->playerID);
|
||||
Game::playerContainer.PromoteMember(team, promoted->playerID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -613,16 +611,16 @@ void ChatPacketHandler::HandleTeamLootOption(Packet* packet) {
|
||||
char option;
|
||||
inStream.Read(option);
|
||||
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||
|
||||
if (team != nullptr) {
|
||||
if (team->leaderID != playerID) return;
|
||||
|
||||
team->lootFlag = option;
|
||||
|
||||
playerContainer.TeamStatusUpdate(team);
|
||||
Game::playerContainer.TeamStatusUpdate(team);
|
||||
|
||||
playerContainer.UpdateTeamsOnWorld(team, false);
|
||||
Game::playerContainer.UpdateTeamsOnWorld(team, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -631,18 +629,18 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
|
||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||
inStream.Read(playerID);
|
||||
|
||||
auto* team = playerContainer.GetTeam(playerID);
|
||||
auto* data = playerContainer.GetPlayerData(playerID);
|
||||
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||
auto* data = Game::playerContainer.GetPlayerData(playerID);
|
||||
|
||||
if (team != nullptr && data != nullptr) {
|
||||
if (team->local && data->zoneID.GetMapID() != team->zoneId.GetMapID() && data->zoneID.GetCloneID() != team->zoneId.GetCloneID()) {
|
||||
playerContainer.RemoveMember(team, playerID, false, false, true, true);
|
||||
Game::playerContainer.RemoveMember(team, playerID, false, false, true, true);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (team->memberIDs.size() <= 1 && !team->local) {
|
||||
playerContainer.DisbandTeam(team);
|
||||
Game::playerContainer.DisbandTeam(team);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -653,16 +651,16 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
|
||||
ChatPacketHandler::SendTeamSetLeader(data, LWOOBJID_EMPTY);
|
||||
}
|
||||
|
||||
playerContainer.TeamStatusUpdate(team);
|
||||
Game::playerContainer.TeamStatusUpdate(team);
|
||||
|
||||
const auto leaderName = GeneralUtils::UTF8ToUTF16(data->playerName);
|
||||
|
||||
for (const auto memberId : team->memberIDs) {
|
||||
auto* otherMember = playerContainer.GetPlayerData(memberId);
|
||||
auto* otherMember = Game::playerContainer.GetPlayerData(memberId);
|
||||
|
||||
if (memberId == playerID) continue;
|
||||
|
||||
const auto memberName = playerContainer.GetName(memberId);
|
||||
const auto memberName = Game::playerContainer.GetName(memberId);
|
||||
|
||||
if (otherMember != nullptr) {
|
||||
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID);
|
||||
@@ -670,7 +668,7 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
|
||||
ChatPacketHandler::SendTeamAddPlayer(data, false, team->local, false, memberId, memberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0));
|
||||
}
|
||||
|
||||
playerContainer.UpdateTeamsOnWorld(team, false);
|
||||
Game::playerContainer.UpdateTeamsOnWorld(team, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -707,7 +705,7 @@ void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeader
|
||||
bitStream.Write(ucLootFlag);
|
||||
bitStream.Write(ucNumOfOtherPlayers);
|
||||
bitStream.Write(ucResponseCode);
|
||||
bitStream.Write(static_cast<uint32_t>(wsLeaderName.size()));
|
||||
bitStream.Write<uint32_t>(wsLeaderName.size());
|
||||
for (const auto character : wsLeaderName) {
|
||||
bitStream.Write(character);
|
||||
}
|
||||
@@ -732,7 +730,7 @@ void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderI
|
||||
bitStream.Write<uint32_t>(0); // BinaryBuffe, no clue what's in here
|
||||
bitStream.Write(ucLootFlag);
|
||||
bitStream.Write(ucNumOfOtherPlayers);
|
||||
bitStream.Write(static_cast<uint32_t>(wsLeaderName.size()));
|
||||
bitStream.Write<uint32_t>(wsLeaderName.size());
|
||||
for (const auto character : wsLeaderName) {
|
||||
bitStream.Write(character);
|
||||
}
|
||||
@@ -773,7 +771,7 @@ void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTria
|
||||
bitStream.Write(bLocal);
|
||||
bitStream.Write(bNoLootOnDeath);
|
||||
bitStream.Write(i64PlayerID);
|
||||
bitStream.Write(static_cast<uint32_t>(wsPlayerName.size()));
|
||||
bitStream.Write<uint32_t>(wsPlayerName.size());
|
||||
for (const auto character : wsPlayerName) {
|
||||
bitStream.Write(character);
|
||||
}
|
||||
@@ -804,7 +802,7 @@ void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband
|
||||
bitStream.Write(bLocal);
|
||||
bitStream.Write(i64LeaderID);
|
||||
bitStream.Write(i64PlayerID);
|
||||
bitStream.Write(static_cast<uint32_t>(wsPlayerName.size()));
|
||||
bitStream.Write<uint32_t>(wsPlayerName.size());
|
||||
for (const auto character : wsPlayerName) {
|
||||
bitStream.Write(character);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "eChatMessageType.h"
|
||||
#include "eChatInternalMessageType.h"
|
||||
#include "eWorldMessageType.h"
|
||||
#include "ChatIgnoreList.h"
|
||||
|
||||
#include "Game.h"
|
||||
|
||||
@@ -32,16 +33,14 @@ namespace Game {
|
||||
dConfig* config = nullptr;
|
||||
dChatFilter* chatFilter = nullptr;
|
||||
AssetManager* assetManager = nullptr;
|
||||
bool shouldShutdown = false;
|
||||
Game::signal_t lastSignal = 0;
|
||||
std::mt19937 randomEngine;
|
||||
PlayerContainer playerContainer;
|
||||
}
|
||||
|
||||
|
||||
Logger* SetupLogger();
|
||||
void HandlePacket(Packet* packet);
|
||||
|
||||
PlayerContainer playerContainer;
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
constexpr uint32_t chatFramerate = mediumFramerate;
|
||||
constexpr uint32_t chatFrameDelta = mediumFrameDelta;
|
||||
@@ -49,17 +48,20 @@ int main(int argc, char** argv) {
|
||||
Diagnostics::SetProcessFileName(argv[0]);
|
||||
Diagnostics::Initialize();
|
||||
|
||||
std::signal(SIGINT, Game::OnSignal);
|
||||
std::signal(SIGTERM, Game::OnSignal);
|
||||
|
||||
//Create all the objects we need to run our service:
|
||||
Game::logger = SetupLogger();
|
||||
if (!Game::logger) return EXIT_FAILURE;
|
||||
|
||||
//Read our config:
|
||||
Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "chatconfig.ini").string());
|
||||
Game::config = new dConfig("chatconfig.ini");
|
||||
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
|
||||
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
|
||||
|
||||
LOG("Starting Chat server...");
|
||||
LOG("Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
|
||||
LOG("Version: %s", PROJECT_VERSION);
|
||||
LOG("Compiled on: %s", __TIMESTAMP__);
|
||||
|
||||
try {
|
||||
@@ -102,13 +104,13 @@ int main(int argc, char** argv) {
|
||||
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(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::shouldShutdown);
|
||||
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal);
|
||||
|
||||
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf"))));
|
||||
|
||||
Game::randomEngine = std::mt19937(time(0));
|
||||
|
||||
playerContainer.Initialize();
|
||||
Game::playerContainer.Initialize();
|
||||
|
||||
//Run it until server gets a kill message from Master:
|
||||
auto t = std::chrono::high_resolution_clock::now();
|
||||
@@ -119,7 +121,8 @@ int main(int argc, char** argv) {
|
||||
uint32_t framesSinceMasterDisconnect = 0;
|
||||
uint32_t framesSinceLastSQLPing = 0;
|
||||
|
||||
while (!Game::shouldShutdown) {
|
||||
Game::logger->Flush(); // once immediately before main loop
|
||||
while (!Game::ShouldShutdown()) {
|
||||
//Check if we're still connected to master:
|
||||
if (!Game::server->GetIsConnectedToMaster()) {
|
||||
framesSinceMasterDisconnect++;
|
||||
@@ -200,19 +203,19 @@ void HandlePacket(Packet* packet) {
|
||||
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) {
|
||||
switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
|
||||
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
|
||||
playerContainer.InsertPlayer(packet);
|
||||
Game::playerContainer.InsertPlayer(packet);
|
||||
break;
|
||||
|
||||
case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION:
|
||||
playerContainer.RemovePlayer(packet);
|
||||
Game::playerContainer.RemovePlayer(packet);
|
||||
break;
|
||||
|
||||
case eChatInternalMessageType::MUTE_UPDATE:
|
||||
playerContainer.MuteUpdate(packet);
|
||||
Game::playerContainer.MuteUpdate(packet);
|
||||
break;
|
||||
|
||||
case eChatInternalMessageType::CREATE_TEAM:
|
||||
playerContainer.CreateTeamServer(packet);
|
||||
Game::playerContainer.CreateTeamServer(packet);
|
||||
break;
|
||||
|
||||
case eChatInternalMessageType::ANNOUNCEMENT: {
|
||||
@@ -234,7 +237,15 @@ void HandlePacket(Packet* packet) {
|
||||
break;
|
||||
|
||||
case eChatMessageType::GET_IGNORE_LIST:
|
||||
LOG("Asked for ignore list, but is unimplemented right now.");
|
||||
ChatIgnoreList::GetIgnoreList(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::ADD_IGNORE:
|
||||
ChatIgnoreList::AddIgnore(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::REMOVE_IGNORE:
|
||||
ChatIgnoreList::RemoveIgnore(packet);
|
||||
break;
|
||||
|
||||
case eChatMessageType::TEAM_GET_STATUS:
|
||||
|
||||
@@ -354,7 +354,7 @@ void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
|
||||
|
||||
if (!deleteTeam) {
|
||||
bitStream.Write(team->lootFlag);
|
||||
bitStream.Write(static_cast<char>(team->memberIDs.size()));
|
||||
bitStream.Write<char>(team->memberIDs.size());
|
||||
for (const auto memberID : team->memberIDs) {
|
||||
bitStream.Write(memberID);
|
||||
}
|
||||
|
||||
@@ -7,12 +7,26 @@
|
||||
#include "dServer.h"
|
||||
#include <unordered_map>
|
||||
|
||||
struct IgnoreData {
|
||||
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;
|
||||
std::string playerName;
|
||||
};
|
||||
|
||||
struct PlayerData {
|
||||
LWOOBJID playerID;
|
||||
std::string playerName;
|
||||
SystemAddress sysAddr;
|
||||
LWOZONEID zoneID;
|
||||
std::vector<FriendData> friends;
|
||||
std::vector<IgnoreData> ignoredPlayers;
|
||||
time_t muteExpire;
|
||||
uint8_t countOfBestFriends = 0;
|
||||
};
|
||||
|
||||
@@ -54,17 +54,17 @@ void RakNet::BitStream::Write<AMFBaseValue&>(AMFBaseValue& value) {
|
||||
* 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;
|
||||
unsigned char b4 = static_cast<unsigned char>(v);
|
||||
if (v < 0x00200000) {
|
||||
b4 = b4 & 0x7F;
|
||||
if (v > 0x7F) {
|
||||
unsigned char b3;
|
||||
v = v >> 7;
|
||||
b3 = ((unsigned char)(v)) | 0x80;
|
||||
b3 = static_cast<unsigned char>(v) | 0x80;
|
||||
if (v > 0x7F) {
|
||||
unsigned char b2;
|
||||
v = v >> 7;
|
||||
b2 = ((unsigned char)(v)) | 0x80;
|
||||
b2 = static_cast<unsigned char>(v) | 0x80;
|
||||
bs->Write(b2);
|
||||
}
|
||||
|
||||
@@ -76,11 +76,11 @@ void WriteUInt29(RakNet::BitStream* bs, uint32_t v) {
|
||||
unsigned char b3;
|
||||
|
||||
v = v >> 8;
|
||||
b3 = ((unsigned char)(v)) | 0x80;
|
||||
b3 = static_cast<unsigned char>(v) | 0x80;
|
||||
v = v >> 7;
|
||||
b2 = ((unsigned char)(v)) | 0x80;
|
||||
b2 = static_cast<unsigned char>(v) | 0x80;
|
||||
v = v >> 7;
|
||||
b1 = ((unsigned char)(v)) | 0x80;
|
||||
b1 = static_cast<unsigned char>(v) | 0x80;
|
||||
|
||||
bs->Write(b1);
|
||||
bs->Write(b2);
|
||||
@@ -105,8 +105,8 @@ void WriteFlagNumber(RakNet::BitStream* bs, uint32_t v) {
|
||||
* RakNet writes in the correct byte order - do not reverse this.
|
||||
*/
|
||||
void WriteAMFString(RakNet::BitStream* bs, const std::string& str) {
|
||||
WriteFlagNumber(bs, (uint32_t)str.size());
|
||||
bs->Write(str.c_str(), (uint32_t)str.size());
|
||||
WriteFlagNumber(bs, static_cast<uint32_t>(str.size()));
|
||||
bs->Write(str.c_str(), static_cast<uint32_t>(str.size()));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
#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;
|
||||
@@ -23,36 +15,3 @@ 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;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
#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));
|
||||
@@ -15,13 +24,51 @@ namespace BinaryIO {
|
||||
return stream.read(reinterpret_cast<char*>(&value), sizeof(T));
|
||||
}
|
||||
|
||||
void WriteString(const std::string& stringToWrite, std::ofstream& outstream);
|
||||
enum class ReadType : int8_t {
|
||||
WideString = 0,
|
||||
String = 1,
|
||||
};
|
||||
|
||||
template<typename SizeType>
|
||||
inline void ReadString(std::istream& stream, std::u16string& value) {
|
||||
static_assert(std::is_integral<SizeType>::value, "SizeType must be an integral type.");
|
||||
|
||||
SizeType size;
|
||||
BinaryRead(stream, size);
|
||||
|
||||
if (!stream.good()) throw std::runtime_error("Failed to read from istream.");
|
||||
value.resize(size);
|
||||
stream.read(reinterpret_cast<char*>(value.data()), size * sizeof(uint16_t));
|
||||
}
|
||||
|
||||
template<typename SizeType>
|
||||
inline void ReadString(std::istream& stream, std::string& value, ReadType readType) {
|
||||
static_assert(std::is_integral<SizeType>::value, "SizeType must be an integral type.");
|
||||
|
||||
SizeType size;
|
||||
BinaryRead(stream, size);
|
||||
|
||||
if (!stream.good()) throw std::runtime_error("Failed to read from istream.");
|
||||
value.resize(size);
|
||||
if (readType == ReadType::WideString) {
|
||||
uint16_t wideChar;
|
||||
|
||||
// Faster to do this than to read a u16string and convert it to a string since we only go through allocator once
|
||||
for (SizeType i = 0; i < size; ++i) {
|
||||
BinaryRead(stream, wideChar);
|
||||
value[i] = static_cast<char>(wideChar);
|
||||
}
|
||||
} else {
|
||||
stream.read(value.data(), size);
|
||||
}
|
||||
}
|
||||
|
||||
std::string ReadString(std::istream& instream);
|
||||
std::string ReadString(std::istream& instream, 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__
|
||||
|
||||
@@ -51,7 +51,7 @@ uint32_t BrickByBrickFix::TruncateBrokenBrickByBrickXml() {
|
||||
|
||||
if (actualUncompressedSize != -1) {
|
||||
uint32_t previousSize = completeUncompressedModel.size();
|
||||
completeUncompressedModel.append((char*)uncompressedChunk.get());
|
||||
completeUncompressedModel.append(reinterpret_cast<char*>(uncompressedChunk.get()));
|
||||
completeUncompressedModel.resize(previousSize + actualUncompressedSize);
|
||||
} else {
|
||||
LOG("Failed to inflate chunk %i for model %llu. Error: %i", chunkCount, model.id, err);
|
||||
|
||||
@@ -5,6 +5,7 @@ set(DCOMMON_SOURCES
|
||||
"dConfig.cpp"
|
||||
"Diagnostics.cpp"
|
||||
"Logger.cpp"
|
||||
"Game.cpp"
|
||||
"GeneralUtils.cpp"
|
||||
"LDFFormat.cpp"
|
||||
"MD5.cpp"
|
||||
|
||||
@@ -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>
|
||||
@@ -115,7 +115,15 @@ void GenerateDump() {
|
||||
}
|
||||
|
||||
void CatchUnhandled(int sig) {
|
||||
#ifndef __include_backtrace__
|
||||
std::exception_ptr eptr = std::current_exception();
|
||||
try {
|
||||
if (eptr) std::rethrow_exception(eptr);
|
||||
} catch(const std::exception& e) {
|
||||
LOG("Caught exception: '%s'", e.what());
|
||||
}
|
||||
Game::logger->Flush();
|
||||
|
||||
#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());
|
||||
@@ -167,7 +175,7 @@ void CatchUnhandled(int sig) {
|
||||
backtrace_symbols_fd(array, size, STDOUT_FILENO);
|
||||
# endif // defined(__GNUG__)
|
||||
|
||||
#else // __include_backtrace__
|
||||
#else // INCLUDE_BACKTRACE
|
||||
|
||||
struct backtrace_state* state = backtrace_create_state(
|
||||
Diagnostics::GetProcessFileName().c_str(),
|
||||
@@ -178,8 +186,8 @@ void CatchUnhandled(int sig) {
|
||||
struct bt_ctx ctx = { state, 0 };
|
||||
Bt(state);
|
||||
|
||||
#endif // __include_backtrace__
|
||||
|
||||
#endif // INCLUDE_BACKTRACE
|
||||
Game::logger->Flush();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -197,10 +205,10 @@ void MakeBacktrace() {
|
||||
sigact.sa_sigaction = CritErrHdlr;
|
||||
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
|
||||
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) {
|
||||
if (sigaction(SIGSEGV, &sigact, nullptr) != 0 ||
|
||||
sigaction(SIGFPE, &sigact, nullptr) != 0 ||
|
||||
sigaction(SIGABRT, &sigact, nullptr) != 0 ||
|
||||
sigaction(SIGILL, &sigact, nullptr) != 0) {
|
||||
fprintf(stderr, "error setting signal handler for %d (%s)\n",
|
||||
SIGSEGV,
|
||||
strsignal(SIGSEGV));
|
||||
|
||||
@@ -28,19 +28,17 @@ FdbToSqlite::Convert::Convert(std::string binaryOutPath) {
|
||||
this->m_BinaryOutPath = binaryOutPath;
|
||||
}
|
||||
|
||||
bool FdbToSqlite::Convert::ConvertDatabase(AssetMemoryBuffer& buffer) {
|
||||
bool FdbToSqlite::Convert::ConvertDatabase(AssetStream& 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(cdClientBuffer);
|
||||
ReadTables(numberOfTables, cdClientBuffer);
|
||||
int32_t numberOfTables = ReadInt32(buffer);
|
||||
ReadTables(numberOfTables, buffer);
|
||||
|
||||
CDClientDatabase::ExecuteQuery("COMMIT;");
|
||||
} catch (CppSQLite3Exception& e) {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <iosfwd>
|
||||
#include <map>
|
||||
|
||||
class AssetMemoryBuffer;
|
||||
#include "AssetManager.h"
|
||||
|
||||
enum class eSqliteDataType : int32_t;
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace FdbToSqlite {
|
||||
*
|
||||
* @return true if the database was converted properly, false otherwise.
|
||||
*/
|
||||
bool ConvertDatabase(AssetMemoryBuffer& buffer);
|
||||
bool ConvertDatabase(AssetStream& buffer);
|
||||
|
||||
/**
|
||||
* @brief Reads a 32 bit int from the fdb file.
|
||||
|
||||
7
dCommon/Game.cpp
Normal file
7
dCommon/Game.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "Game.h"
|
||||
|
||||
namespace Game {
|
||||
void OnSignal(int signal) {
|
||||
lastSignal = signal;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <random>
|
||||
#include <csignal>
|
||||
|
||||
class dServer;
|
||||
class Logger;
|
||||
@@ -12,8 +14,10 @@ class AssetManager;
|
||||
struct SystemAddress;
|
||||
class EntityManager;
|
||||
class dZoneManager;
|
||||
class PlayerContainer;
|
||||
|
||||
namespace Game {
|
||||
using signal_t = volatile std::sig_atomic_t;
|
||||
extern Logger* logger;
|
||||
extern dServer* server;
|
||||
extern InstanceManager* im;
|
||||
@@ -23,7 +27,14 @@ namespace Game {
|
||||
extern RakPeerInterface* chatServer;
|
||||
extern AssetManager* assetManager;
|
||||
extern SystemAddress chatSysAddr;
|
||||
extern bool shouldShutdown;
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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 = (const uint8_t*)&slice.front();
|
||||
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&slice.front());
|
||||
if (rem > 0) {
|
||||
uint8_t first = bytes[0];
|
||||
if (first < 0x80) { // 1 byte character
|
||||
|
||||
@@ -234,18 +234,30 @@ namespace GeneralUtils {
|
||||
return T();
|
||||
}
|
||||
|
||||
// on Windows we need to undef these or else they conflict with our numeric limits calls
|
||||
// DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS
|
||||
#ifdef _WIN32
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
/**
|
||||
* 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");
|
||||
|
||||
return static_cast<typename std::underlying_type_t<eType>>(entry);
|
||||
}
|
||||
|
||||
// on Windows we need to undef these or else they conflict with our numeric limits calls
|
||||
// DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS
|
||||
#ifdef _WIN32
|
||||
#undef min
|
||||
#undef max
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
inline T GenerateRandomNumber() {
|
||||
// Make sure it is a numeric type
|
||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||
|
||||
|
||||
return GenerateRandomNumber<T>(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,15 +63,15 @@ private:
|
||||
|
||||
//! Writes the key to the packet
|
||||
void WriteKey(RakNet::BitStream* packet) {
|
||||
packet->Write(static_cast<uint8_t>(this->key.length() * sizeof(uint16_t)));
|
||||
packet->Write<uint8_t>(this->key.length() * sizeof(uint16_t));
|
||||
for (uint32_t i = 0; i < this->key.length(); ++i) {
|
||||
packet->Write(static_cast<uint16_t>(this->key[i]));
|
||||
packet->Write<uint16_t>(this->key[i]);
|
||||
}
|
||||
}
|
||||
|
||||
//! Writes the value to the packet
|
||||
void WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
||||
packet->Write<uint8_t>(this->GetValueType());
|
||||
packet->Write(this->value);
|
||||
}
|
||||
|
||||
@@ -179,30 +179,30 @@ template<> inline eLDFType LDFData<std::string>::GetValueType(void) { return LDF
|
||||
// The specialized version for std::u16string (UTF-16)
|
||||
template<>
|
||||
inline void LDFData<std::u16string>::WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
||||
packet->Write<uint8_t>(this->GetValueType());
|
||||
|
||||
packet->Write(static_cast<uint32_t>(this->value.length()));
|
||||
packet->Write<uint32_t>(this->value.length());
|
||||
for (uint32_t i = 0; i < this->value.length(); ++i) {
|
||||
packet->Write(static_cast<uint16_t>(this->value[i]));
|
||||
packet->Write<uint16_t>(this->value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// The specialized version for bool
|
||||
template<>
|
||||
inline void LDFData<bool>::WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
||||
packet->Write<uint8_t>(this->GetValueType());
|
||||
|
||||
packet->Write(static_cast<uint8_t>(this->value));
|
||||
packet->Write<uint8_t>(this->value);
|
||||
}
|
||||
|
||||
// The specialized version for std::string (UTF-8)
|
||||
template<>
|
||||
inline void LDFData<std::string>::WriteValue(RakNet::BitStream* packet) {
|
||||
packet->Write(static_cast<uint8_t>(this->GetValueType()));
|
||||
packet->Write<uint8_t>(this->GetValueType());
|
||||
|
||||
packet->Write(static_cast<uint32_t>(this->value.length()));
|
||||
packet->Write<uint32_t>(this->value.length());
|
||||
for (uint32_t i = 0; i < this->value.length(); ++i) {
|
||||
packet->Write(static_cast<uint8_t>(this->value[i]));
|
||||
packet->Write<uint8_t>(this->value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
Writer::~Writer() {
|
||||
// Flush before we close
|
||||
Flush();
|
||||
// Dont try to close stdcout...
|
||||
if (!m_Outfile || m_IsConsoleWriter) return;
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ void Metrics::EndMeasurement(MetricVariable variable) {
|
||||
}
|
||||
|
||||
float Metrics::ToMiliseconds(int64_t nanoseconds) {
|
||||
return (float)nanoseconds / 1e6;
|
||||
return static_cast<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 (size_t)info.PeakWorkingSetSize;
|
||||
return static_cast<size_t>(info.PeakWorkingSetSize);
|
||||
|
||||
#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__)))
|
||||
/* AIX and Solaris ------------------------------------------ */
|
||||
struct psinfo psinfo;
|
||||
int fd = -1;
|
||||
if ((fd = open("/proc/self/psinfo", O_RDONLY)) == -1)
|
||||
return (size_t)0L; /* Can't open? */
|
||||
return static_cast<size_t>(0L); /* Can't open? */
|
||||
if (read(fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) {
|
||||
close(fd);
|
||||
return (size_t)0L; /* Can't read? */
|
||||
return static_cast<size_t>(0L); /* Can't read? */
|
||||
}
|
||||
close(fd);
|
||||
return (size_t)(psinfo.pr_rssize * 1024L);
|
||||
return static_cast<size_t>(psinfo.pr_rssize * 1024L);
|
||||
|
||||
#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__))
|
||||
/* BSD, Linux, and OSX -------------------------------------- */
|
||||
struct rusage rusage;
|
||||
getrusage(RUSAGE_SELF, &rusage);
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
return (size_t)rusage.ru_maxrss;
|
||||
return static_cast<size_t>(rusage.ru_maxrss);
|
||||
#else
|
||||
return (size_t)(rusage.ru_maxrss * 1024L);
|
||||
return static_cast<size_t>(rusage.ru_maxrss * 1024L);
|
||||
#endif
|
||||
|
||||
#else
|
||||
/* Unknown OS ----------------------------------------------- */
|
||||
return (size_t)0L; /* Unsupported. */
|
||||
return static_cast<size_t>(0L); /* Unsupported. */
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -234,33 +234,33 @@ size_t Metrics::GetCurrentRSS() {
|
||||
/* Windows -------------------------------------------------- */
|
||||
PROCESS_MEMORY_COUNTERS info;
|
||||
GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info));
|
||||
return (size_t)info.WorkingSetSize;
|
||||
return static_cast<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,
|
||||
(task_info_t)&info, &infoCount) != KERN_SUCCESS)
|
||||
return (size_t)0L; /* Can't access? */
|
||||
return (size_t)info.resident_size;
|
||||
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);
|
||||
|
||||
#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 (size_t)0L; /* Can't open? */
|
||||
return static_cast<size_t>(0L); /* Can't open? */
|
||||
if (fscanf(fp, "%*s%ld", &rss) != 1) {
|
||||
fclose(fp);
|
||||
return (size_t)0L; /* Can't read? */
|
||||
return static_cast<size_t>(0L); /* Can't read? */
|
||||
}
|
||||
fclose(fp);
|
||||
return (size_t)rss * (size_t)sysconf(_SC_PAGESIZE);
|
||||
return static_cast<size_t>(rss) * static_cast<size_t>(sysconf(_SC_PAGESIZE));
|
||||
|
||||
#else
|
||||
/* AIX, BSD, Solaris, and Unknown OS ------------------------ */
|
||||
return (size_t)0L; /* Unsupported. */
|
||||
return static_cast<size_t>(0L); /* Unsupported. */
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -114,13 +114,13 @@ bool NiPoint3::operator!=(const NiPoint3& point) const {
|
||||
//! Operator for subscripting
|
||||
float& NiPoint3::operator[](int i) {
|
||||
float* base = &x;
|
||||
return (float&)base[i];
|
||||
return base[i];
|
||||
}
|
||||
|
||||
//! Operator for subscripting
|
||||
const float& NiPoint3::operator[](int i) const {
|
||||
const float* base = &x;
|
||||
return (float&)base[i];
|
||||
return base[i];
|
||||
}
|
||||
|
||||
//! Operator for addition of vectors
|
||||
@@ -181,7 +181,7 @@ bool NiPoint3::IsWithinAxisAlignedBox(const NiPoint3& minPoint, const NiPoint3&
|
||||
if (this->y < minPoint.y) return false;
|
||||
if (this->y > maxPoint.y) return false;
|
||||
|
||||
return (this->z < maxPoint.z&& this->z > minPoint.z);
|
||||
return (this->z < maxPoint.z && this->z > minPoint.z);
|
||||
}
|
||||
|
||||
//! Checks to see if the point (or vector) is within a sphere
|
||||
@@ -232,10 +232,21 @@ NiPoint3 NiPoint3::MoveTowards(const NiPoint3& current, const NiPoint3& target,
|
||||
float dx = target.x - current.x;
|
||||
float dy = target.y - current.y;
|
||||
float dz = target.z - current.z;
|
||||
float lengthSquared = (float)((double)dx * (double)dx + (double)dy * (double)dy + (double)dz * (double)dz);
|
||||
if ((double)lengthSquared == 0.0 || (double)maxDistanceDelta >= 0.0 && (double)lengthSquared <= (double)maxDistanceDelta * (double)maxDistanceDelta)
|
||||
|
||||
float lengthSquared = static_cast<float>(
|
||||
static_cast<double>(dx) * static_cast<double>(dx) +
|
||||
static_cast<double>(dy) * static_cast<double>(dy) +
|
||||
static_cast<double>(dz) * static_cast<double>(dz)
|
||||
);
|
||||
|
||||
if (static_cast<double>(lengthSquared) == 0.0
|
||||
|| static_cast<double>(maxDistanceDelta) >= 0.0
|
||||
&& static_cast<double>(lengthSquared)
|
||||
<= static_cast<double>(maxDistanceDelta) * static_cast<double>(maxDistanceDelta)) {
|
||||
return target;
|
||||
float length = (float)std::sqrt((double)lengthSquared);
|
||||
}
|
||||
|
||||
float length = std::sqrt(lengthSquared);
|
||||
return NiPoint3(current.x + dx / length * maxDistanceDelta, current.y + dy / length * maxDistanceDelta, current.z + dz / length * maxDistanceDelta);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// Source: http://www.zedwood.com/article/cpp-sha512-function
|
||||
|
||||
#include "SHA512.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
@@ -81,8 +81,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, (uint8_t*)fixedName.c_str(), fixedName.size());
|
||||
crc = crc32b(crc, (Bytef*)"\0\0\0\0", 4);
|
||||
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);
|
||||
|
||||
for (const auto& item : this->m_PackIndex->GetPackFileIndices()) {
|
||||
if (item.m_Crc == crc) {
|
||||
@@ -113,7 +113,7 @@ bool AssetManager::GetFile(const char* name, char** data, uint32_t* len) {
|
||||
#endif
|
||||
fseek(file, 0, SEEK_END);
|
||||
*len = ftell(file);
|
||||
*data = (char*)malloc(*len);
|
||||
*data = static_cast<char*>(malloc(*len));
|
||||
fseek(file, 0, SEEK_SET);
|
||||
int32_t readInData = fread(*data, sizeof(uint8_t), *len, file);
|
||||
fclose(file);
|
||||
@@ -129,8 +129,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, (uint8_t*)fixedName.c_str(), fixedName.size());
|
||||
crc = crc32b(crc, (Bytef*)"\0\0\0\0", 4);
|
||||
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);
|
||||
|
||||
for (const auto& item : this->m_PackIndex->GetPackFileIndices()) {
|
||||
if (item.m_Crc == crc) {
|
||||
@@ -152,13 +152,12 @@ bool AssetManager::GetFile(const char* name, char** data, uint32_t* len) {
|
||||
return success;
|
||||
}
|
||||
|
||||
AssetMemoryBuffer AssetManager::GetFileAsBuffer(const char* name) {
|
||||
char* buf;
|
||||
uint32_t len;
|
||||
AssetStream AssetManager::GetFile(const char* name) {
|
||||
char* buf; uint32_t len;
|
||||
|
||||
bool success = this->GetFile(name, &buf, &len);
|
||||
|
||||
return AssetMemoryBuffer(buf, len, success);
|
||||
return AssetStream(buf, len, success);
|
||||
}
|
||||
|
||||
uint32_t AssetManager::crc32b(uint32_t base, uint8_t* message, size_t l) {
|
||||
@@ -168,7 +167,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 ^= (((unsigned int)message[i]) << 24);
|
||||
crc ^= (static_cast<unsigned int>(message[i]) << 24);
|
||||
for (j = 0; j < 8; j++) { // Do eight times.
|
||||
msb = crc >> 31;
|
||||
crc <<= 1;
|
||||
|
||||
@@ -25,6 +25,10 @@ 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);
|
||||
}
|
||||
@@ -40,9 +44,17 @@ struct AssetMemoryBuffer : std::streambuf {
|
||||
setg(eback(), eback() + off, egptr());
|
||||
return gptr() - eback();
|
||||
}
|
||||
};
|
||||
|
||||
void close() {
|
||||
free(m_Base);
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -56,7 +68,7 @@ public:
|
||||
|
||||
bool HasFile(const char* name);
|
||||
bool GetFile(const char* name, char** data, uint32_t* len);
|
||||
AssetMemoryBuffer GetFileAsBuffer(const char* name);
|
||||
AssetStream GetFile(const char* name);
|
||||
|
||||
private:
|
||||
void LoadPackIndex();
|
||||
|
||||
@@ -76,7 +76,7 @@ bool Pack::ReadFileFromPack(uint32_t crc, char** data, uint32_t* len) {
|
||||
fseek(file, pos, SEEK_SET);
|
||||
|
||||
if (!isCompressed) {
|
||||
char* tempData = (char*)malloc(pkRecord.m_UncompressedSize);
|
||||
char* tempData = static_cast<char*>(malloc(pkRecord.m_UncompressedSize));
|
||||
int32_t readInData = fread(tempData, sizeof(uint8_t), pkRecord.m_UncompressedSize, file);
|
||||
|
||||
*data = tempData;
|
||||
@@ -90,7 +90,7 @@ bool Pack::ReadFileFromPack(uint32_t crc, char** data, uint32_t* len) {
|
||||
|
||||
fseek(file, pos, SEEK_SET);
|
||||
|
||||
char* decompressedData = (char*)malloc(pkRecord.m_UncompressedSize);
|
||||
char* decompressedData = static_cast<char*>(malloc(pkRecord.m_UncompressedSize));
|
||||
uint32_t currentReadPos = 0;
|
||||
|
||||
while (true) {
|
||||
@@ -100,12 +100,12 @@ bool Pack::ReadFileFromPack(uint32_t crc, char** data, uint32_t* len) {
|
||||
int32_t readInData = fread(&size, sizeof(uint32_t), 1, file);
|
||||
pos += 4; // Move pointer position 4 to the right
|
||||
|
||||
char* chunk = (char*)malloc(size);
|
||||
char* chunk = static_cast<char*>(malloc(size));
|
||||
int32_t readInData2 = fread(chunk, sizeof(int8_t), size, file);
|
||||
pos += size; // Move pointer position the amount of bytes read to the right
|
||||
|
||||
int32_t err;
|
||||
currentReadPos += ZCompression::Decompress((uint8_t*)chunk, size, reinterpret_cast<uint8_t*>(decompressedData + currentReadPos), ZCompression::MAX_SD0_CHUNK_SIZE, err);
|
||||
currentReadPos += ZCompression::Decompress(reinterpret_cast<uint8_t*>(chunk), size, reinterpret_cast<uint8_t*>(decompressedData + currentReadPos), ZCompression::MAX_SD0_CHUNK_SIZE, err);
|
||||
|
||||
free(chunk);
|
||||
}
|
||||
|
||||
@@ -8,21 +8,10 @@ PackIndex::PackIndex(const std::filesystem::path& filePath) {
|
||||
|
||||
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_Version);
|
||||
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_PackPathCount);
|
||||
|
||||
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);
|
||||
|
||||
m_PackPaths.resize(m_PackPathCount);
|
||||
for (auto& item : m_PackPaths) {
|
||||
BinaryIO::ReadString<uint32_t>(m_FileStream, item, BinaryIO::ReadType::String);
|
||||
}
|
||||
|
||||
BinaryIO::BinaryRead<uint32_t>(m_FileStream, m_PackFileIndexCount);
|
||||
|
||||
@@ -10,8 +10,23 @@ 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::ifstream in(BinaryPathFinder::GetBinaryDir() / m_ConfigFilePath);
|
||||
std::filesystem::path config_dir = GetConfigDir();
|
||||
|
||||
std::ifstream in(config_dir / m_ConfigFilePath);
|
||||
if (!in.good()) return;
|
||||
|
||||
std::string line{};
|
||||
@@ -19,7 +34,7 @@ void dConfig::LoadConfig() {
|
||||
if (!line.empty() && line.front() != '#') ProcessLine(line);
|
||||
}
|
||||
|
||||
std::ifstream sharedConfig(BinaryPathFinder::GetBinaryDir() / "sharedconfig.ini", std::ios::in);
|
||||
std::ifstream sharedConfig(config_dir / "sharedconfig.ini", std::ios::in);
|
||||
if (!sharedConfig.good()) return;
|
||||
|
||||
line.clear();
|
||||
@@ -34,6 +49,11 @@ 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];
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,11 @@ 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.
|
||||
*
|
||||
|
||||
29
dCommon/dEnums/StringifiedEnum.h
Normal file
29
dCommon/dEnums/StringifiedEnum.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef __STRINGIFIEDENUM_H__
|
||||
#define __STRINGIFIEDENUM_H__
|
||||
|
||||
#include <string>
|
||||
#include "magic_enum.hpp"
|
||||
|
||||
namespace StringifiedEnum {
|
||||
template<typename T>
|
||||
const std::string_view ToString(const T e) {
|
||||
static_assert(std::is_enum_v<T>, "Not an enum"); // Check type
|
||||
|
||||
constexpr auto sv = &magic_enum::enum_entries<T>();
|
||||
|
||||
const auto it = std::lower_bound(
|
||||
sv->begin(), sv->end(), e,
|
||||
[&](const std::pair<T, std::string_view>& lhs, const T rhs) { return lhs.first < rhs; }
|
||||
);
|
||||
|
||||
std::string_view output;
|
||||
if (it != sv->end() && it->first == e) {
|
||||
output = it->second;
|
||||
} else {
|
||||
output = "UNKNOWN";
|
||||
}
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // !__STRINGIFIEDENUM_H__
|
||||
@@ -148,11 +148,11 @@ public:
|
||||
if (size > maxSize) size = maxSize;
|
||||
|
||||
for (uint32_t i = 0; i < size; ++i) {
|
||||
bitStream.Write(static_cast<uint16_t>(friendName[i]));
|
||||
bitStream.Write<uint16_t>(friendName[i]);
|
||||
}
|
||||
|
||||
for (uint32_t j = 0; j < remSize; ++j) {
|
||||
bitStream.Write(static_cast<uint16_t>(0));
|
||||
bitStream.Write<uint16_t>(0);
|
||||
}
|
||||
|
||||
bitStream.Write<uint32_t>(0); //???
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -166,7 +166,8 @@ enum ePlayerFlag : int32_t {
|
||||
NJ_LIGHTNING_SPINJITZU = 2031,
|
||||
NJ_ICE_SPINJITZU = 2032,
|
||||
NJ_FIRE_SPINJITZU = 2033,
|
||||
NJ_WU_SHOW_DAILY_CHEST = 2099
|
||||
NJ_WU_SHOW_DAILY_CHEST = 2099,
|
||||
DLU_SKIP_CINEMATICS = 1'000'000,
|
||||
};
|
||||
|
||||
#endif //!__EPLAYERFLAG__H__
|
||||
|
||||
15
dCommon/dEnums/eQuickBuildState.h
Normal file
15
dCommon/dEnums/eQuickBuildState.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef __EQUICKBUILDSTATE__H__
|
||||
#define __EQUICKBUILDSTATE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eQuickBuildState : uint32_t {
|
||||
OPEN,
|
||||
COMPLETED = 2,
|
||||
RESETTING = 4,
|
||||
BUILDING,
|
||||
INCOMPLETE
|
||||
};
|
||||
|
||||
|
||||
#endif //!__EQUICKBUILDSTATE__H__
|
||||
@@ -1,15 +0,0 @@
|
||||
#ifndef __EREBUILDSTATE__H__
|
||||
#define __EREBUILDSTATE__H__
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
enum class eRebuildState : uint32_t {
|
||||
OPEN,
|
||||
COMPLETED = 2,
|
||||
RESETTING = 4,
|
||||
BUILDING,
|
||||
INCOMPLETE
|
||||
};
|
||||
|
||||
|
||||
#endif //!__EREBUILDSTATE__H__
|
||||
@@ -34,7 +34,7 @@ enum class eReplicaComponentType : uint32_t {
|
||||
PLATFORM_BOUNDARY,
|
||||
MODULE,
|
||||
ARCADE,
|
||||
VEHICLE_PHYSICS, // Havok demo based
|
||||
HAVOK_VEHICLE_PHYSICS,
|
||||
MOVEMENT_AI,
|
||||
EXHIBIT,
|
||||
OVERHEAD_ICON,
|
||||
@@ -50,11 +50,11 @@ enum class eReplicaComponentType : uint32_t {
|
||||
PROPERTY_ENTRANCE,
|
||||
FX,
|
||||
PROPERTY_MANAGEMENT,
|
||||
VEHICLE_PHYSICS_NEW, // internal physics based on havok
|
||||
VEHICLE_PHYSICS,
|
||||
PHYSICS_SYSTEM,
|
||||
QUICK_BUILD,
|
||||
SWITCH,
|
||||
ZONE_CONTROL, // Minigame
|
||||
MINI_GAME_CONTROL,
|
||||
CHANGLING,
|
||||
CHOICE_BUILD,
|
||||
PACKAGE,
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "magic_enum.hpp"
|
||||
|
||||
enum class eWorldMessageType : uint32_t {
|
||||
VALIDATION = 1, // Session info
|
||||
CHARACTER_LIST_REQUEST,
|
||||
@@ -40,4 +42,10 @@ enum class eWorldMessageType : uint32_t {
|
||||
UI_HELP_TOP_5 = 91
|
||||
};
|
||||
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<eWorldMessageType> {
|
||||
static constexpr int min = 0;
|
||||
static constexpr int max = 91;
|
||||
};
|
||||
|
||||
#endif //!__EWORLDMESSAGETYPE__H__
|
||||
|
||||
@@ -37,10 +37,13 @@
|
||||
#include "CDPropertyTemplateTable.h"
|
||||
#include "CDFeatureGatingTable.h"
|
||||
#include "CDRailActivatorComponent.h"
|
||||
#include "CDRewardCodesTable.h"
|
||||
|
||||
#ifndef CDCLIENT_CACHE_ALL
|
||||
// Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory.
|
||||
// A vanilla CDClient takes about 46MB of memory + the regular world data.
|
||||
// #define CDCLIENT_CACHE_ALL
|
||||
// # define CDCLIENT_CACHE_ALL
|
||||
#endif // CDCLIENT_CACHE_ALL
|
||||
|
||||
#ifdef CDCLIENT_CACHE_ALL
|
||||
#define CDCLIENT_DONT_CACHE_TABLE(x) x
|
||||
@@ -82,6 +85,7 @@ CDClientManager::CDClientManager() {
|
||||
CDRailActivatorComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDRarityTableTable::Instance().LoadValuesFromDatabase();
|
||||
CDRebuildComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDRewardCodesTable::Instance().LoadValuesFromDatabase();
|
||||
CDRewardsTable::Instance().LoadValuesFromDatabase();
|
||||
CDScriptComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDSkillBehaviorTable::Instance().LoadValuesFromDatabase();
|
||||
|
||||
@@ -10,7 +10,7 @@ void CDComponentsRegistryTable::LoadValuesFromDatabase() {
|
||||
entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0));
|
||||
entry.component_id = tableData.getIntField("component_id", -1);
|
||||
|
||||
this->mappedEntries.insert_or_assign(((uint64_t)entry.component_type) << 32 | ((uint64_t)entry.id), entry.component_id);
|
||||
this->mappedEntries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id);
|
||||
this->mappedEntries.insert_or_assign(entry.id, 0);
|
||||
|
||||
tableData.nextRow();
|
||||
@@ -22,7 +22,7 @@ void CDComponentsRegistryTable::LoadValuesFromDatabase() {
|
||||
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) {
|
||||
auto exists = mappedEntries.find(id);
|
||||
if (exists != mappedEntries.end()) {
|
||||
auto iter = mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
|
||||
auto iter = mappedEntries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id));
|
||||
return iter == mappedEntries.end() ? defaultValue : iter->second;
|
||||
}
|
||||
|
||||
@@ -38,15 +38,14 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponent
|
||||
entry.component_type = static_cast<eReplicaComponentType>(tableData.getIntField("component_type", 0));
|
||||
entry.component_id = tableData.getIntField("component_id", -1);
|
||||
|
||||
this->mappedEntries.insert_or_assign(((uint64_t)entry.component_type) << 32 | ((uint64_t)entry.id), entry.component_id);
|
||||
this->mappedEntries.insert_or_assign(static_cast<uint64_t>(entry.component_type) << 32 | static_cast<uint64_t>(entry.id), entry.component_id);
|
||||
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
mappedEntries.insert_or_assign(id, 0);
|
||||
|
||||
auto iter = this->mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
|
||||
auto iter = this->mappedEntries.find(static_cast<uint64_t>(componentType) << 32 | static_cast<uint64_t>(id));
|
||||
|
||||
return iter == this->mappedEntries.end() ? defaultValue : iter->second;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFe
|
||||
|
||||
bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const {
|
||||
for (const auto& entry : entries) {
|
||||
if (entry.featureName == feature.featureName && entry >= feature) {
|
||||
if (entry.featureName == feature.featureName && feature >= entry) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ void CDMissionEmailTable::LoadValuesFromDatabase() {
|
||||
entry.notificationGroup = tableData.getIntField("notificationGroup", -1);
|
||||
entry.missionID = tableData.getIntField("missionID", -1);
|
||||
entry.attachmentLOT = tableData.getIntField("attachmentLOT", 0);
|
||||
entry.localize = (bool)tableData.getIntField("localize", -1);
|
||||
entry.localize = static_cast<bool>(tableData.getIntField("localize", 1));
|
||||
entry.locStatus = tableData.getIntField("locStatus", -1);
|
||||
entry.gate_version = tableData.getStringField("gate_version", "");
|
||||
|
||||
@@ -50,4 +50,3 @@ std::vector<CDMissionEmail> CDMissionEmailTable::Query(std::function<bool(CDMiss
|
||||
const std::vector<CDMissionEmail>& CDMissionEmailTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#include "CDRewardCodesTable.h"
|
||||
|
||||
void CDRewardCodesTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM RewardCodes");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
|
||||
tableSize.nextRow();
|
||||
}
|
||||
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RewardCodes");
|
||||
while (!tableData.eof()) {
|
||||
CDRewardCode entry;
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
entry.code = tableData.getStringField("code", "");
|
||||
entry.attachmentLOT = tableData.getIntField("attachmentLOT", -1);
|
||||
UNUSED_COLUMN(entry.locStatus = tableData.getIntField("locStatus", -1));
|
||||
UNUSED_COLUMN(entry.gate_version = tableData.getStringField("gate_version", ""));
|
||||
|
||||
this->entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
}
|
||||
|
||||
LOT CDRewardCodesTable::GetAttachmentLOT(uint32_t rewardCodeId) const {
|
||||
for (auto const &entry : this->entries){
|
||||
if (rewardCodeId == entry.id) return entry.attachmentLOT;
|
||||
}
|
||||
return LOT_NULL;
|
||||
}
|
||||
|
||||
uint32_t CDRewardCodesTable::GetCodeID(std::string code) const {
|
||||
for (auto const &entry : this->entries){
|
||||
if (code == entry.code) return entry.id;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
|
||||
struct CDRewardCode {
|
||||
uint32_t id;
|
||||
std::string code;
|
||||
LOT attachmentLOT;
|
||||
UNUSED(uint32_t locStatus);
|
||||
UNUSED(std::string gate_version);
|
||||
};
|
||||
|
||||
|
||||
class CDRewardCodesTable : public CDTable<CDRewardCodesTable> {
|
||||
private:
|
||||
std::vector<CDRewardCode> entries;
|
||||
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
const std::vector<CDRewardCode>& GetEntries() const;
|
||||
LOT GetAttachmentLOT(uint32_t rewardCodeId) const;
|
||||
uint32_t GetCodeID(std::string code) const;
|
||||
};
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
|
||||
// CPPLinq
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -31,6 +31,7 @@ set(DDATABASE_CDCLIENTDATABASE_CDCLIENTTABLES_SOURCES "CDActivitiesTable.cpp"
|
||||
"CDRailActivatorComponent.cpp"
|
||||
"CDRarityTableTable.cpp"
|
||||
"CDRebuildComponentTable.cpp"
|
||||
"CDRewardCodesTable.cpp"
|
||||
"CDRewardsTable.cpp"
|
||||
"CDScriptComponentTable.cpp"
|
||||
"CDSkillBehaviorTable.cpp"
|
||||
|
||||
@@ -14,3 +14,7 @@ endforeach()
|
||||
|
||||
add_library(dDatabase STATIC ${DDATABASE_SOURCES})
|
||||
target_link_libraries(dDatabase sqlite3 mariadbConnCpp)
|
||||
|
||||
if (${CDCLIENT_CACHE_ALL})
|
||||
add_compile_definitions(dDatabase CDCLIENT_CACHE_ALL=${CDCLIENT_CACHE_ALL})
|
||||
endif()
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include "ICharInfo.h"
|
||||
#include "IAccounts.h"
|
||||
#include "IActivityLog.h"
|
||||
#include "IIgnoreList.h"
|
||||
#include "IAccountsRewardCodes.h"
|
||||
|
||||
namespace sql {
|
||||
class Statement;
|
||||
@@ -38,7 +40,7 @@ class GameDatabase :
|
||||
public IMail, public ICommandLog, public IPlayerCheatDetections, public IBugReports,
|
||||
public IPropertyContents, public IProperty, public IPetNames, public ICharXml,
|
||||
public IMigrationHistory, public IUgc, public IFriends, public ICharInfo,
|
||||
public IAccounts, public IActivityLog {
|
||||
public IAccounts, public IActivityLog, public IAccountsRewardCodes, public IIgnoreList {
|
||||
public:
|
||||
virtual ~GameDatabase() = default;
|
||||
// TODO: These should be made private.
|
||||
|
||||
13
dDatabase/GameDatabase/ITables/IAccountsRewardCodes.h
Normal file
13
dDatabase/GameDatabase/ITables/IAccountsRewardCodes.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef __IACCOUNTSREWARDCODES__H__
|
||||
#define __IACCOUNTSREWARDCODES__H__
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
class IAccountsRewardCodes {
|
||||
public:
|
||||
virtual void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) = 0;
|
||||
virtual std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) = 0;
|
||||
};
|
||||
|
||||
#endif //!__IACCOUNTSREWARDCODES__H__
|
||||
20
dDatabase/GameDatabase/ITables/IIgnoreList.h
Normal file
20
dDatabase/GameDatabase/ITables/IIgnoreList.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef __IIGNORELIST__H__
|
||||
#define __IIGNORELIST__H__
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class IIgnoreList {
|
||||
public:
|
||||
struct Info {
|
||||
std::string name;
|
||||
uint32_t id;
|
||||
};
|
||||
|
||||
virtual std::vector<Info> GetIgnoreList(const uint32_t playerId) = 0;
|
||||
virtual void AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) = 0;
|
||||
virtual void RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) = 0;
|
||||
};
|
||||
|
||||
#endif //!__IIGNORELIST__H__
|
||||
@@ -95,7 +95,7 @@ void MigrationRunner::RunSQLiteMigrations() {
|
||||
|
||||
// Check if there is an entry in the migration history table on the cdclient database.
|
||||
cdstmt = CDClientDatabase::CreatePreppedStmt("SELECT name FROM migration_history WHERE name = ?;");
|
||||
cdstmt.bind((int32_t) 1, migration.name.c_str());
|
||||
cdstmt.bind(static_cast<int32_t>(1), migration.name.c_str());
|
||||
auto cdres = cdstmt.execQuery();
|
||||
|
||||
if (!cdres.eof()) continue;
|
||||
@@ -124,7 +124,7 @@ void MigrationRunner::RunSQLiteMigrations() {
|
||||
|
||||
// Insert into cdclient database.
|
||||
cdstmt = CDClientDatabase::CreatePreppedStmt("INSERT INTO migration_history (name) VALUES (?);");
|
||||
cdstmt.bind((int32_t) 1, migration.name.c_str());
|
||||
cdstmt.bind(static_cast<int32_t>(1), migration.name.c_str());
|
||||
cdstmt.execQuery();
|
||||
CDClientDatabase::ExecuteQuery("COMMIT;");
|
||||
}
|
||||
|
||||
@@ -103,6 +103,11 @@ public:
|
||||
std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) override;
|
||||
std::optional<bool> IsPlaykeyActive(const int32_t playkeyId) override;
|
||||
std::vector<IUgc::Model> GetUgcModels(const LWOOBJID& propertyId) override;
|
||||
void AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
|
||||
void RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
|
||||
std::vector<IIgnoreList::Info> GetIgnoreList(const uint32_t playerId) override;
|
||||
void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override;
|
||||
std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) override;
|
||||
private:
|
||||
|
||||
// Generic query functions that can be used for any query.
|
||||
|
||||
17
dDatabase/GameDatabase/MySQL/Tables/AccountsRewardCodes.cpp
Normal file
17
dDatabase/GameDatabase/MySQL/Tables/AccountsRewardCodes.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "MySQLDatabase.h"
|
||||
|
||||
void MySQLDatabase::InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) {
|
||||
ExecuteInsert("INSERT IGNORE INTO accounts_rewardcodes (account_id, rewardcode) VALUES (?, ?);", account_id, reward_code);
|
||||
}
|
||||
|
||||
std::vector<uint32_t> MySQLDatabase::GetRewardCodesByAccountID(const uint32_t account_id) {
|
||||
auto result = ExecuteSelect("SELECT rewardcode FROM accounts_rewardcodes WHERE account_id = ?;", account_id);
|
||||
|
||||
std::vector<uint32_t> toReturn;
|
||||
toReturn.reserve(result->rowsCount());
|
||||
while (result->next()) {
|
||||
toReturn.push_back(result->getUInt("rewardcode"));
|
||||
}
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES
|
||||
"Accounts.cpp"
|
||||
"AccountsRewardCodes.cpp"
|
||||
"ActivityLog.cpp"
|
||||
"BugReports.cpp"
|
||||
"CharInfo.cpp"
|
||||
"CharXml.cpp"
|
||||
"CommandLog.cpp"
|
||||
"Friends.cpp"
|
||||
"IgnoreList.cpp"
|
||||
"Leaderboard.cpp"
|
||||
"Mail.cpp"
|
||||
"MigrationHistory.cpp"
|
||||
|
||||
22
dDatabase/GameDatabase/MySQL/Tables/IgnoreList.cpp
Normal file
22
dDatabase/GameDatabase/MySQL/Tables/IgnoreList.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "MySQLDatabase.h"
|
||||
|
||||
std::vector<IIgnoreList::Info> MySQLDatabase::GetIgnoreList(const uint32_t playerId) {
|
||||
auto result = ExecuteSelect("SELECT ci.name AS name, il.ignored_player_id AS ignore_id FROM ignore_list AS il JOIN charinfo AS ci ON il.ignored_player_id = ci.id WHERE il.player_id = ?", playerId);
|
||||
|
||||
std::vector<IIgnoreList::Info> ignoreList;
|
||||
|
||||
ignoreList.reserve(result->rowsCount());
|
||||
while (result->next()) {
|
||||
ignoreList.push_back(IIgnoreList::Info{ result->getString("name").c_str(), result->getUInt("ignore_id") });
|
||||
}
|
||||
|
||||
return ignoreList;
|
||||
}
|
||||
|
||||
void MySQLDatabase::AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
|
||||
ExecuteInsert("INSERT IGNORE INTO ignore_list (player_id, ignored_player_id) VALUES (?, ?)", playerId, ignoredPlayerId);
|
||||
}
|
||||
|
||||
void MySQLDatabase::RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
|
||||
ExecuteDelete("DELETE FROM ignore_list WHERE player_id = ? AND ignored_player_id = ?", playerId, ignoredPlayerId);
|
||||
}
|
||||
113
dGame/Entity.cpp
113
dGame/Entity.cpp
@@ -47,7 +47,7 @@
|
||||
#include "MovingPlatformComponent.h"
|
||||
#include "MissionComponent.h"
|
||||
#include "MissionOfferComponent.h"
|
||||
#include "RebuildComponent.h"
|
||||
#include "QuickBuildComponent.h"
|
||||
#include "BuildBorderComponent.h"
|
||||
#include "MovementAIComponent.h"
|
||||
#include "VendorComponent.h"
|
||||
@@ -62,7 +62,7 @@
|
||||
#include "ModelComponent.h"
|
||||
#include "ZCompression.h"
|
||||
#include "PetComponent.h"
|
||||
#include "VehiclePhysicsComponent.h"
|
||||
#include "HavokVehiclePhysicsComponent.h"
|
||||
#include "PossessableComponent.h"
|
||||
#include "PossessorComponent.h"
|
||||
#include "ModuleAssemblyComponent.h"
|
||||
@@ -76,7 +76,7 @@
|
||||
#include "eGameMasterLevel.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
#include "eReplicaPacketType.h"
|
||||
#include "ZoneControlComponent.h"
|
||||
#include "MiniGameControlComponent.h"
|
||||
#include "RacingStatsComponent.h"
|
||||
#include "CollectibleComponent.h"
|
||||
#include "ItemComponent.h"
|
||||
@@ -166,7 +166,9 @@ void Entity::Initialize() {
|
||||
|
||||
if (!groupIDs.empty()) {
|
||||
m_Groups = GeneralUtils::SplitString(groupIDs, ';');
|
||||
m_Groups.erase(m_Groups.end() - 1);
|
||||
if (!m_Groups.empty()) {
|
||||
if (m_Groups.back().empty()) m_Groups.erase(m_Groups.end() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,8 +219,8 @@ void Entity::Initialize() {
|
||||
AddComponent<PetComponent>(petComponentId);
|
||||
}
|
||||
|
||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ZONE_CONTROL) > 0) {
|
||||
AddComponent<ZoneControlComponent>();
|
||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MINI_GAME_CONTROL) > 0) {
|
||||
AddComponent<MiniGameControlComponent>();
|
||||
}
|
||||
|
||||
uint32_t possessableComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::POSSESSABLE);
|
||||
@@ -299,10 +301,10 @@ void Entity::Initialize() {
|
||||
AddComponent<PhantomPhysicsComponent>()->SetPhysicsEffectActive(false);
|
||||
}
|
||||
|
||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VEHICLE_PHYSICS) > 0) {
|
||||
auto* vehiclePhysicsComponent = AddComponent<VehiclePhysicsComponent>();
|
||||
vehiclePhysicsComponent->SetPosition(m_DefaultPosition);
|
||||
vehiclePhysicsComponent->SetRotation(m_DefaultRotation);
|
||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::HAVOK_VEHICLE_PHYSICS) > 0) {
|
||||
auto* havokVehiclePhysicsComponent = AddComponent<HavokVehiclePhysicsComponent>();
|
||||
havokVehiclePhysicsComponent->SetPosition(m_DefaultPosition);
|
||||
havokVehiclePhysicsComponent->SetRotation(m_DefaultRotation);
|
||||
}
|
||||
|
||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SOUND_TRIGGER, -1) != -1) {
|
||||
@@ -325,16 +327,16 @@ void Entity::Initialize() {
|
||||
* Multiple components require the destructible component.
|
||||
*/
|
||||
int buffComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::BUFF);
|
||||
int rebuildComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD);
|
||||
int quickBuildComponentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD);
|
||||
|
||||
int componentID = -1;
|
||||
if (collectibleComponentID > 0) componentID = collectibleComponentID;
|
||||
if (rebuildComponentID > 0) componentID = rebuildComponentID;
|
||||
if (quickBuildComponentID > 0) componentID = quickBuildComponentID;
|
||||
if (buffComponentID > 0) componentID = buffComponentID;
|
||||
|
||||
CDDestructibleComponentTable* destCompTable = CDClientManager::Instance().GetTable<CDDestructibleComponentTable>();
|
||||
std::vector<CDDestructibleComponent> destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); });
|
||||
|
||||
|
||||
bool isSmashable = GetVarAs<int32_t>(u"is_smashable") != 0;
|
||||
if (buffComponentID > 0 || collectibleComponentID > 0 || isSmashable) {
|
||||
DestroyableComponent* comp = AddComponent<DestroyableComponent>();
|
||||
@@ -519,45 +521,50 @@ void Entity::Initialize() {
|
||||
}
|
||||
|
||||
if (int componentID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::QUICK_BUILD) > 0) {
|
||||
auto* rebuildComponent = AddComponent<RebuildComponent>();
|
||||
auto* quickBuildComponent = AddComponent<QuickBuildComponent>();
|
||||
|
||||
CDRebuildComponentTable* rebCompTable = CDClientManager::Instance().GetTable<CDRebuildComponentTable>();
|
||||
std::vector<CDRebuildComponent> rebCompData = rebCompTable->Query([=](CDRebuildComponent entry) { return (entry.id == rebuildComponentID); });
|
||||
std::vector<CDRebuildComponent> rebCompData = rebCompTable->Query([=](CDRebuildComponent entry) { return (entry.id == quickBuildComponentID); });
|
||||
|
||||
if (rebCompData.size() > 0) {
|
||||
rebuildComponent->SetResetTime(rebCompData[0].reset_time);
|
||||
rebuildComponent->SetCompleteTime(rebCompData[0].complete_time);
|
||||
rebuildComponent->SetTakeImagination(rebCompData[0].take_imagination);
|
||||
rebuildComponent->SetInterruptible(rebCompData[0].interruptible);
|
||||
rebuildComponent->SetSelfActivator(rebCompData[0].self_activator);
|
||||
rebuildComponent->SetActivityId(rebCompData[0].activityID);
|
||||
rebuildComponent->SetPostImaginationCost(rebCompData[0].post_imagination_cost);
|
||||
rebuildComponent->SetTimeBeforeSmash(rebCompData[0].time_before_smash);
|
||||
quickBuildComponent->SetResetTime(rebCompData[0].reset_time);
|
||||
quickBuildComponent->SetCompleteTime(rebCompData[0].complete_time);
|
||||
quickBuildComponent->SetTakeImagination(rebCompData[0].take_imagination);
|
||||
quickBuildComponent->SetInterruptible(rebCompData[0].interruptible);
|
||||
quickBuildComponent->SetSelfActivator(rebCompData[0].self_activator);
|
||||
quickBuildComponent->SetActivityId(rebCompData[0].activityID);
|
||||
quickBuildComponent->SetPostImaginationCost(rebCompData[0].post_imagination_cost);
|
||||
quickBuildComponent->SetTimeBeforeSmash(rebCompData[0].time_before_smash);
|
||||
|
||||
const auto rebuildResetTime = GetVar<float>(u"rebuild_reset_time");
|
||||
|
||||
if (rebuildResetTime != 0.0f) {
|
||||
rebuildComponent->SetResetTime(rebuildResetTime);
|
||||
quickBuildComponent->SetResetTime(rebuildResetTime);
|
||||
|
||||
// Known bug with moving platform in FV that casues it to build at the end instead of the start.
|
||||
// This extends the smash time so players can ride up the lift.
|
||||
if (m_TemplateID == 9483)
|
||||
{
|
||||
rebuildComponent->SetResetTime(rebuildComponent->GetResetTime() + 25);
|
||||
if (m_TemplateID == 9483) {
|
||||
quickBuildComponent->SetResetTime(quickBuildComponent->GetResetTime() + 25);
|
||||
}
|
||||
}
|
||||
|
||||
const auto activityID = GetVar<int32_t>(u"activityID");
|
||||
|
||||
if (activityID > 0) {
|
||||
rebuildComponent->SetActivityId(activityID);
|
||||
quickBuildComponent->SetActivityId(activityID);
|
||||
Loot::CacheMatrix(activityID);
|
||||
}
|
||||
|
||||
const auto timeBeforeSmash = GetVar<float>(u"tmeSmsh");
|
||||
|
||||
if (timeBeforeSmash > 0) {
|
||||
quickBuildComponent->SetTimeBeforeSmash(timeBeforeSmash);
|
||||
}
|
||||
|
||||
const auto compTime = GetVar<float>(u"compTime");
|
||||
|
||||
if (compTime > 0) {
|
||||
rebuildComponent->SetCompleteTime(compTime);
|
||||
quickBuildComponent->SetCompleteTime(compTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -598,8 +605,8 @@ void Entity::Initialize() {
|
||||
}
|
||||
|
||||
// Scripted activity component
|
||||
int scriptedActivityID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SCRIPTED_ACTIVITY);
|
||||
if ((scriptedActivityID > 0)) {
|
||||
int scriptedActivityID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SCRIPTED_ACTIVITY, -1);
|
||||
if ((scriptedActivityID != -1)) {
|
||||
AddComponent<ScriptedActivityComponent>(scriptedActivityID);
|
||||
}
|
||||
|
||||
@@ -738,7 +745,7 @@ void Entity::Initialize() {
|
||||
!HasComponent(eReplicaComponentType::PHANTOM_PHYSICS) &&
|
||||
!HasComponent(eReplicaComponentType::PROPERTY) &&
|
||||
!HasComponent(eReplicaComponentType::RACING_CONTROL) &&
|
||||
!HasComponent(eReplicaComponentType::VEHICLE_PHYSICS)
|
||||
!HasComponent(eReplicaComponentType::HAVOK_VEHICLE_PHYSICS)
|
||||
)
|
||||
//if (HasComponent(eReplicaComponentType::BASE_COMBAT_AI))
|
||||
{
|
||||
@@ -975,9 +982,9 @@ void Entity::WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacke
|
||||
}
|
||||
outBitStream->Write(m_ChildEntities.size() > 0);
|
||||
if (m_ChildEntities.size() > 0) {
|
||||
outBitStream->Write((uint16_t)m_ChildEntities.size());
|
||||
outBitStream->Write<uint16_t>(m_ChildEntities.size());
|
||||
for (Entity* child : m_ChildEntities) {
|
||||
outBitStream->Write((uint64_t)child->GetObjectID());
|
||||
outBitStream->Write<uint64_t>(child->GetObjectID());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1017,9 +1024,9 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
||||
rigidbodyPhantomPhysics->Serialize(outBitStream, bIsInitialUpdate);
|
||||
}
|
||||
|
||||
VehiclePhysicsComponent* vehiclePhysicsComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::VEHICLE_PHYSICS, vehiclePhysicsComponent)) {
|
||||
vehiclePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
HavokVehiclePhysicsComponent* havokVehiclePhysicsComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::HAVOK_VEHICLE_PHYSICS, havokVehiclePhysicsComponent)) {
|
||||
havokVehiclePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
}
|
||||
|
||||
PhantomPhysicsComponent* phantomPhysicsComponent;
|
||||
@@ -1118,14 +1125,14 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
||||
baseCombatAiComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
}
|
||||
|
||||
RebuildComponent* rebuildComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::QUICK_BUILD, rebuildComponent)) {
|
||||
QuickBuildComponent* quickBuildComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::QUICK_BUILD, quickBuildComponent)) {
|
||||
DestroyableComponent* destroyableComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) {
|
||||
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
}
|
||||
destroyableSerialized = true;
|
||||
rebuildComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
quickBuildComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
}
|
||||
|
||||
MovingPlatformComponent* movingPlatformComponent;
|
||||
@@ -1191,9 +1198,9 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
||||
}
|
||||
}
|
||||
|
||||
ZoneControlComponent* zoneControlComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::ZONE_CONTROL, zoneControlComponent)) {
|
||||
zoneControlComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
MiniGameControlComponent* miniGameControlComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::MINI_GAME_CONTROL, miniGameControlComponent)) {
|
||||
miniGameControlComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
}
|
||||
|
||||
// BBB Component, unused currently
|
||||
@@ -1503,7 +1510,7 @@ void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u
|
||||
destroyableComponent->Smash(source, killType, deathType);
|
||||
}
|
||||
|
||||
void Entity::Kill(Entity* murderer) {
|
||||
void Entity::Kill(Entity* murderer, const eKillType killType) {
|
||||
if (!m_PlayerIsReadyForUpdates) return;
|
||||
|
||||
for (const auto& cb : m_DieCallbacks) {
|
||||
@@ -1527,7 +1534,7 @@ void Entity::Kill(Entity* murderer) {
|
||||
bool waitForDeathAnimation = false;
|
||||
|
||||
if (destroyableComponent) {
|
||||
waitForDeathAnimation = destroyableComponent->GetDeathBehavior() == 0;
|
||||
waitForDeathAnimation = destroyableComponent->GetDeathBehavior() == 0 && killType != eKillType::SILENT;
|
||||
}
|
||||
|
||||
// Live waited a hard coded 12 seconds for death animations of type 0 before networking destruction!
|
||||
@@ -1581,10 +1588,10 @@ void Entity::AddCollisionPhantomCallback(const std::function<void(Entity* target
|
||||
m_PhantomCollisionCallbacks.push_back(callback);
|
||||
}
|
||||
|
||||
void Entity::AddRebuildCompleteCallback(const std::function<void(Entity* user)>& callback) const {
|
||||
auto* rebuildComponent = GetComponent<RebuildComponent>();
|
||||
if (rebuildComponent != nullptr) {
|
||||
rebuildComponent->AddRebuildCompleteCallback(callback);
|
||||
void Entity::AddQuickBuildCompleteCallback(const std::function<void(Entity* user)>& callback) const {
|
||||
auto* quickBuildComponent = GetComponent<QuickBuildComponent>();
|
||||
if (quickBuildComponent != nullptr) {
|
||||
quickBuildComponent->AddQuickBuildCompleteCallback(callback);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1840,7 +1847,7 @@ const NiPoint3& Entity::GetPosition() const {
|
||||
return simple->GetPosition();
|
||||
}
|
||||
|
||||
auto* vehicel = GetComponent<VehiclePhysicsComponent>();
|
||||
auto* vehicel = GetComponent<HavokVehiclePhysicsComponent>();
|
||||
|
||||
if (vehicel != nullptr) {
|
||||
return vehicel->GetPosition();
|
||||
@@ -1868,7 +1875,7 @@ const NiQuaternion& Entity::GetRotation() const {
|
||||
return simple->GetRotation();
|
||||
}
|
||||
|
||||
auto* vehicel = GetComponent<VehiclePhysicsComponent>();
|
||||
auto* vehicel = GetComponent<HavokVehiclePhysicsComponent>();
|
||||
|
||||
if (vehicel != nullptr) {
|
||||
return vehicel->GetRotation();
|
||||
@@ -1896,7 +1903,7 @@ void Entity::SetPosition(NiPoint3 position) {
|
||||
simple->SetPosition(position);
|
||||
}
|
||||
|
||||
auto* vehicel = GetComponent<VehiclePhysicsComponent>();
|
||||
auto* vehicel = GetComponent<HavokVehiclePhysicsComponent>();
|
||||
|
||||
if (vehicel != nullptr) {
|
||||
vehicel->SetPosition(position);
|
||||
@@ -1924,7 +1931,7 @@ void Entity::SetRotation(NiQuaternion rotation) {
|
||||
simple->SetRotation(rotation);
|
||||
}
|
||||
|
||||
auto* vehicel = GetComponent<VehiclePhysicsComponent>();
|
||||
auto* vehicel = GetComponent<HavokVehiclePhysicsComponent>();
|
||||
|
||||
if (vehicel != nullptr) {
|
||||
vehicel->SetRotation(rotation);
|
||||
|
||||
@@ -210,8 +210,8 @@ public:
|
||||
void RequestActivityExit(Entity* sender, LWOOBJID player, bool canceled);
|
||||
|
||||
void Smash(const LWOOBJID source = LWOOBJID_EMPTY, const eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"");
|
||||
void Kill(Entity* murderer = nullptr);
|
||||
void AddRebuildCompleteCallback(const std::function<void(Entity* user)>& callback) const;
|
||||
void Kill(Entity* murderer = nullptr, const eKillType killType = eKillType::SILENT);
|
||||
void AddQuickBuildCompleteCallback(const std::function<void(Entity* user)>& callback) const;
|
||||
void AddCollisionPhantomCallback(const std::function<void(Entity* target)>& callback);
|
||||
void AddDieCallback(const std::function<void()>& callback);
|
||||
void Resurrect();
|
||||
|
||||
@@ -47,10 +47,6 @@ std::vector<LWOMAPID> EntityManager::m_GhostingExcludedZones = {
|
||||
|
||||
// Configure some exceptions for ghosting, nessesary for some special objects.
|
||||
std::vector<LOT> EntityManager::m_GhostingExcludedLOTs = {
|
||||
// NT - Pipes
|
||||
9524,
|
||||
12408,
|
||||
|
||||
// AG - Footrace
|
||||
4967
|
||||
};
|
||||
@@ -185,8 +181,8 @@ void EntityManager::SerializeEntities() {
|
||||
m_SerializationCounter++;
|
||||
|
||||
RakNet::BitStream stream;
|
||||
stream.Write(static_cast<char>(ID_REPLICA_MANAGER_SERIALIZE));
|
||||
stream.Write(static_cast<unsigned short>(entity->GetNetworkId()));
|
||||
stream.Write<char>(ID_REPLICA_MANAGER_SERIALIZE);
|
||||
stream.Write<unsigned short>(entity->GetNetworkId());
|
||||
|
||||
entity->WriteBaseReplicaData(&stream, eReplicaPacketType::SERIALIZATION);
|
||||
entity->WriteComponents(&stream, eReplicaPacketType::SERIALIZATION);
|
||||
@@ -370,9 +366,9 @@ void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr
|
||||
|
||||
RakNet::BitStream stream;
|
||||
|
||||
stream.Write(static_cast<char>(ID_REPLICA_MANAGER_CONSTRUCTION));
|
||||
stream.Write<char>(ID_REPLICA_MANAGER_CONSTRUCTION);
|
||||
stream.Write(true);
|
||||
stream.Write(static_cast<unsigned short>(entity->GetNetworkId()));
|
||||
stream.Write<unsigned short>(entity->GetNetworkId());
|
||||
|
||||
entity->WriteBaseReplicaData(&stream, eReplicaPacketType::CONSTRUCTION);
|
||||
entity->WriteComponents(&stream, eReplicaPacketType::CONSTRUCTION);
|
||||
@@ -420,8 +416,8 @@ void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr)
|
||||
|
||||
RakNet::BitStream stream;
|
||||
|
||||
stream.Write(static_cast<char>(ID_REPLICA_MANAGER_DESTRUCTION));
|
||||
stream.Write(static_cast<unsigned short>(entity->GetNetworkId()));
|
||||
stream.Write<char>(ID_REPLICA_MANAGER_DESTRUCTION);
|
||||
stream.Write<unsigned short>(entity->GetNetworkId());
|
||||
|
||||
Game::server->Send(&stream, sysAddr, sysAddr == UNASSIGNED_SYSTEM_ADDRESS);
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@ void Leaderboard::SetupLeaderboard(bool weekly, uint32_t resultStart, uint32_t r
|
||||
SELECT leaderboardsRanked.*, character_id, UNIX_TIMESTAMP(last_played) as lastPlayed, leaderboardsRanked.name, leaderboardsRanked.ranking FROM leaderboardsRanked, myStanding, lowestRanking
|
||||
WHERE leaderboardsRanked.ranking
|
||||
BETWEEN
|
||||
LEAST(GREATEST(CAST(myRank AS SIGNED) - 5, %i), lowestRanking.lowestRank - 9)
|
||||
LEAST(GREATEST(CAST(myRank AS SIGNED) - 5, %i), CAST(lowestRanking.lowestRank AS SIGNED) - 9)
|
||||
AND
|
||||
LEAST(GREATEST(myRank + 5, %i), lowestRanking.lowestRank)
|
||||
ORDER BY ranking ASC;
|
||||
|
||||
@@ -60,6 +60,8 @@ void Player::SetSystemAddress(const SystemAddress& value) {
|
||||
}
|
||||
|
||||
void Player::SetRespawnPos(const NiPoint3 position) {
|
||||
if (!m_Character) return;
|
||||
|
||||
m_respawnPos = position;
|
||||
|
||||
m_Character->SetRespawnPoint(Game::zoneManager->GetZone()->GetWorldID(), position);
|
||||
|
||||
@@ -110,3 +110,7 @@ void User::UserOutOfSync() {
|
||||
Game::server->Disconnect(this->m_SystemAddress, eServerDisconnectIdentifiers::PLAY_SCHEDULE_TIME_DONE);
|
||||
}
|
||||
}
|
||||
|
||||
void User::UpdateBestFriendValue(const std::string_view playerName, const bool newValue) {
|
||||
m_IsBestFriendMap[playerName.data()] = newValue;
|
||||
}
|
||||
|
||||
@@ -43,8 +43,8 @@ public:
|
||||
bool GetLastChatMessageApproved() { return m_LastChatMessageApproved; }
|
||||
void SetLastChatMessageApproved(bool approved) { m_LastChatMessageApproved = approved; }
|
||||
|
||||
std::unordered_map<std::string, bool> GetIsBestFriendMap() { return m_IsBestFriendMap; }
|
||||
void SetIsBestFriendMap(std::unordered_map<std::string, bool> mapToSet) { m_IsBestFriendMap = mapToSet; }
|
||||
const std::unordered_map<std::string, bool>& GetIsBestFriendMap() { return m_IsBestFriendMap; }
|
||||
void UpdateBestFriendValue(const std::string_view playerName, const bool newValue);
|
||||
|
||||
bool GetIsMuted() const;
|
||||
|
||||
|
||||
@@ -44,57 +44,53 @@ inline void StripCR(std::string& str) {
|
||||
void UserManager::Initialize() {
|
||||
std::string line;
|
||||
|
||||
AssetMemoryBuffer fnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_first.txt");
|
||||
if (!fnBuff.m_Success) {
|
||||
auto fnStream = Game::assetManager->GetFile("names/minifigname_first.txt");
|
||||
if (!fnStream) {
|
||||
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_first.txt").string().c_str());
|
||||
throw std::runtime_error("Aborting initialization due to missing minifigure name file.");
|
||||
}
|
||||
std::istream fnStream = std::istream(&fnBuff);
|
||||
|
||||
while (std::getline(fnStream, line, '\n')) {
|
||||
std::string name = line;
|
||||
StripCR(name);
|
||||
m_FirstNames.push_back(name);
|
||||
}
|
||||
fnBuff.close();
|
||||
|
||||
AssetMemoryBuffer mnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_middle.txt");
|
||||
if (!mnBuff.m_Success) {
|
||||
auto mnStream = Game::assetManager->GetFile("names/minifigname_middle.txt");
|
||||
if (!mnStream) {
|
||||
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_middle.txt").string().c_str());
|
||||
throw std::runtime_error("Aborting initialization due to missing minifigure name file.");
|
||||
}
|
||||
std::istream mnStream = std::istream(&mnBuff);
|
||||
|
||||
while (std::getline(mnStream, line, '\n')) {
|
||||
std::string name = line;
|
||||
StripCR(name);
|
||||
m_MiddleNames.push_back(name);
|
||||
}
|
||||
mnBuff.close();
|
||||
|
||||
AssetMemoryBuffer lnBuff = Game::assetManager->GetFileAsBuffer("names/minifigname_last.txt");
|
||||
if (!lnBuff.m_Success) {
|
||||
auto lnStream = Game::assetManager->GetFile("names/minifigname_last.txt");
|
||||
if (!lnStream) {
|
||||
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "names/minifigname_last.txt").string().c_str());
|
||||
throw std::runtime_error("Aborting initialization due to missing minifigure name file.");
|
||||
}
|
||||
std::istream lnStream = std::istream(&lnBuff);
|
||||
|
||||
while (std::getline(lnStream, line, '\n')) {
|
||||
std::string name = line;
|
||||
StripCR(name);
|
||||
m_LastNames.push_back(name);
|
||||
}
|
||||
lnBuff.close();
|
||||
|
||||
//Load our pre-approved names:
|
||||
AssetMemoryBuffer chatListBuff = Game::assetManager->GetFileAsBuffer("chatplus_en_us.txt");
|
||||
if (!chatListBuff.m_Success) {
|
||||
// Load our pre-approved names:
|
||||
auto chatListStream = Game::assetManager->GetFile("chatplus_en_us.txt");
|
||||
if (!chatListStream) {
|
||||
LOG("Failed to load %s", (Game::assetManager->GetResPath() / "chatplus_en_us.txt").string().c_str());
|
||||
throw std::runtime_error("Aborting initialization due to missing chat whitelist file.");
|
||||
}
|
||||
std::istream chatListStream = std::istream(&chatListBuff);
|
||||
|
||||
while (std::getline(chatListStream, line, '\n')) {
|
||||
StripCR(line);
|
||||
m_PreapprovedNames.push_back(line);
|
||||
}
|
||||
chatListBuff.close();
|
||||
}
|
||||
|
||||
UserManager::~UserManager() {
|
||||
@@ -207,7 +203,7 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
|
||||
chars[i]->SaveXMLToDatabase();
|
||||
|
||||
chars[i]->GetEntity()->SetCharacter(nullptr);
|
||||
|
||||
|
||||
delete chars[i];
|
||||
}
|
||||
|
||||
@@ -267,7 +263,7 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
}
|
||||
|
||||
//Now that the name is ok, we can get an objectID from Master:
|
||||
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t objectID) {
|
||||
ObjectIDManager::Instance()->RequestPersistentID([=, this](uint32_t objectID) {
|
||||
if (Database::Get()->GetCharacterInfo(objectID)) {
|
||||
LOG("Character object id unavailable, check object_id_tracker!");
|
||||
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::OBJECT_ID_UNAVAILABLE);
|
||||
@@ -275,60 +271,58 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
}
|
||||
|
||||
std::stringstream xml;
|
||||
xml << "<obj v=\"1\"><mf hc=\"" << hairColor << "\" hs=\"" << hairStyle << "\" hd=\"0\" t=\"" << shirtColor << "\" l=\"" << pantsColor;
|
||||
xml << "<obj v=\"1\">";
|
||||
|
||||
xml << "<mf hc=\"" << hairColor << "\" hs=\"" << hairStyle << "\" hd=\"0\" t=\"" << shirtColor << "\" l=\"" << pantsColor;
|
||||
xml << "\" hdc=\"0\" cd=\"" << shirtStyle << "\" lh=\"" << lh << "\" rh=\"" << rh << "\" es=\"" << eyebrows << "\" ";
|
||||
xml << "ess=\"" << eyes << "\" ms=\"" << mouth << "\"/>";
|
||||
|
||||
xml << "<char acct=\"" << u->GetAccountID() << "\" cc=\"0\" gm=\"0\" ft=\"0\" llog=\"" << time(NULL) << "\" ";
|
||||
xml << "ls=\"0\" lzx=\"-626.5847\" lzy=\"613.3515\" lzz=\"-28.6374\" lzrx=\"0.0\" lzry=\"0.7015\" lzrz=\"0.0\" lzrw=\"0.7126\" ";
|
||||
xml << "stt=\"0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;\"></char>";
|
||||
|
||||
xml << "<dest hm=\"4\" hc=\"4\" im=\"0\" ic=\"0\" am=\"0\" ac=\"0\" d=\"0\"/>";
|
||||
|
||||
xml << "<inv><bag><b t=\"0\" m=\"20\"/><b t=\"1\" m=\"40\"/><b t=\"2\" m=\"240\"/><b t=\"3\" m=\"240\"/><b t=\"14\" m=\"40\"/></bag><items><in t=\"0\">";
|
||||
std::string xmlSave1 = xml.str();
|
||||
|
||||
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t idforshirt) {
|
||||
std::stringstream xml2;
|
||||
LWOOBJID lwoidforshirt = ObjectIDManager::GenerateRandomObjectID();
|
||||
LWOOBJID lwoidforpants;
|
||||
|
||||
LWOOBJID lwoidforshirt = idforshirt;
|
||||
GeneralUtils::SetBit(lwoidforshirt, eObjectBits::CHARACTER);
|
||||
GeneralUtils::SetBit(lwoidforshirt, eObjectBits::PERSISTENT);
|
||||
xml2 << xmlSave1 << "<i l=\"" << shirtLOT << "\" id=\"" << lwoidforshirt << "\" s=\"0\" c=\"1\" eq=\"1\" b=\"1\"/>";
|
||||
do {
|
||||
lwoidforpants = ObjectIDManager::GenerateRandomObjectID();
|
||||
} while (lwoidforpants == lwoidforshirt); //Make sure we don't have the same ID for both shirt and pants
|
||||
|
||||
std::string xmlSave2 = xml2.str();
|
||||
GeneralUtils::SetBit(lwoidforshirt, eObjectBits::CHARACTER);
|
||||
GeneralUtils::SetBit(lwoidforshirt, eObjectBits::PERSISTENT);
|
||||
GeneralUtils::SetBit(lwoidforpants, eObjectBits::CHARACTER);
|
||||
GeneralUtils::SetBit(lwoidforpants, eObjectBits::PERSISTENT);
|
||||
|
||||
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t idforpants) {
|
||||
LWOOBJID lwoidforpants = idforpants;
|
||||
GeneralUtils::SetBit(lwoidforpants, eObjectBits::CHARACTER);
|
||||
GeneralUtils::SetBit(lwoidforpants, eObjectBits::PERSISTENT);
|
||||
xml << "<i l=\"" << shirtLOT << "\" id=\"" << lwoidforshirt << "\" s=\"0\" c=\"1\" eq=\"1\" b=\"1\"/>";
|
||||
xml << "<i l=\"" << pantsLOT << "\" id=\"" << lwoidforpants << "\" s=\"1\" c=\"1\" eq=\"1\" b=\"1\"/>";
|
||||
|
||||
std::stringstream xml3;
|
||||
xml3 << xmlSave2 << "<i l=\"" << pantsLOT << "\" id=\"" << lwoidforpants << "\" s=\"1\" c=\"1\" eq=\"1\" b=\"1\"/>";
|
||||
xml << "</in></items></inv><lvl l=\"1\" cv=\"1\" sb=\"500\"/><flag></flag></obj>";
|
||||
|
||||
xml3 << "</in></items></inv><lvl l=\"1\" cv=\"1\" sb=\"500\"/><flag></flag></obj>";
|
||||
//Check to see if our name was pre-approved:
|
||||
bool nameOk = IsNamePreapproved(name);
|
||||
if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
|
||||
|
||||
//Check to see if our name was pre-approved:
|
||||
bool nameOk = IsNamePreapproved(name);
|
||||
if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
|
||||
std::string_view nameToAssign = !name.empty() && nameOk ? name : predefinedName;
|
||||
std::string pendingName = !name.empty() && !nameOk ? name : "";
|
||||
|
||||
std::string_view nameToAssign = !name.empty() && nameOk ? name : predefinedName;
|
||||
std::string pendingName = !name.empty() && !nameOk ? name : "";
|
||||
ICharInfo::Info info;
|
||||
info.name = nameToAssign;
|
||||
info.pendingName = pendingName;
|
||||
info.id = objectID;
|
||||
info.accountId = u->GetAccountID();
|
||||
|
||||
ICharInfo::Info info;
|
||||
info.name = nameToAssign;
|
||||
info.pendingName = pendingName;
|
||||
info.id = objectID;
|
||||
info.accountId = u->GetAccountID();
|
||||
Database::Get()->InsertNewCharacter(info);
|
||||
|
||||
Database::Get()->InsertNewCharacter(info);
|
||||
//Now finally insert our character xml:
|
||||
Database::Get()->InsertCharacterXml(objectID, xml.str());
|
||||
|
||||
//Now finally insert our character xml:
|
||||
Database::Get()->InsertCharacterXml(objectID, xml3.str());
|
||||
|
||||
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::SUCCESS);
|
||||
UserManager::RequestCharacterList(sysAddr);
|
||||
});
|
||||
});
|
||||
});
|
||||
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::SUCCESS);
|
||||
UserManager::RequestCharacterList(sysAddr);
|
||||
});
|
||||
}
|
||||
|
||||
void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet) {
|
||||
@@ -407,7 +401,7 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
return;
|
||||
}
|
||||
|
||||
if (Database::Get()->GetCharacterInfo(newName)) {
|
||||
if (!Database::Get()->GetCharacterInfo(newName)) {
|
||||
if (IsNamePreapproved(newName)) {
|
||||
Database::Get()->SetCharacterName(charID, newName);
|
||||
LOG("Character %s now known as %s", character->GetName().c_str(), newName.c_str());
|
||||
@@ -466,16 +460,18 @@ void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID
|
||||
|
||||
uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) {
|
||||
try {
|
||||
std::string shirtQuery = "select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == \"character create shirt\" AND icc.color1 == ";
|
||||
shirtQuery += std::to_string(shirtColor);
|
||||
shirtQuery += " AND icc.decal == ";
|
||||
shirtQuery = shirtQuery + std::to_string(shirtStyle);
|
||||
auto tableData = CDClientDatabase::ExecuteQuery(shirtQuery);
|
||||
auto shirtLOT = tableData.getIntField(0, -1);
|
||||
auto stmt = CDClientDatabase::CreatePreppedStmt(
|
||||
"select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ? AND icc.decal == ?"
|
||||
);
|
||||
stmt.bind(1, "character create shirt");
|
||||
stmt.bind(2, static_cast<int>(shirtColor));
|
||||
stmt.bind(3, static_cast<int>(shirtStyle));
|
||||
auto tableData = stmt.execQuery();
|
||||
auto shirtLOT = tableData.getIntField(0, 4069);
|
||||
tableData.finalize();
|
||||
return shirtLOT;
|
||||
} catch (const std::exception&) {
|
||||
LOG("Failed to execute query! Using backup...");
|
||||
} catch (const std::exception& ex) {
|
||||
LOG("Could not look up shirt %i %i: %s", shirtColor, shirtStyle, ex.what());
|
||||
// in case of no shirt found in CDServer, return problematic red vest.
|
||||
return 4069;
|
||||
}
|
||||
@@ -483,14 +479,17 @@ uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) {
|
||||
|
||||
uint32_t FindCharPantsID(uint32_t pantsColor) {
|
||||
try {
|
||||
std::string pantsQuery = "select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == \"cc pants\" AND icc.color1 == ";
|
||||
pantsQuery += std::to_string(pantsColor);
|
||||
auto tableData = CDClientDatabase::ExecuteQuery(pantsQuery);
|
||||
auto pantsLOT = tableData.getIntField(0, -1);
|
||||
auto stmt = CDClientDatabase::CreatePreppedStmt(
|
||||
"select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ?"
|
||||
);
|
||||
stmt.bind(1, "cc pants");
|
||||
stmt.bind(2, static_cast<int>(pantsColor));
|
||||
auto tableData = stmt.execQuery();
|
||||
auto pantsLOT = tableData.getIntField(0, 2508);
|
||||
tableData.finalize();
|
||||
return pantsLOT;
|
||||
} catch (const std::exception&) {
|
||||
LOG("Failed to execute query! Using backup...");
|
||||
} catch (const std::exception& ex) {
|
||||
LOG("Could not look up pants %i: %s", pantsColor, ex.what());
|
||||
// in case of no pants color found in CDServer, return red pants.
|
||||
return 2508;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ void ApplyBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS
|
||||
if (buffComponent == nullptr) return;
|
||||
|
||||
buffComponent->ApplyBuff(m_BuffId, m_Duration, context->originator, addImmunity, cancelOnDamaged, cancelOnDeath,
|
||||
cancelOnLogout, cancelonRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone);
|
||||
cancelOnLogout, cancelonRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone, m_ApplyOnTeammates);
|
||||
}
|
||||
|
||||
void ApplyBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
|
||||
@@ -45,4 +45,5 @@ void ApplyBuffBehavior::Load() {
|
||||
cancelOnUi = GetBoolean("cancel_on_ui");
|
||||
cancelOnUnequip = GetBoolean("cancel_on_unequip");
|
||||
cancelOnZone = GetBoolean("cancel_on_zone");
|
||||
m_ApplyOnTeammates = GetBoolean("apply_on_teammates");
|
||||
}
|
||||
|
||||
@@ -31,4 +31,6 @@ public:
|
||||
void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
|
||||
|
||||
void Load() override;
|
||||
private:
|
||||
bool m_ApplyOnTeammates;
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "Logger.h"
|
||||
#include "BehaviorBranchContext.h"
|
||||
#include "BehaviorContext.h"
|
||||
#include "RebuildComponent.h"
|
||||
#include "QuickBuildComponent.h"
|
||||
#include "DestroyableComponent.h"
|
||||
#include "Game.h"
|
||||
#include "Logger.h"
|
||||
|
||||
@@ -22,7 +22,6 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi
|
||||
if (entity->IsPlayer() && !this->m_DontApplyImmune) {
|
||||
const float immunityTime = Game::zoneManager->GetWorldConfig()->globalImmunityTime;
|
||||
destroyableComponent->SetDamageCooldownTimer(immunityTime);
|
||||
LOG_DEBUG("Target targetEntity %llu took damage, setting damage cooldown timer to %f s", branch.target, immunityTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,11 +187,7 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
|
||||
return;
|
||||
}
|
||||
|
||||
const float immunityTime = Game::zoneManager->GetWorldConfig()->globalImmunityTime;
|
||||
LOG_DEBUG("Damage cooldown timer currently %f s", destroyableComponent->GetDamageCooldownTimer());
|
||||
|
||||
const bool isImmune = (destroyableComponent->IsImmune()) || (destroyableComponent->IsCooldownImmune());
|
||||
|
||||
const bool isImmune = destroyableComponent->IsImmune() || destroyableComponent->IsCooldownImmune();
|
||||
bitStream->Write(isImmune);
|
||||
|
||||
if (isImmune) {
|
||||
@@ -219,8 +214,7 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
|
||||
|
||||
//Handle player damage cooldown
|
||||
if (isSuccess && targetEntity->IsPlayer() && !this->m_DontApplyImmune) {
|
||||
destroyableComponent->SetDamageCooldownTimer(immunityTime);
|
||||
LOG_DEBUG("Target targetEntity %llu took damage, setting damage cooldown timer to %f s", branch.target, immunityTime);
|
||||
destroyableComponent->SetDamageCooldownTimer(Game::zoneManager->GetWorldConfig()->globalImmunityTime);
|
||||
}
|
||||
|
||||
eBasicAttackSuccessTypes successState = eBasicAttackSuccessTypes::FAILIMMUNE;
|
||||
|
||||
@@ -368,11 +368,11 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID
|
||||
|
||||
if (!type.empty()) {
|
||||
typeQuery.bind(1, typeString.c_str());
|
||||
typeQuery.bind(2, (int)effectId);
|
||||
typeQuery.bind(2, static_cast<int>(effectId));
|
||||
|
||||
result = typeQuery.execQuery();
|
||||
} else {
|
||||
idQuery.bind(1, (int)effectId);
|
||||
idQuery.bind(1, static_cast<int>(effectId));
|
||||
|
||||
result = idQuery.execQuery();
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "DestroyableComponent.h"
|
||||
#include "EchoSyncSkill.h"
|
||||
#include "PhantomPhysicsComponent.h"
|
||||
#include "RebuildComponent.h"
|
||||
#include "QuickBuildComponent.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
#include "TeamManager.h"
|
||||
#include "eConnectionType.h"
|
||||
@@ -249,7 +249,7 @@ bool BehaviorContext::CalculateUpdate(const float deltaTime) {
|
||||
entry.behavior->SyncCalculation(this, bitStream, entry.branchContext);
|
||||
|
||||
if (!clientInitalized) {
|
||||
echo.sBitStream.assign((char*)bitStream->GetData(), bitStream->GetNumberOfBytesUsed());
|
||||
echo.sBitStream.assign(reinterpret_cast<char*>(bitStream->GetData()), bitStream->GetNumberOfBytesUsed());
|
||||
|
||||
// Write message
|
||||
RakNet::BitStream message;
|
||||
@@ -412,8 +412,8 @@ bool BehaviorContext::CheckTargetingRequirements(const Entity* target) const {
|
||||
if (!target) return false;
|
||||
|
||||
// ignore quickbuilds that aren't completed
|
||||
auto* targetQuickbuildComponent = target->GetComponent<RebuildComponent>();
|
||||
if (targetQuickbuildComponent && targetQuickbuildComponent->GetState() != eRebuildState::COMPLETED) return false;
|
||||
auto* targetQuickbuildComponent = target->GetComponent<QuickBuildComponent>();
|
||||
if (targetQuickbuildComponent && targetQuickbuildComponent->GetState() != eQuickBuildState::COMPLETED) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -38,10 +38,12 @@ void JetPackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bit
|
||||
}
|
||||
|
||||
void JetPackBehavior::Load() {
|
||||
this->m_WarningEffectID = GetInt("warning_effect_id");
|
||||
this->m_Airspeed = GetFloat("airspeed");
|
||||
this->m_MaxAirspeed = GetFloat("max_airspeed");
|
||||
this->m_VerticalVelocity = GetFloat("vertical_velocity");
|
||||
this->m_EnableHover = GetBoolean("enable_hover");
|
||||
this->m_BypassChecks = GetBoolean("bypass_checks", true);
|
||||
this->m_WarningEffectID = GetInt("warning_effect_id", -1);
|
||||
this->m_Airspeed = GetFloat("airspeed", 10);
|
||||
this->m_MaxAirspeed = GetFloat("max_airspeed", 15);
|
||||
this->m_VerticalVelocity = GetFloat("vertical_velocity", 1);
|
||||
this->m_EnableHover = GetBoolean("enable_hover", false);
|
||||
|
||||
// TODO: Implement proper jetpack checks, so we can set this default to false
|
||||
this->m_BypassChecks = GetBoolean("bypass_checks", true);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "Game.h"
|
||||
#include "Logger.h"
|
||||
#include "DestroyableComponent.h"
|
||||
#include "RebuildComponent.h"
|
||||
#include "QuickBuildComponent.h"
|
||||
#include "Entity.h"
|
||||
#include "EntityInfo.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
@@ -53,10 +53,10 @@ void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea
|
||||
entity->SetOwnerOverride(context->originator);
|
||||
|
||||
// Unset the flag to reposition the player, this makes it harder to glitch out of the map
|
||||
auto* rebuildComponent = entity->GetComponent<RebuildComponent>();
|
||||
auto* quickBuildComponent = entity->GetComponent<QuickBuildComponent>();
|
||||
|
||||
if (rebuildComponent != nullptr) {
|
||||
rebuildComponent->SetRepositionPlayer(false);
|
||||
if (quickBuildComponent != nullptr) {
|
||||
quickBuildComponent->SetRepositionPlayer(false);
|
||||
}
|
||||
|
||||
Game::entityManager->ConstructEntity(entity);
|
||||
|
||||
@@ -42,7 +42,7 @@ void SwitchMultipleBehavior::Load() {
|
||||
"(select bP2.value FROM BehaviorParameter bP2 WHERE bP2.behaviorID = ?1 AND bP2.parameterID LIKE 'value %' "
|
||||
"AND replace(bP1.parameterID, 'behavior ', '') = replace(bP2.parameterID, 'value ', '')) as value "
|
||||
"FROM BehaviorParameter bP1 WHERE bP1.behaviorID = ?1 AND bP1.parameterID LIKE 'behavior %';");
|
||||
query.bind(1, (int)this->m_behaviorId);
|
||||
query.bind(1, static_cast<int>(this->m_behaviorId));
|
||||
|
||||
auto result = query.execQuery();
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "BehaviorContext.h"
|
||||
#include "BaseCombatAIComponent.h"
|
||||
#include "EntityManager.h"
|
||||
#include "RebuildComponent.h"
|
||||
#include "QuickBuildComponent.h"
|
||||
#include "DestroyableComponent.h"
|
||||
|
||||
#include <vector>
|
||||
@@ -104,7 +104,7 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
|
||||
|
||||
const auto casterPosition = self->GetPosition();
|
||||
|
||||
auto reference = self->GetPosition(); //+ m_offset;
|
||||
auto reference = self->GetPosition() + m_offset;
|
||||
|
||||
targets.clear();
|
||||
|
||||
@@ -114,46 +114,34 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
|
||||
context->FilterTargets(validTargets, this->m_ignoreFactionList, this->m_includeFactionList, this->m_targetSelf, this->m_targetEnemy, this->m_targetFriend, this->m_targetTeam);
|
||||
|
||||
for (auto validTarget : validTargets) {
|
||||
if (targets.size() >= this->m_maxTargets) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (std::find(targets.begin(), targets.end(), validTarget) != targets.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (targets.size() >= this->m_maxTargets) break;
|
||||
if (std::find(targets.begin(), targets.end(), validTarget) != targets.end()) continue;
|
||||
if (validTarget->GetIsDead()) continue;
|
||||
|
||||
const auto otherPosition = validTarget->GetPosition();
|
||||
const auto targetPos = validTarget->GetPosition();
|
||||
|
||||
const auto heightDifference = std::abs(otherPosition.y - casterPosition.y);
|
||||
|
||||
/*if (otherPosition.y > reference.y && heightDifference > this->m_upperBound || otherPosition.y < reference.y && heightDifference > this->m_lowerBound)
|
||||
{
|
||||
// make sure we aren't too high or low in comparison to the targer
|
||||
const auto heightDifference = std::abs(reference.y - targetPos.y);
|
||||
if (targetPos.y > reference.y && heightDifference > this->m_upperBound || targetPos.y < reference.y && heightDifference > this->m_lowerBound)
|
||||
continue;
|
||||
}*/
|
||||
|
||||
const auto forward = self->GetRotation().GetForwardVector();
|
||||
|
||||
// forward is a normalized vector of where the caster is facing.
|
||||
// otherPosition is the position of the target.
|
||||
// targetPos is the position of the target.
|
||||
// reference is the position of the caster.
|
||||
// If we cast a ray forward from the caster, does it come within m_farWidth of the target?
|
||||
|
||||
const auto distance = Vector3::Distance(reference, otherPosition);
|
||||
const auto distance = Vector3::Distance(reference, targetPos);
|
||||
|
||||
if (m_method == 2) {
|
||||
NiPoint3 rayPoint = casterPosition + forward * distance;
|
||||
|
||||
if (m_farWidth > 0 && Vector3::DistanceSquared(rayPoint, otherPosition) > this->m_farWidth * this->m_farWidth) {
|
||||
if (m_farWidth > 0 && Vector3::DistanceSquared(rayPoint, targetPos) > this->m_farWidth * this->m_farWidth)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
auto normalized = (reference - otherPosition) / distance;
|
||||
|
||||
auto normalized = (reference - targetPos) / distance;
|
||||
const float degreeAngle = std::abs(Vector3::Angle(forward, normalized) * (180 / 3.14) - 180);
|
||||
|
||||
if (distance >= this->m_minRange && this->m_maxRange >= distance && degreeAngle <= 2 * this->m_angle) {
|
||||
targets.push_back(validTarget);
|
||||
}
|
||||
@@ -167,33 +155,26 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
|
||||
});
|
||||
|
||||
const auto hit = !targets.empty();
|
||||
|
||||
bitStream->Write(hit);
|
||||
|
||||
if (this->m_checkEnv) {
|
||||
const auto blocked = false; // TODO
|
||||
|
||||
bitStream->Write(blocked);
|
||||
}
|
||||
|
||||
if (hit) {
|
||||
if (combatAi != nullptr) {
|
||||
combatAi->LookAt(targets[0]->GetPosition());
|
||||
}
|
||||
if (combatAi) combatAi->LookAt(targets[0]->GetPosition());
|
||||
|
||||
context->foundTarget = true; // We want to continue with this behavior
|
||||
|
||||
const auto count = static_cast<uint32_t>(targets.size());
|
||||
|
||||
bitStream->Write(count);
|
||||
|
||||
for (auto* target : targets) {
|
||||
bitStream->Write(target->GetObjectID());
|
||||
}
|
||||
|
||||
for (auto* target : targets) {
|
||||
branch.target = target->GetObjectID();
|
||||
|
||||
this->m_action->Calculate(context, bitStream, branch);
|
||||
}
|
||||
} else {
|
||||
@@ -214,8 +195,8 @@ void TacArcBehavior::Load() {
|
||||
GetFloat("offset_z", 0.0f)
|
||||
);
|
||||
this->m_method = GetInt("method", 1);
|
||||
this->m_upperBound = GetFloat("upper_bound", 4.4f);
|
||||
this->m_lowerBound = GetFloat("lower_bound", 0.4f);
|
||||
this->m_upperBound = std::abs(GetFloat("upper_bound", 4.4f));
|
||||
this->m_lowerBound = std::abs(GetFloat("lower_bound", 0.4f));
|
||||
this->m_usePickedTarget = GetBoolean("use_picked_target", false);
|
||||
this->m_useTargetPostion = GetBoolean("use_target_position", false);
|
||||
this->m_checkEnv = GetBoolean("check_env", false);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "ScriptedActivityComponent.h"
|
||||
#include "ActivityComponent.h"
|
||||
#include "GameMessages.h"
|
||||
#include "CDClientManager.h"
|
||||
#include "MissionComponent.h"
|
||||
@@ -29,10 +29,11 @@
|
||||
#include "CDActivitiesTable.h"
|
||||
#include "LeaderboardManager.h"
|
||||
|
||||
ScriptedActivityComponent::ScriptedActivityComponent(Entity* parent, int activityID) : Component(parent) {
|
||||
m_ActivityID = activityID;
|
||||
ActivityComponent::ActivityComponent(Entity* parent, int32_t activityID) : Component(parent) {
|
||||
if (activityID > 0) m_ActivityID = activityID;
|
||||
else m_ActivityID = parent->GetVar<int32_t>(u"activityID");
|
||||
CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
|
||||
std::vector<CDActivities> activities = activitiesTable->Query([=](CDActivities entry) {return (entry.ActivityID == m_ActivityID); });
|
||||
std::vector<CDActivities> activities = activitiesTable->Query([this](CDActivities entry) {return (entry.ActivityID == m_ActivityID); });
|
||||
|
||||
for (CDActivities activity : activities) {
|
||||
m_ActivityInfo = activity;
|
||||
@@ -40,15 +41,10 @@ ScriptedActivityComponent::ScriptedActivityComponent(Entity* parent, int activit
|
||||
m_ActivityInfo.minTeamSize = 1;
|
||||
m_ActivityInfo.minTeams = 1;
|
||||
}
|
||||
|
||||
const auto& transferOverride = parent->GetVar<std::u16string>(u"transferZoneID");
|
||||
if (!transferOverride.empty()) {
|
||||
m_ActivityInfo.instanceMapID = std::stoi(GeneralUtils::UTF16ToWTF8(transferOverride));
|
||||
|
||||
// TODO: LU devs made me do it (for some reason cannon cove instancer is marked to go to GF survival)
|
||||
// NOTE: 1301 is GF survival
|
||||
if (m_ActivityInfo.instanceMapID == 1301) {
|
||||
m_ActivityInfo.instanceMapID = 1302;
|
||||
if (m_ActivityInfo.instanceMapID == -1) {
|
||||
const auto& transferOverride = parent->GetVarAsString(u"transferZoneID");
|
||||
if (!transferOverride.empty()) {
|
||||
GeneralUtils::TryParse(transferOverride, m_ActivityInfo.instanceMapID);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,30 +75,28 @@ ScriptedActivityComponent::ScriptedActivityComponent(Entity* parent, int activit
|
||||
}
|
||||
}
|
||||
|
||||
ScriptedActivityComponent::~ScriptedActivityComponent()
|
||||
= default;
|
||||
|
||||
void ScriptedActivityComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
outBitStream->Write(true);
|
||||
outBitStream->Write<uint32_t>(m_ActivityPlayers.size());
|
||||
|
||||
if (!m_ActivityPlayers.empty()) {
|
||||
for (const auto& activityPlayer : m_ActivityPlayers) {
|
||||
|
||||
outBitStream->Write<LWOOBJID>(activityPlayer->playerID);
|
||||
for (const auto& activityValue : activityPlayer->values) {
|
||||
outBitStream->Write<float_t>(activityValue);
|
||||
void ActivityComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
outBitStream->Write(m_DirtyActivityInfo);
|
||||
if (m_DirtyActivityInfo) {
|
||||
outBitStream->Write<uint32_t>(m_ActivityPlayers.size());
|
||||
if (!m_ActivityPlayers.empty()) {
|
||||
for (const auto& activityPlayer : m_ActivityPlayers) {
|
||||
outBitStream->Write<LWOOBJID>(activityPlayer->playerID);
|
||||
for (const auto& activityValue : activityPlayer->values) {
|
||||
outBitStream->Write<float_t>(activityValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!bIsInitialUpdate) m_DirtyActivityInfo = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptedActivityComponent::ReloadConfig() {
|
||||
void ActivityComponent::ReloadConfig() {
|
||||
CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
|
||||
std::vector<CDActivities> activities = activitiesTable->Query([=](CDActivities entry) {return (entry.ActivityID == m_ActivityID); });
|
||||
std::vector<CDActivities> activities = activitiesTable->Query([this](CDActivities entry) {return (entry.ActivityID == m_ActivityID); });
|
||||
for (auto activity : activities) {
|
||||
auto mapID = m_ActivityInfo.instanceMapID;
|
||||
if ((mapID == 1203 || mapID == 1261 || mapID == 1303 || mapID == 1403) && Game::config->GetValue("solo_racing") == "1") {
|
||||
if (static_cast<Leaderboard::Type>(activity.leaderboardType) == Leaderboard::Type::Racing && Game::config->GetValue("solo_racing") == "1") {
|
||||
m_ActivityInfo.minTeamSize = 1;
|
||||
m_ActivityInfo.minTeams = 1;
|
||||
} else {
|
||||
@@ -112,11 +106,7 @@ void ScriptedActivityComponent::ReloadConfig() {
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptedActivityComponent::HandleMessageBoxResponse(Entity* player, const std::string& id) {
|
||||
if (m_ActivityInfo.ActivityID == 103) {
|
||||
return;
|
||||
}
|
||||
|
||||
void ActivityComponent::HandleMessageBoxResponse(Entity* player, const std::string& id) {
|
||||
if (id == "LobbyExit") {
|
||||
PlayerLeave(player->GetObjectID());
|
||||
} else if (id == "PlayButton") {
|
||||
@@ -124,11 +114,8 @@ void ScriptedActivityComponent::HandleMessageBoxResponse(Entity* player, const s
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptedActivityComponent::PlayerJoin(Entity* player) {
|
||||
if (m_ActivityInfo.ActivityID == 103 || PlayerIsInQueue(player) || !IsValidActivity(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
void ActivityComponent::PlayerJoin(Entity* player) {
|
||||
if (PlayerIsInQueue(player)) return;
|
||||
// If we have a lobby, queue the player and allow others to join, otherwise spin up an instance on the spot
|
||||
if (HasLobby()) {
|
||||
PlayerJoinLobby(player);
|
||||
@@ -136,11 +123,9 @@ void ScriptedActivityComponent::PlayerJoin(Entity* player) {
|
||||
auto* instance = NewInstance();
|
||||
instance->AddParticipant(player);
|
||||
}
|
||||
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
|
||||
void ScriptedActivityComponent::PlayerJoinLobby(Entity* player) {
|
||||
void ActivityComponent::PlayerJoinLobby(Entity* player) {
|
||||
if (!m_Parent->HasComponent(eReplicaComponentType::QUICK_BUILD))
|
||||
GameMessages::SendMatchResponse(player, player->GetSystemAddress(), 0); // tell the client they joined a lobby
|
||||
LobbyPlayer* newLobbyPlayer = new LobbyPlayer();
|
||||
@@ -189,7 +174,7 @@ void ScriptedActivityComponent::PlayerJoinLobby(Entity* player) {
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptedActivityComponent::PlayerLeave(LWOOBJID playerID) {
|
||||
void ActivityComponent::PlayerLeave(LWOOBJID playerID) {
|
||||
|
||||
// Removes the player from a lobby and notifies the others, not applicable for non-lobby instances
|
||||
for (Lobby* lobby : m_Queue) {
|
||||
@@ -214,7 +199,7 @@ void ScriptedActivityComponent::PlayerLeave(LWOOBJID playerID) {
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptedActivityComponent::Update(float deltaTime) {
|
||||
void ActivityComponent::Update(float deltaTime) {
|
||||
std::vector<Lobby*> lobbiesToRemove{};
|
||||
// Ticks all the lobbies, not applicable for non-instance activities
|
||||
for (Lobby* lobby : m_Queue) {
|
||||
@@ -287,7 +272,7 @@ void ScriptedActivityComponent::Update(float deltaTime) {
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptedActivityComponent::RemoveLobby(Lobby* lobby) {
|
||||
void ActivityComponent::RemoveLobby(Lobby* lobby) {
|
||||
for (int i = 0; i < m_Queue.size(); ++i) {
|
||||
if (m_Queue[i] == lobby) {
|
||||
m_Queue.erase(m_Queue.begin() + i);
|
||||
@@ -296,29 +281,12 @@ void ScriptedActivityComponent::RemoveLobby(Lobby* lobby) {
|
||||
}
|
||||
}
|
||||
|
||||
bool ScriptedActivityComponent::HasLobby() const {
|
||||
bool ActivityComponent::HasLobby() const {
|
||||
// If the player is not in the world he has to be, create a lobby for the transfer
|
||||
return m_ActivityInfo.instanceMapID != UINT_MAX && m_ActivityInfo.instanceMapID != Game::server->GetZoneID();
|
||||
}
|
||||
|
||||
bool ScriptedActivityComponent::IsValidActivity(Entity* player) {
|
||||
// Makes it so that scripted activities with an unimplemented map cannot be joined
|
||||
/*if (player->GetGMLevel() < eGameMasterLevel::DEVELOPER && (m_ActivityInfo.instanceMapID == 1302 || m_ActivityInfo.instanceMapID == 1301)) {
|
||||
if (m_Parent->GetLOT() == 4860) {
|
||||
auto* missionComponent = player->GetComponent<MissionComponent>();
|
||||
missionComponent->CompleteMission(229);
|
||||
}
|
||||
|
||||
ChatPackets::SendSystemMessage(player->GetSystemAddress(), u"Sorry, this activity is not ready.");
|
||||
static_cast<Player*>(player)->SendToZone(Game::zoneManager->GetZone()->GetWorldID()); // Gets them out of this stuck state
|
||||
|
||||
return false;
|
||||
}*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ScriptedActivityComponent::PlayerIsInQueue(Entity* player) {
|
||||
bool ActivityComponent::PlayerIsInQueue(Entity* player) {
|
||||
for (Lobby* lobby : m_Queue) {
|
||||
for (LobbyPlayer* lobbyPlayer : lobby->players) {
|
||||
if (player->GetObjectID() == lobbyPlayer->entityID) return true;
|
||||
@@ -328,7 +296,7 @@ bool ScriptedActivityComponent::PlayerIsInQueue(Entity* player) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScriptedActivityComponent::IsPlayedBy(Entity* player) const {
|
||||
bool ActivityComponent::IsPlayedBy(Entity* player) const {
|
||||
for (const auto* instance : this->m_Instances) {
|
||||
for (const auto* instancePlayer : instance->GetParticipants()) {
|
||||
if (instancePlayer != nullptr && instancePlayer->GetObjectID() == player->GetObjectID())
|
||||
@@ -339,7 +307,7 @@ bool ScriptedActivityComponent::IsPlayedBy(Entity* player) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScriptedActivityComponent::IsPlayedBy(LWOOBJID playerID) const {
|
||||
bool ActivityComponent::IsPlayedBy(LWOOBJID playerID) const {
|
||||
for (const auto* instance : this->m_Instances) {
|
||||
for (const auto* instancePlayer : instance->GetParticipants()) {
|
||||
if (instancePlayer != nullptr && instancePlayer->GetObjectID() == playerID)
|
||||
@@ -350,7 +318,7 @@ bool ScriptedActivityComponent::IsPlayedBy(LWOOBJID playerID) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScriptedActivityComponent::TakeCost(Entity* player) const {
|
||||
bool ActivityComponent::TakeCost(Entity* player) const {
|
||||
if (m_ActivityInfo.optionalCostLOT <= 0 || m_ActivityInfo.optionalCostCount <= 0)
|
||||
return true;
|
||||
|
||||
@@ -366,7 +334,7 @@ bool ScriptedActivityComponent::TakeCost(Entity* player) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ScriptedActivityComponent::PlayerReady(Entity* player, bool bReady) {
|
||||
void ActivityComponent::PlayerReady(Entity* player, bool bReady) {
|
||||
for (Lobby* lobby : m_Queue) {
|
||||
for (LobbyPlayer* lobbyPlayer : lobby->players) {
|
||||
if (lobbyPlayer->entityID == player->GetObjectID()) {
|
||||
@@ -389,13 +357,13 @@ void ScriptedActivityComponent::PlayerReady(Entity* player, bool bReady) {
|
||||
}
|
||||
}
|
||||
|
||||
ActivityInstance* ScriptedActivityComponent::NewInstance() {
|
||||
ActivityInstance* ActivityComponent::NewInstance() {
|
||||
auto* instance = new ActivityInstance(m_Parent, m_ActivityInfo);
|
||||
m_Instances.push_back(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void ScriptedActivityComponent::LoadPlayersIntoInstance(ActivityInstance* instance, const std::vector<LobbyPlayer*>& lobby) const {
|
||||
void ActivityComponent::LoadPlayersIntoInstance(ActivityInstance* instance, const std::vector<LobbyPlayer*>& lobby) const {
|
||||
for (LobbyPlayer* player : lobby) {
|
||||
auto* entity = player->GetEntity();
|
||||
if (entity == nullptr || !TakeCost(entity)) {
|
||||
@@ -406,11 +374,11 @@ void ScriptedActivityComponent::LoadPlayersIntoInstance(ActivityInstance* instan
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<ActivityInstance*>& ScriptedActivityComponent::GetInstances() const {
|
||||
const std::vector<ActivityInstance*>& ActivityComponent::GetInstances() const {
|
||||
return m_Instances;
|
||||
}
|
||||
|
||||
ActivityInstance* ScriptedActivityComponent::GetInstance(const LWOOBJID playerID) {
|
||||
ActivityInstance* ActivityComponent::GetInstance(const LWOOBJID playerID) {
|
||||
for (const auto* instance : GetInstances()) {
|
||||
for (const auto* participant : instance->GetParticipants()) {
|
||||
if (participant->GetObjectID() == playerID)
|
||||
@@ -421,14 +389,14 @@ ActivityInstance* ScriptedActivityComponent::GetInstance(const LWOOBJID playerID
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ScriptedActivityComponent::ClearInstances() {
|
||||
void ActivityComponent::ClearInstances() {
|
||||
for (ActivityInstance* instance : m_Instances) {
|
||||
delete instance;
|
||||
}
|
||||
m_Instances.clear();
|
||||
}
|
||||
|
||||
ActivityPlayer* ScriptedActivityComponent::GetActivityPlayerData(LWOOBJID playerID) {
|
||||
ActivityPlayer* ActivityComponent::GetActivityPlayerData(LWOOBJID playerID) {
|
||||
for (auto* activityData : m_ActivityPlayers) {
|
||||
if (activityData->playerID == playerID) {
|
||||
return activityData;
|
||||
@@ -438,13 +406,14 @@ ActivityPlayer* ScriptedActivityComponent::GetActivityPlayerData(LWOOBJID player
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ScriptedActivityComponent::RemoveActivityPlayerData(LWOOBJID playerID) {
|
||||
void ActivityComponent::RemoveActivityPlayerData(LWOOBJID playerID) {
|
||||
for (size_t i = 0; i < m_ActivityPlayers.size(); i++) {
|
||||
if (m_ActivityPlayers[i]->playerID == playerID) {
|
||||
delete m_ActivityPlayers[i];
|
||||
m_ActivityPlayers[i] = nullptr;
|
||||
|
||||
m_ActivityPlayers.erase(m_ActivityPlayers.begin() + i);
|
||||
m_DirtyActivityInfo = true;
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
|
||||
return;
|
||||
@@ -452,38 +421,39 @@ void ScriptedActivityComponent::RemoveActivityPlayerData(LWOOBJID playerID) {
|
||||
}
|
||||
}
|
||||
|
||||
ActivityPlayer* ScriptedActivityComponent::AddActivityPlayerData(LWOOBJID playerID) {
|
||||
ActivityPlayer* ActivityComponent::AddActivityPlayerData(LWOOBJID playerID) {
|
||||
auto* data = GetActivityPlayerData(playerID);
|
||||
if (data != nullptr)
|
||||
return data;
|
||||
|
||||
m_ActivityPlayers.push_back(new ActivityPlayer{ playerID, {} });
|
||||
m_DirtyActivityInfo = true;
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
|
||||
return GetActivityPlayerData(playerID);
|
||||
}
|
||||
|
||||
float_t ScriptedActivityComponent::GetActivityValue(LWOOBJID playerID, uint32_t index) {
|
||||
float_t ActivityComponent::GetActivityValue(LWOOBJID playerID, uint32_t index) {
|
||||
auto value = -1.0f;
|
||||
|
||||
auto* data = GetActivityPlayerData(playerID);
|
||||
if (data != nullptr) {
|
||||
value = data->values[std::min(index, (uint32_t)9)];
|
||||
value = data->values[std::min(index, static_cast<uint32_t>(9))];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
void ScriptedActivityComponent::SetActivityValue(LWOOBJID playerID, uint32_t index, float_t value) {
|
||||
void ActivityComponent::SetActivityValue(LWOOBJID playerID, uint32_t index, float_t value) {
|
||||
auto* data = AddActivityPlayerData(playerID);
|
||||
if (data != nullptr) {
|
||||
data->values[std::min(index, (uint32_t)9)] = value;
|
||||
data->values[std::min(index, static_cast<uint32_t>(9))] = value;
|
||||
}
|
||||
|
||||
m_DirtyActivityInfo = true;
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
|
||||
void ScriptedActivityComponent::PlayerRemove(LWOOBJID playerID) {
|
||||
void ActivityComponent::PlayerRemove(LWOOBJID playerID) {
|
||||
for (auto* instance : GetInstances()) {
|
||||
auto participants = instance->GetParticipants();
|
||||
for (const auto* participant : participants) {
|
||||
@@ -562,7 +532,7 @@ void ActivityInstance::RewardParticipant(Entity* participant) {
|
||||
|
||||
// First, get the activity data
|
||||
auto* activityRewardsTable = CDClientManager::Instance().GetTable<CDActivityRewardsTable>();
|
||||
std::vector<CDActivityRewards> activityRewards = activityRewardsTable->Query([=](CDActivityRewards entry) { return (entry.objectTemplate == m_ActivityInfo.ActivityID); });
|
||||
std::vector<CDActivityRewards> activityRewards = activityRewardsTable->Query([this](CDActivityRewards entry) { return (entry.objectTemplate == m_ActivityInfo.ActivityID); });
|
||||
|
||||
if (!activityRewards.empty()) {
|
||||
uint32_t minCoins = 0;
|
||||
371
dGame/dComponents/ActivityComponent.h
Normal file
371
dGame/dComponents/ActivityComponent.h
Normal file
@@ -0,0 +1,371 @@
|
||||
#ifndef ACTIVITYCOMPONENT_H
|
||||
#define ACTIVITYCOMPONENT_H
|
||||
|
||||
#include "CDClientManager.h"
|
||||
#include "BitStream.h"
|
||||
#include "Entity.h"
|
||||
#include "Component.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
|
||||
#include "CDActivitiesTable.h"
|
||||
|
||||
/**
|
||||
* Represents an instance of an activity, having participants and score
|
||||
*/
|
||||
class ActivityInstance {
|
||||
public:
|
||||
ActivityInstance(Entity* parent, CDActivities activityInfo) { m_Parent = parent; m_ActivityInfo = activityInfo; };
|
||||
//~ActivityInstance();
|
||||
|
||||
/**
|
||||
* Adds an entity to this activity
|
||||
* @param participant the entity to add
|
||||
*/
|
||||
void AddParticipant(Entity* participant);
|
||||
|
||||
/**
|
||||
* Removes all the participants from this activity
|
||||
*/
|
||||
void ClearParticipants() { m_Participants.clear(); };
|
||||
|
||||
/**
|
||||
* Starts the instance world for this activity and sends all participants there
|
||||
*/
|
||||
void StartZone();
|
||||
|
||||
/**
|
||||
* Gives the rewards for completing this activity to some participant
|
||||
* @param participant the participant to give rewards to
|
||||
*/
|
||||
void RewardParticipant(Entity* participant);
|
||||
|
||||
/**
|
||||
* Removes a participant from this activity
|
||||
* @param participant the participant to remove
|
||||
*/
|
||||
void RemoveParticipant(const Entity* participant);
|
||||
|
||||
/**
|
||||
* Returns all the participants of this activity
|
||||
* @return all the participants of this activity
|
||||
*/
|
||||
std::vector<Entity*> GetParticipants() const;
|
||||
|
||||
/**
|
||||
* Currently unused
|
||||
*/
|
||||
uint32_t GetScore() const;
|
||||
|
||||
/**
|
||||
* Currently unused
|
||||
*/
|
||||
void SetScore(uint32_t score);
|
||||
private:
|
||||
|
||||
/**
|
||||
* Currently unused
|
||||
*/
|
||||
uint32_t score = 0;
|
||||
|
||||
/**
|
||||
* The instance ID of this activity
|
||||
*/
|
||||
uint32_t m_NextZoneCloneID = 0;
|
||||
|
||||
/**
|
||||
* The database information for this activity
|
||||
*/
|
||||
CDActivities m_ActivityInfo;
|
||||
|
||||
/**
|
||||
* The entity that owns this activity (the entity that has the ScriptedActivityComponent)
|
||||
*/
|
||||
Entity* m_Parent;
|
||||
|
||||
/**
|
||||
* All the participants of this activity
|
||||
*/
|
||||
std::vector<LWOOBJID> m_Participants;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents an entity in a lobby
|
||||
*/
|
||||
struct LobbyPlayer {
|
||||
|
||||
/**
|
||||
* The ID of the entity that is in the lobby
|
||||
*/
|
||||
LWOOBJID entityID;
|
||||
|
||||
/**
|
||||
* Whether or not the entity is ready
|
||||
*/
|
||||
bool ready = false;
|
||||
|
||||
/**
|
||||
* Returns the entity that is in the lobby
|
||||
* @return the entity that is in the lobby
|
||||
*/
|
||||
Entity* GetEntity() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a lobby of players with a timer until it should start the activity
|
||||
*/
|
||||
struct Lobby {
|
||||
|
||||
/**
|
||||
* The lobby of players
|
||||
*/
|
||||
std::vector<LobbyPlayer*> players;
|
||||
|
||||
/**
|
||||
* The timer that determines when the activity should start
|
||||
*/
|
||||
float timer;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents the score for the player in an activity, one index might represent score, another one time, etc.
|
||||
*/
|
||||
struct ActivityPlayer {
|
||||
|
||||
/**
|
||||
* The entity that the score is tracked for
|
||||
*/
|
||||
LWOOBJID playerID;
|
||||
|
||||
/**
|
||||
* The list of score for this entity
|
||||
*/
|
||||
float values[10];
|
||||
};
|
||||
|
||||
/**
|
||||
* Welcome to the absolute behemoth that is the scripted activity component. I have now clue how this was managed in
|
||||
* live but I figure somewhat similarly and it's terrible. In a nutshell, this components handles any activity that
|
||||
* can be done in the game from quick builds to boss fights to races. On top of that, this component handles instancing
|
||||
* and lobbying.
|
||||
*/
|
||||
class ActivityComponent : public Component {
|
||||
public:
|
||||
ActivityComponent(Entity* parent, int32_t activityID);
|
||||
|
||||
void Update(float deltaTime) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
|
||||
/**
|
||||
* Makes some entity join the minigame, if it's a lobbied one, the entity will be placed in the lobby
|
||||
* @param player the entity to join the game
|
||||
*/
|
||||
void PlayerJoin(Entity* player);
|
||||
|
||||
/**
|
||||
* Makes an entity join the lobby for this minigame, if it exists
|
||||
* @param player the entity to join
|
||||
*/
|
||||
void PlayerJoinLobby(Entity* player);
|
||||
|
||||
/**
|
||||
* Makes the player leave the lobby
|
||||
* @param playerID the entity to leave the lobby
|
||||
*/
|
||||
void PlayerLeave(LWOOBJID playerID);
|
||||
|
||||
/**
|
||||
* Removes the entity from the minigame (and its score)
|
||||
* @param playerID the entity to remove from the minigame
|
||||
*/
|
||||
void PlayerRemove(LWOOBJID playerID);
|
||||
|
||||
/**
|
||||
* Adds all the players to an instance of some activity
|
||||
* @param instance the instance to load the players into
|
||||
* @param lobby the players to load into the instance
|
||||
*/
|
||||
void LoadPlayersIntoInstance(ActivityInstance* instance, const std::vector<LobbyPlayer*>& lobby) const;
|
||||
|
||||
/**
|
||||
* Removes a lobby from the activity manager
|
||||
* @param lobby the lobby to remove
|
||||
*/
|
||||
void RemoveLobby(Lobby* lobby);
|
||||
|
||||
/**
|
||||
* Marks a player as (un)ready in a lobby
|
||||
* @param player the entity to mark
|
||||
* @param bReady true if the entity is ready, false otherwise
|
||||
*/
|
||||
void PlayerReady(Entity* player, bool bReady);
|
||||
|
||||
/**
|
||||
* Returns the ID of this activity
|
||||
* @return the ID of this activity
|
||||
*/
|
||||
int GetActivityID() { return m_ActivityInfo.ActivityID; }
|
||||
|
||||
/**
|
||||
* Returns if this activity has a lobby, e.g. if it needs to instance players to some other map
|
||||
* @return true if this activity has a lobby, false otherwise
|
||||
*/
|
||||
bool HasLobby() const;
|
||||
|
||||
/**
|
||||
* Checks if a player is currently waiting in a lobby
|
||||
* @param player the entity to check for
|
||||
* @return true if the entity is waiting in a lobby, false otherwise
|
||||
*/
|
||||
bool PlayerIsInQueue(Entity* player);
|
||||
|
||||
/**
|
||||
* Checks if an entity is currently playing this activity
|
||||
* @param player the entity to check
|
||||
* @return true if the entity is playing this lobby, false otherwise
|
||||
*/
|
||||
bool IsPlayedBy(Entity* player) const;
|
||||
|
||||
/**
|
||||
* Checks if an entity is currently playing this activity
|
||||
* @param playerID the entity to check
|
||||
* @return true if the entity is playing this lobby, false otherwise
|
||||
*/
|
||||
bool IsPlayedBy(LWOOBJID playerID) const;
|
||||
|
||||
/**
|
||||
* Removes the cost of the activity (e.g. green imaginate) for the entity that plays this activity
|
||||
* @param player the entity to take cost for
|
||||
* @return true if the cost was successfully deducted, false otherwise
|
||||
*/
|
||||
bool TakeCost(Entity* player) const;
|
||||
|
||||
/**
|
||||
* Handles any response from a player clicking on a lobby / instance menu
|
||||
* @param player the entity that clicked
|
||||
* @param id the message that was passed
|
||||
*/
|
||||
void HandleMessageBoxResponse(Entity* player, const std::string& id);
|
||||
|
||||
/**
|
||||
* Creates a new instance for this activity
|
||||
* @return a new instance for this activity
|
||||
*/
|
||||
ActivityInstance* NewInstance();
|
||||
|
||||
/**
|
||||
* Returns all the currently active instances of this activity
|
||||
* @return all the currently active instances of this activity
|
||||
*/
|
||||
const std::vector<ActivityInstance*>& GetInstances() const;
|
||||
|
||||
/**
|
||||
* Returns the instance that some entity is currently playing in
|
||||
* @param playerID the entity to check for
|
||||
* @return if any, the instance that the entity is currently in
|
||||
*/
|
||||
ActivityInstance* GetInstance(const LWOOBJID playerID);
|
||||
|
||||
/**
|
||||
* @brief Reloads the config settings for this component
|
||||
*
|
||||
*/
|
||||
void ReloadConfig();
|
||||
|
||||
/**
|
||||
* Removes all the instances
|
||||
*/
|
||||
void ClearInstances();
|
||||
|
||||
/**
|
||||
* Returns all the score for the players that are currently playing this activity
|
||||
* @return
|
||||
*/
|
||||
std::vector<ActivityPlayer*> GetActivityPlayers() { return m_ActivityPlayers; };
|
||||
|
||||
/**
|
||||
* Returns activity data for a specific entity (e.g. score and such).
|
||||
* @param playerID the entity to get data for
|
||||
* @return the activity data (score) for the passed player in this activity, if it exists
|
||||
*/
|
||||
ActivityPlayer* GetActivityPlayerData(LWOOBJID playerID);
|
||||
|
||||
/**
|
||||
* Sets some score value for an entity
|
||||
* @param playerID the entity to set score for
|
||||
* @param index the score index to set
|
||||
* @param value the value to set in for that index
|
||||
*/
|
||||
void SetActivityValue(LWOOBJID playerID, uint32_t index, float_t value);
|
||||
|
||||
/**
|
||||
* Returns activity score for the passed parameters
|
||||
* @param playerID the entity to get score for
|
||||
* @param index the index to get score for
|
||||
* @return activity score for the passed parameters
|
||||
*/
|
||||
float_t GetActivityValue(LWOOBJID playerID, uint32_t index);
|
||||
|
||||
/**
|
||||
* Removes activity score tracking for some entity
|
||||
* @param playerID the entity to remove score for
|
||||
*/
|
||||
void RemoveActivityPlayerData(LWOOBJID playerID);
|
||||
|
||||
/**
|
||||
* Adds activity score tracking for some entity
|
||||
* @param playerID the entity to add the activity score for
|
||||
* @return the created entry
|
||||
*/
|
||||
ActivityPlayer* AddActivityPlayerData(LWOOBJID playerID);
|
||||
|
||||
/**
|
||||
* Sets the mapID that this activity points to
|
||||
* @param mapID the map ID to set
|
||||
*/
|
||||
void SetInstanceMapID(uint32_t mapID) { m_ActivityInfo.instanceMapID = mapID; };
|
||||
|
||||
/**
|
||||
* Returns the LMI that this activity points to for a team size
|
||||
* @param teamSize the team size to get the LMI for
|
||||
* @return the LMI that this activity points to for a team size
|
||||
*/
|
||||
uint32_t GetLootMatrixForTeamSize(uint32_t teamSize) { return m_ActivityLootMatrices[teamSize]; }
|
||||
private:
|
||||
|
||||
/**
|
||||
* The database information for this activity
|
||||
*/
|
||||
CDActivities m_ActivityInfo;
|
||||
|
||||
/**
|
||||
* All the active instances of this activity
|
||||
*/
|
||||
std::vector<ActivityInstance*> m_Instances;
|
||||
|
||||
/**
|
||||
* The current lobbies for this activity
|
||||
*/
|
||||
std::vector<Lobby*> m_Queue;
|
||||
|
||||
/**
|
||||
* All the activity score for the players in this activity
|
||||
*/
|
||||
std::vector<ActivityPlayer*> m_ActivityPlayers;
|
||||
|
||||
/**
|
||||
* LMIs for team sizes
|
||||
*/
|
||||
std::unordered_map<uint32_t, uint32_t> m_ActivityLootMatrices;
|
||||
|
||||
/**
|
||||
* The activity id
|
||||
*/
|
||||
int32_t m_ActivityID;
|
||||
|
||||
/**
|
||||
* If the Activity info is dirty
|
||||
*/
|
||||
bool m_DirtyActivityInfo = true;
|
||||
};
|
||||
|
||||
#endif // ACTIVITYCOMPONENT_H
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "SkillComponent.h"
|
||||
#include "RebuildComponent.h"
|
||||
#include "QuickBuildComponent.h"
|
||||
#include "DestroyableComponent.h"
|
||||
#include "Metrics.hpp"
|
||||
#include "CDComponentsRegistryTable.h"
|
||||
@@ -40,7 +40,7 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id):
|
||||
//Grab the aggro information from BaseCombatAI:
|
||||
auto componentQuery = CDClientDatabase::CreatePreppedStmt(
|
||||
"SELECT aggroRadius, tetherSpeed, pursuitSpeed, softTetherRadius, hardTetherRadius FROM BaseCombatAIComponent WHERE id = ?;");
|
||||
componentQuery.bind(1, (int)id);
|
||||
componentQuery.bind(1, static_cast<int>(id));
|
||||
|
||||
auto componentResult = componentQuery.execQuery();
|
||||
|
||||
@@ -77,7 +77,7 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id):
|
||||
*/
|
||||
auto skillQuery = CDClientDatabase::CreatePreppedStmt(
|
||||
"SELECT skillID, cooldown, behaviorID FROM SkillBehavior WHERE skillID IN (SELECT skillID FROM ObjectSkills WHERE objectTemplate = ?);");
|
||||
skillQuery.bind(1, (int)parent->GetLOT());
|
||||
skillQuery.bind(1, static_cast<int>(parent->GetLOT()));
|
||||
|
||||
auto result = skillQuery.execQuery();
|
||||
|
||||
@@ -243,12 +243,12 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) {
|
||||
bool hadRemainingDowntime = m_SkillTime > 0.0f;
|
||||
if (m_SkillTime > 0.0f) m_SkillTime -= deltaTime;
|
||||
|
||||
auto* rebuild = m_Parent->GetComponent<RebuildComponent>();
|
||||
auto* rebuild = m_Parent->GetComponent<QuickBuildComponent>();
|
||||
|
||||
if (rebuild != nullptr) {
|
||||
const auto state = rebuild->GetState();
|
||||
|
||||
if (state != eRebuildState::COMPLETED) {
|
||||
if (state != eQuickBuildState::COMPLETED) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -523,7 +523,7 @@ bool BaseCombatAIComponent::IsMech() {
|
||||
void BaseCombatAIComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
outBitStream->Write(m_DirtyStateOrTarget || bIsInitialUpdate);
|
||||
if (m_DirtyStateOrTarget || bIsInitialUpdate) {
|
||||
outBitStream->Write(uint32_t(m_State));
|
||||
outBitStream->Write(m_State);
|
||||
outBitStream->Write(m_Target);
|
||||
m_DirtyStateOrTarget = false;
|
||||
}
|
||||
@@ -559,12 +559,12 @@ bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* quickbuild = entity->GetComponent<RebuildComponent>();
|
||||
auto* quickbuild = entity->GetComponent<QuickBuildComponent>();
|
||||
|
||||
if (quickbuild != nullptr) {
|
||||
const auto state = quickbuild->GetState();
|
||||
|
||||
if (state != eRebuildState::COMPLETED) {
|
||||
if (state != eQuickBuildState::COMPLETED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class Entity;
|
||||
/**
|
||||
* The current state of the AI
|
||||
*/
|
||||
enum class AiState : int {
|
||||
enum class AiState : uint32_t {
|
||||
idle = 0, // Doing nothing
|
||||
aggro, // Waiting for an enemy to cross / running back to spawn
|
||||
tether, // Chasing an enemy
|
||||
|
||||
@@ -11,9 +11,21 @@
|
||||
#include "EntityManager.h"
|
||||
#include "CDClientManager.h"
|
||||
#include "CDSkillBehaviorTable.h"
|
||||
#include "TeamManager.h"
|
||||
|
||||
std::unordered_map<int32_t, std::vector<BuffParameter>> BuffComponent::m_Cache{};
|
||||
|
||||
namespace {
|
||||
std::map<std::string, std::string> BuffFx = {
|
||||
{ "overtime", "OTB_" },
|
||||
{ "max_health", "HEALTH_" },
|
||||
{ "max_imagination", "IMAGINATION_" },
|
||||
{ "max_armor", "ARMOR_" },
|
||||
{ "speed", "SPEED_" },
|
||||
{ "loot", "LOOT_" }
|
||||
};
|
||||
}
|
||||
|
||||
BuffComponent::BuffComponent(Entity* parent) : Component(parent) {
|
||||
}
|
||||
|
||||
@@ -22,32 +34,38 @@ BuffComponent::~BuffComponent() {
|
||||
|
||||
void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
if (!bIsInitialUpdate) return;
|
||||
if (m_Buffs.empty()) {
|
||||
outBitStream->Write0();
|
||||
} else {
|
||||
outBitStream->Write1();
|
||||
outBitStream->Write(!m_Buffs.empty());
|
||||
if (!m_Buffs.empty()) {
|
||||
outBitStream->Write<uint32_t>(m_Buffs.size());
|
||||
|
||||
for (const auto& buff : m_Buffs) {
|
||||
outBitStream->Write<uint32_t>(buff.first);
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write0();
|
||||
for (const auto& [id, buff] : m_Buffs) {
|
||||
outBitStream->Write<uint32_t>(id);
|
||||
outBitStream->Write(buff.time != 0.0f);
|
||||
if (buff.time != 0.0f) outBitStream->Write<uint32_t>(buff.time * 1000.0f);
|
||||
outBitStream->Write(buff.cancelOnDeath);
|
||||
outBitStream->Write(buff.cancelOnZone);
|
||||
outBitStream->Write(buff.cancelOnDamaged);
|
||||
outBitStream->Write(buff.cancelOnRemoveBuff);
|
||||
outBitStream->Write(buff.cancelOnUi);
|
||||
outBitStream->Write(buff.cancelOnLogout);
|
||||
outBitStream->Write(buff.cancelOnUnequip);
|
||||
outBitStream->Write0(); // Cancel on Damage Absorb Ran Out. Generally false from what I can tell
|
||||
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write0();
|
||||
auto* team = TeamManager::Instance()->GetTeam(buff.source);
|
||||
bool addedByTeammate = false;
|
||||
if (team) {
|
||||
addedByTeammate = std::count(team->members.begin(), team->members.end(), m_Parent->GetObjectID()) > 0;
|
||||
}
|
||||
|
||||
outBitStream->Write<uint32_t>(0);
|
||||
outBitStream->Write(addedByTeammate); // Added by teammate. If source is in the same team as the target, this is true. Otherwise, false.
|
||||
outBitStream->Write(buff.applyOnTeammates);
|
||||
if (addedByTeammate) outBitStream->Write(buff.source);
|
||||
|
||||
outBitStream->Write<uint32_t>(buff.refCount);
|
||||
}
|
||||
}
|
||||
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write0(); // something to do with immunity buffs?
|
||||
}
|
||||
|
||||
void BuffComponent::Update(float deltaTime) {
|
||||
@@ -83,17 +101,55 @@ void BuffComponent::Update(float deltaTime) {
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& GetFxName(const std::string& buffname) {
|
||||
const auto& toReturn = BuffFx[buffname];
|
||||
if (toReturn.empty()) {
|
||||
LOG_DEBUG("No fx name for %s", buffname.c_str());
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
void BuffComponent::ApplyBuffFx(uint32_t buffId, const BuffParameter& buff) {
|
||||
std::string fxToPlay;
|
||||
const auto& buffName = GetFxName(buff.name);
|
||||
|
||||
if (buffName.empty()) return;
|
||||
|
||||
fxToPlay += std::to_string(buffId);
|
||||
LOG_DEBUG("Playing %s %i", fxToPlay.c_str(), buff.effectId);
|
||||
GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), buff.effectId, u"cast", fxToPlay, LWOOBJID_EMPTY, 1.07f, 1.0f, false);
|
||||
}
|
||||
|
||||
void BuffComponent::RemoveBuffFx(uint32_t buffId, const BuffParameter& buff) {
|
||||
std::string fxToPlay;
|
||||
const auto& buffName = GetFxName(buff.name);
|
||||
|
||||
if (buffName.empty()) return;
|
||||
|
||||
fxToPlay += std::to_string(buffId);
|
||||
LOG_DEBUG("Stopping %s", fxToPlay.c_str());
|
||||
GameMessages::SendStopFXEffect(m_Parent, false, fxToPlay);
|
||||
}
|
||||
|
||||
void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOOBJID source, bool addImmunity,
|
||||
bool cancelOnDamaged, bool cancelOnDeath, bool cancelOnLogout, bool cancelOnRemoveBuff,
|
||||
bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone) {
|
||||
bool cancelOnUi, bool cancelOnUnequip, bool cancelOnZone, bool applyOnTeammates) {
|
||||
// Prevent buffs from stacking.
|
||||
if (HasBuff(id)) {
|
||||
m_Buffs[id].refCount++;
|
||||
m_Buffs[id].time = duration;
|
||||
return;
|
||||
}
|
||||
|
||||
GameMessages::SendAddBuff(const_cast<LWOOBJID&>(m_Parent->GetObjectID()), source, (uint32_t)id,
|
||||
(uint32_t)duration * 1000, addImmunity, cancelOnDamaged, cancelOnDeath,
|
||||
cancelOnLogout, cancelOnRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone);
|
||||
auto* team = TeamManager::Instance()->GetTeam(source);
|
||||
bool addedByTeammate = false;
|
||||
if (team) {
|
||||
addedByTeammate = std::count(team->members.begin(), team->members.end(), m_Parent->GetObjectID()) > 0;
|
||||
}
|
||||
|
||||
GameMessages::SendAddBuff(const_cast<LWOOBJID&>(m_Parent->GetObjectID()), source, static_cast<uint32_t>(id),
|
||||
static_cast<uint32_t>(duration) * 1000, addImmunity, cancelOnDamaged, cancelOnDeath,
|
||||
cancelOnLogout, cancelOnRemoveBuff, cancelOnUi, cancelOnUnequip, cancelOnZone, addedByTeammate, applyOnTeammates);
|
||||
|
||||
float tick = 0;
|
||||
float stacks = 0;
|
||||
@@ -121,17 +177,43 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO
|
||||
buff.stacks = stacks;
|
||||
buff.source = source;
|
||||
buff.behaviorID = behaviorID;
|
||||
buff.cancelOnDamaged = cancelOnDamaged;
|
||||
buff.cancelOnDeath = cancelOnDeath;
|
||||
buff.cancelOnLogout = cancelOnLogout;
|
||||
buff.cancelOnRemoveBuff = cancelOnRemoveBuff;
|
||||
buff.cancelOnUi = cancelOnUi;
|
||||
buff.cancelOnUnequip = cancelOnUnequip;
|
||||
buff.cancelOnZone = cancelOnZone;
|
||||
buff.refCount = 1;
|
||||
|
||||
m_Buffs.emplace(id, buff);
|
||||
|
||||
auto* parent = GetParent();
|
||||
if (!cancelOnDeath) return;
|
||||
|
||||
m_Parent->AddDieCallback([parent, id]() {
|
||||
LOG_DEBUG("Removing buff %i because parent died", id);
|
||||
if (!parent) return;
|
||||
auto* buffComponent = parent->GetComponent<BuffComponent>();
|
||||
if (buffComponent) buffComponent->RemoveBuff(id, false, false, true);
|
||||
});
|
||||
}
|
||||
|
||||
void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity) {
|
||||
void BuffComponent::RemoveBuff(int32_t id, bool fromUnEquip, bool removeImmunity, bool ignoreRefCount) {
|
||||
const auto& iter = m_Buffs.find(id);
|
||||
|
||||
if (iter == m_Buffs.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ignoreRefCount && !iter->second.cancelOnRemoveBuff) {
|
||||
iter->second.refCount--;
|
||||
LOG_DEBUG("refCount for buff %i is now %i", id, iter->second.refCount);
|
||||
if (iter->second.refCount > 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GameMessages::SendRemoveBuff(m_Parent, fromUnEquip, removeImmunity, id);
|
||||
|
||||
m_Buffs.erase(iter);
|
||||
@@ -146,6 +228,7 @@ bool BuffComponent::HasBuff(int32_t id) {
|
||||
void BuffComponent::ApplyBuffEffect(int32_t id) {
|
||||
const auto& parameters = GetBuffParameters(id);
|
||||
for (const auto& parameter : parameters) {
|
||||
ApplyBuffFx(id, parameter);
|
||||
if (parameter.name == "max_health") {
|
||||
const auto maxHealth = parameter.value;
|
||||
|
||||
@@ -182,6 +265,7 @@ void BuffComponent::ApplyBuffEffect(int32_t id) {
|
||||
void BuffComponent::RemoveBuffEffect(int32_t id) {
|
||||
const auto& parameters = GetBuffParameters(id);
|
||||
for (const auto& parameter : parameters) {
|
||||
RemoveBuffFx(id, parameter);
|
||||
if (parameter.name == "max_health") {
|
||||
const auto maxHealth = parameter.value;
|
||||
|
||||
@@ -251,13 +335,25 @@ void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
|
||||
|
||||
auto* buffEntry = buffElement->FirstChildElement("b");
|
||||
|
||||
while (buffEntry != nullptr) {
|
||||
while (buffEntry) {
|
||||
int32_t id = buffEntry->IntAttribute("id");
|
||||
float t = buffEntry->FloatAttribute("t");
|
||||
float tk = buffEntry->FloatAttribute("tk");
|
||||
float tt = buffEntry->FloatAttribute("tt");
|
||||
int32_t s = buffEntry->FloatAttribute("s");
|
||||
LWOOBJID sr = buffEntry->Int64Attribute("sr");
|
||||
int32_t b = buffEntry->IntAttribute("b");
|
||||
int32_t refCount = buffEntry->IntAttribute("refCount");
|
||||
|
||||
bool cancelOnDamaged = buffEntry->BoolAttribute("cancelOnDamaged");
|
||||
bool cancelOnDeath = buffEntry->BoolAttribute("cancelOnDeath");
|
||||
bool cancelOnLogout = buffEntry->BoolAttribute("cancelOnLogout");
|
||||
bool cancelOnRemoveBuff = buffEntry->BoolAttribute("cancelOnRemoveBuff");
|
||||
bool cancelOnUi = buffEntry->BoolAttribute("cancelOnUi");
|
||||
bool cancelOnUnequip = buffEntry->BoolAttribute("cancelOnUnequip");
|
||||
bool cancelOnZone = buffEntry->BoolAttribute("cancelOnZone");
|
||||
bool applyOnTeammates = buffEntry->BoolAttribute("applyOnTeammates");
|
||||
|
||||
|
||||
Buff buff;
|
||||
buff.id = id;
|
||||
@@ -266,6 +362,18 @@ void BuffComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
|
||||
buff.stacks = s;
|
||||
buff.source = sr;
|
||||
buff.behaviorID = b;
|
||||
buff.refCount = refCount;
|
||||
buff.tickTime = tt;
|
||||
|
||||
buff.cancelOnDamaged = cancelOnDamaged;
|
||||
buff.cancelOnDeath = cancelOnDeath;
|
||||
buff.cancelOnLogout = cancelOnLogout;
|
||||
buff.cancelOnRemoveBuff = cancelOnRemoveBuff;
|
||||
buff.cancelOnUi = cancelOnUi;
|
||||
buff.cancelOnUnequip = cancelOnUnequip;
|
||||
buff.cancelOnZone = cancelOnZone;
|
||||
buff.applyOnTeammates = applyOnTeammates;
|
||||
|
||||
|
||||
m_Buffs.emplace(id, buff);
|
||||
|
||||
@@ -288,15 +396,28 @@ void BuffComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
|
||||
buffElement->DeleteChildren();
|
||||
}
|
||||
|
||||
for (const auto& buff : m_Buffs) {
|
||||
for (const auto& [id, buff] : m_Buffs) {
|
||||
auto* buffEntry = doc->NewElement("b");
|
||||
// TODO: change this if to if (buff.cancelOnZone || buff.cancelOnLogout) handling at some point. No current way to differentiate between zone transfer and logout.
|
||||
if (buff.cancelOnZone) continue;
|
||||
|
||||
buffEntry->SetAttribute("id", buff.first);
|
||||
buffEntry->SetAttribute("t", buff.second.time);
|
||||
buffEntry->SetAttribute("tk", buff.second.tick);
|
||||
buffEntry->SetAttribute("s", buff.second.stacks);
|
||||
buffEntry->SetAttribute("sr", buff.second.source);
|
||||
buffEntry->SetAttribute("b", buff.second.behaviorID);
|
||||
buffEntry->SetAttribute("id", id);
|
||||
buffEntry->SetAttribute("t", buff.time);
|
||||
buffEntry->SetAttribute("tk", buff.tick);
|
||||
buffEntry->SetAttribute("tt", buff.tickTime);
|
||||
buffEntry->SetAttribute("s", buff.stacks);
|
||||
buffEntry->SetAttribute("sr", buff.source);
|
||||
buffEntry->SetAttribute("b", buff.behaviorID);
|
||||
buffEntry->SetAttribute("refCount", buff.refCount);
|
||||
|
||||
buffEntry->SetAttribute("cancelOnDamaged", buff.cancelOnDamaged);
|
||||
buffEntry->SetAttribute("cancelOnDeath", buff.cancelOnDeath);
|
||||
buffEntry->SetAttribute("cancelOnLogout", buff.cancelOnLogout);
|
||||
buffEntry->SetAttribute("cancelOnRemoveBuff", buff.cancelOnRemoveBuff);
|
||||
buffEntry->SetAttribute("cancelOnUi", buff.cancelOnUi);
|
||||
buffEntry->SetAttribute("cancelOnUnequip", buff.cancelOnUnequip);
|
||||
buffEntry->SetAttribute("cancelOnZone", buff.cancelOnZone);
|
||||
buffEntry->SetAttribute("applyOnTeammates", buff.applyOnTeammates);
|
||||
|
||||
buffElement->LinkEndChild(buffEntry);
|
||||
}
|
||||
@@ -309,9 +430,8 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
|
||||
return pair->second;
|
||||
}
|
||||
|
||||
auto query = CDClientDatabase::CreatePreppedStmt(
|
||||
"SELECT * FROM BuffParameters WHERE BuffID = ?;");
|
||||
query.bind(1, (int)buffId);
|
||||
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM BuffParameters WHERE BuffID = ?;");
|
||||
query.bind(1, static_cast<int>(buffId));
|
||||
|
||||
auto result = query.execQuery();
|
||||
|
||||
@@ -321,11 +441,12 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
|
||||
BuffParameter param;
|
||||
|
||||
param.buffId = buffId;
|
||||
param.name = result.getStringField(1);
|
||||
param.value = result.getFloatField(2);
|
||||
param.name = result.getStringField("ParameterName");
|
||||
param.value = result.getFloatField("NumberValue");
|
||||
param.effectId = result.getIntField("EffectID");
|
||||
|
||||
if (!result.fieldIsNull(3)) {
|
||||
std::istringstream stream(result.getStringField(3));
|
||||
std::istringstream stream(result.getStringField("StringValue"));
|
||||
std::string token;
|
||||
|
||||
while (std::getline(stream, token, ',')) {
|
||||
|
||||
@@ -14,8 +14,7 @@ class Entity;
|
||||
/**
|
||||
* Extra information on effects to apply after applying a buff, for example whether to buff armor, imag or health and by how much
|
||||
*/
|
||||
struct BuffParameter
|
||||
{
|
||||
struct BuffParameter {
|
||||
int32_t buffId;
|
||||
std::string name;
|
||||
float value;
|
||||
@@ -26,8 +25,7 @@ struct BuffParameter
|
||||
/**
|
||||
* Meta information about a buff that can be applied, e.g. how long it's applied, who applied it, etc.
|
||||
*/
|
||||
struct Buff
|
||||
{
|
||||
struct Buff {
|
||||
int32_t id = 0;
|
||||
float time = 0;
|
||||
float tick = 0;
|
||||
@@ -35,6 +33,15 @@ struct Buff
|
||||
int32_t stacks = 0;
|
||||
LWOOBJID source = 0;
|
||||
int32_t behaviorID = 0;
|
||||
bool cancelOnDamaged = false;
|
||||
bool cancelOnDeath = false;
|
||||
bool cancelOnLogout = false;
|
||||
bool cancelOnRemoveBuff = false;
|
||||
bool cancelOnUi = false;
|
||||
bool cancelOnUnequip = false;
|
||||
bool cancelOnZone = false;
|
||||
bool applyOnTeammates = false;
|
||||
uint32_t refCount = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -74,14 +81,17 @@ public:
|
||||
*/
|
||||
void ApplyBuff(int32_t id, float duration, LWOOBJID source, bool addImmunity = false, bool cancelOnDamaged = false,
|
||||
bool cancelOnDeath = true, bool cancelOnLogout = false, bool cancelOnRemoveBuff = true,
|
||||
bool cancelOnUi = false, bool cancelOnUnequip = false, bool cancelOnZone = false);
|
||||
bool cancelOnUi = false, bool cancelOnUnequip = false, bool cancelOnZone = false, bool applyOnTeammates = false);
|
||||
|
||||
void ApplyBuffFx(uint32_t buffId, const BuffParameter& buffName);
|
||||
void RemoveBuffFx(uint32_t buffId, const BuffParameter& buffName);
|
||||
|
||||
/**
|
||||
* Removes a buff from the parent entity, reversing its effects
|
||||
* @param id the id of the buff to remove
|
||||
* @param removeImmunity whether or not to remove immunity on removing the buff
|
||||
*/
|
||||
void RemoveBuff(int32_t id, bool fromUnEquip = false, bool removeImmunity = false);
|
||||
void RemoveBuff(int32_t id, bool fromUnEquip = false, bool removeImmunity = false, bool ignoreRefCount = false);
|
||||
|
||||
/**
|
||||
* Returns whether or not the entity has a buff identified by `id`
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp"
|
||||
set(DGAME_DCOMPONENTS_SOURCES "ActivityComponent.cpp"
|
||||
"BaseCombatAIComponent.cpp"
|
||||
"BouncerComponent.cpp"
|
||||
"BuffComponent.cpp"
|
||||
"BuildBorderComponent.cpp"
|
||||
@@ -31,20 +32,19 @@ set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp"
|
||||
"ProximityMonitorComponent.cpp"
|
||||
"RacingControlComponent.cpp"
|
||||
"RailActivatorComponent.cpp"
|
||||
"RebuildComponent.cpp"
|
||||
"QuickBuildComponent.cpp"
|
||||
"RenderComponent.cpp"
|
||||
"RigidbodyPhantomPhysicsComponent.cpp"
|
||||
"MultiZoneEntranceComponent.cpp"
|
||||
"RocketLaunchpadControlComponent.cpp"
|
||||
"ScriptedActivityComponent.cpp"
|
||||
"ShootingGalleryComponent.cpp"
|
||||
"SimplePhysicsComponent.cpp"
|
||||
"SkillComponent.cpp"
|
||||
"SoundTriggerComponent.cpp"
|
||||
"SwitchComponent.cpp"
|
||||
"TriggerComponent.cpp"
|
||||
"VehiclePhysicsComponent.cpp"
|
||||
"HavokVehiclePhysicsComponent.cpp"
|
||||
"VendorComponent.cpp"
|
||||
"ZoneControlComponent.cpp"
|
||||
"MiniGameControlComponent.cpp"
|
||||
PARENT_SCOPE
|
||||
)
|
||||
|
||||
@@ -10,12 +10,16 @@
|
||||
#include "InventoryComponent.h"
|
||||
#include "ControllablePhysicsComponent.h"
|
||||
#include "EntityManager.h"
|
||||
#include "VehiclePhysicsComponent.h"
|
||||
#include "HavokVehiclePhysicsComponent.h"
|
||||
#include "GameMessages.h"
|
||||
#include "Item.h"
|
||||
#include "Amf3.h"
|
||||
#include "eGameMasterLevel.h"
|
||||
#include "eGameActivity.h"
|
||||
#include "User.h"
|
||||
#include "Database.h"
|
||||
#include "CDRewardCodesTable.h"
|
||||
#include "Mail.h"
|
||||
#include <ctime>
|
||||
|
||||
CharacterComponent::CharacterComponent(Entity* parent, Character* character) : Component(parent) {
|
||||
@@ -74,10 +78,14 @@ CharacterComponent::~CharacterComponent() {
|
||||
void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
|
||||
if (bIsInitialUpdate) {
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write(m_ClaimCodes[0] != 0);
|
||||
if (m_ClaimCodes[0] != 0) outBitStream->Write(m_ClaimCodes[0]);
|
||||
outBitStream->Write(m_ClaimCodes[1] != 0);
|
||||
if (m_ClaimCodes[1] != 0) outBitStream->Write(m_ClaimCodes[1]);
|
||||
outBitStream->Write(m_ClaimCodes[2] != 0);
|
||||
if (m_ClaimCodes[2] != 0) outBitStream->Write(m_ClaimCodes[2]);
|
||||
outBitStream->Write(m_ClaimCodes[3] != 0);
|
||||
if (m_ClaimCodes[3] != 0) outBitStream->Write(m_ClaimCodes[3]);
|
||||
|
||||
outBitStream->Write(m_Character->GetHairColor());
|
||||
outBitStream->Write(m_Character->GetHairStyle());
|
||||
@@ -127,7 +135,7 @@ void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInit
|
||||
outBitStream->Write0();
|
||||
outBitStream->Write(m_IsLanding);
|
||||
if (m_IsLanding) {
|
||||
outBitStream->Write(uint16_t(m_LastRocketConfig.size()));
|
||||
outBitStream->Write<uint16_t>(m_LastRocketConfig.size());
|
||||
for (uint16_t character : m_LastRocketConfig) {
|
||||
outBitStream->Write(character);
|
||||
}
|
||||
@@ -149,7 +157,7 @@ void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInit
|
||||
outBitStream->Write(m_DirtySocialInfo);
|
||||
if (m_DirtySocialInfo) {
|
||||
outBitStream->Write(m_GuildID);
|
||||
outBitStream->Write<unsigned char>(static_cast<unsigned char>(m_GuildName.size()));
|
||||
outBitStream->Write<unsigned char>(m_GuildName.size());
|
||||
if (!m_GuildName.empty())
|
||||
outBitStream->WriteBits(reinterpret_cast<const unsigned char*>(m_GuildName.c_str()), static_cast<unsigned char>(m_GuildName.size()) * sizeof(wchar_t) * 8);
|
||||
|
||||
@@ -186,6 +194,13 @@ void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
|
||||
SetReputation(0);
|
||||
}
|
||||
|
||||
character->QueryUnsigned64Attribute("co", &m_ClaimCodes[0]);
|
||||
character->QueryUnsigned64Attribute("co1", &m_ClaimCodes[1]);
|
||||
character->QueryUnsigned64Attribute("co2", &m_ClaimCodes[2]);
|
||||
character->QueryUnsigned64Attribute("co3", &m_ClaimCodes[3]);
|
||||
|
||||
AwardClaimCodes();
|
||||
|
||||
character->QueryInt64Attribute("ls", &m_Uscore);
|
||||
|
||||
// Load the statistics
|
||||
@@ -214,7 +229,7 @@ void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
|
||||
uint32_t mapID;
|
||||
child->QueryAttribute("map", &mapID);
|
||||
|
||||
m_ZoneStatistics.insert({ (LWOMAPID)mapID, statistics });
|
||||
m_ZoneStatistics.insert({ static_cast<LWOMAPID>(mapID), statistics });
|
||||
|
||||
child = child->NextSiblingElement();
|
||||
}
|
||||
@@ -308,6 +323,11 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_ClaimCodes[0] != 0) character->SetAttribute("co", m_ClaimCodes[0]);
|
||||
if (m_ClaimCodes[1] != 0) character->SetAttribute("co1", m_ClaimCodes[1]);
|
||||
if (m_ClaimCodes[2] != 0) character->SetAttribute("co2", m_ClaimCodes[2]);
|
||||
if (m_ClaimCodes[3] != 0) character->SetAttribute("co3", m_ClaimCodes[3]);
|
||||
|
||||
character->SetAttribute("ls", m_Uscore);
|
||||
// Custom attribute to keep track of reputation.
|
||||
character->SetAttribute("rpt", GetReputation());
|
||||
@@ -478,7 +498,7 @@ void CharacterComponent::TrackArmorDelta(int32_t armor) {
|
||||
}
|
||||
}
|
||||
|
||||
void CharacterComponent::TrackRebuildComplete() {
|
||||
void CharacterComponent::TrackQuickBuildComplete() {
|
||||
UpdatePlayerStatistic(QuickBuildsCompleted);
|
||||
|
||||
const auto mapID = Game::zoneManager->GetZoneID().GetMapID();
|
||||
@@ -495,9 +515,9 @@ void CharacterComponent::TrackPositionUpdate(const NiPoint3& newPosition) {
|
||||
const auto distance = NiPoint3::Distance(newPosition, m_Parent->GetPosition());
|
||||
|
||||
if (m_IsRacing) {
|
||||
UpdatePlayerStatistic(DistanceDriven, (uint64_t)distance);
|
||||
UpdatePlayerStatistic(DistanceDriven, static_cast<uint64_t>(distance));
|
||||
} else {
|
||||
UpdatePlayerStatistic(MetersTraveled, (uint64_t)distance);
|
||||
UpdatePlayerStatistic(MetersTraveled, static_cast<uint64_t>(distance));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -738,3 +758,31 @@ void CharacterComponent::UpdateClientMinimap(bool showFaction, std::string ventu
|
||||
arrayToSend.Insert(ventureVisionType, showFaction);
|
||||
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent ? m_Parent->GetSystemAddress() : UNASSIGNED_SYSTEM_ADDRESS, "SetFactionVisibility", arrayToSend);
|
||||
}
|
||||
|
||||
void CharacterComponent::AwardClaimCodes() {
|
||||
if (!m_Parent) return;
|
||||
auto* user = m_Parent->GetParentUser();
|
||||
if (!user) return;
|
||||
|
||||
auto rewardCodes = Database::Get()->GetRewardCodesByAccountID(user->GetAccountID());
|
||||
if (rewardCodes.empty()) return;
|
||||
|
||||
auto* cdrewardCodes = CDClientManager::Instance().GetTable<CDRewardCodesTable>();
|
||||
for (auto const rewardCode: rewardCodes){
|
||||
LOG_DEBUG("Processing RewardCode %i", rewardCode);
|
||||
const uint32_t rewardCodeIndex = rewardCode >> 6;
|
||||
const uint32_t bitIndex = rewardCode % 64;
|
||||
if (GeneralUtils::CheckBit(m_ClaimCodes[rewardCodeIndex], bitIndex)) continue;
|
||||
m_ClaimCodes[rewardCodeIndex] = GeneralUtils::SetBit(m_ClaimCodes[rewardCodeIndex], bitIndex);
|
||||
|
||||
// Don't send it on this one since it's default and the mail doesn't make sense
|
||||
if (rewardCode == 30) continue;
|
||||
|
||||
auto attachmentLOT = cdrewardCodes->GetAttachmentLOT(rewardCode);
|
||||
std::ostringstream subject;
|
||||
subject << "%[RewardCodes_" << rewardCode << "_subjectText]";
|
||||
std::ostringstream body;
|
||||
body << "%[RewardCodes_" << rewardCode << "_bodyText]";
|
||||
Mail::SendMail(LWOOBJID_EMPTY, "%[MAIL_SYSTEM_NOTIFICATION]", m_Parent, subject.str(), body.str(), attachmentLOT, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "CDMissionsTable.h"
|
||||
#include "tinyxml2.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
#include <array>
|
||||
|
||||
enum class eGameActivity : uint32_t;
|
||||
|
||||
@@ -232,7 +233,7 @@ public:
|
||||
/**
|
||||
* Handles completing a rebuild by updating the statistics
|
||||
*/
|
||||
void TrackRebuildComplete();
|
||||
void TrackQuickBuildComplete();
|
||||
|
||||
/**
|
||||
* Tracks a player completing the race, also updates stats
|
||||
@@ -566,6 +567,10 @@ private:
|
||||
LWOOBJID m_LastRocketItemID = LWOOBJID_EMPTY;
|
||||
|
||||
LWOOBJID m_CurrentInteracting = LWOOBJID_EMPTY;
|
||||
|
||||
std::array<uint64_t, 4> m_ClaimCodes{};
|
||||
|
||||
void AwardClaimCodes();
|
||||
};
|
||||
|
||||
#endif // CHARACTERCOMPONENT_H
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "CDClientManager.h"
|
||||
#include "CDDestructibleComponentTable.h"
|
||||
#include "EntityManager.h"
|
||||
#include "RebuildComponent.h"
|
||||
#include "QuickBuildComponent.h"
|
||||
#include "CppScripts.h"
|
||||
#include "Loot.h"
|
||||
#include "Character.h"
|
||||
@@ -85,11 +85,11 @@ void DestroyableComponent::Reinitialize(LOT templateID) {
|
||||
|
||||
int32_t buffComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::BUFF);
|
||||
int32_t collectibleComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::COLLECTIBLE);
|
||||
int32_t rebuildComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::QUICK_BUILD);
|
||||
int32_t quickBuildComponentID = compRegistryTable->GetByIDAndType(templateID, eReplicaComponentType::QUICK_BUILD);
|
||||
|
||||
int32_t componentID = 0;
|
||||
if (collectibleComponentID > 0) componentID = collectibleComponentID;
|
||||
if (rebuildComponentID > 0) componentID = rebuildComponentID;
|
||||
if (quickBuildComponentID > 0) componentID = quickBuildComponentID;
|
||||
if (buffComponentID > 0) componentID = buffComponentID;
|
||||
|
||||
CDDestructibleComponentTable* destCompTable = CDClientManager::Instance().GetTable<CDDestructibleComponentTable>();
|
||||
@@ -154,7 +154,7 @@ void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn
|
||||
outBitStream->Write(m_fMaxArmor);
|
||||
outBitStream->Write(m_fMaxImagination);
|
||||
|
||||
outBitStream->Write(uint32_t(m_FactionIDs.size()));
|
||||
outBitStream->Write<uint32_t>(m_FactionIDs.size());
|
||||
for (size_t i = 0; i < m_FactionIDs.size(); ++i) {
|
||||
outBitStream->Write(m_FactionIDs[i]);
|
||||
}
|
||||
@@ -380,7 +380,7 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore
|
||||
|
||||
auto query = CDClientDatabase::CreatePreppedStmt(
|
||||
"SELECT enemyList FROM Factions WHERE faction = ?;");
|
||||
query.bind(1, (int)factionID);
|
||||
query.bind(1, static_cast<int>(factionID));
|
||||
|
||||
auto result = query.execQuery();
|
||||
|
||||
@@ -557,7 +557,7 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
|
||||
}
|
||||
|
||||
if (IsImmune() || IsCooldownImmune()) {
|
||||
LOG_DEBUG("Target targetEntity %llu is immune!", m_Parent->GetObjectID()); //Immune is succesfully proc'd
|
||||
LOG_DEBUG("Target targetEntity %llu is immune!", m_Parent->GetObjectID());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -796,7 +796,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
|
||||
}
|
||||
}
|
||||
|
||||
m_Parent->Kill(owner);
|
||||
m_Parent->Kill(owner, killType);
|
||||
}
|
||||
|
||||
void DestroyableComponent::SetFaction(int32_t factionID, bool ignoreChecks) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "VehiclePhysicsComponent.h"
|
||||
#include "HavokVehiclePhysicsComponent.h"
|
||||
#include "EntityManager.h"
|
||||
|
||||
VehiclePhysicsComponent::VehiclePhysicsComponent(Entity* parent) : PhysicsComponent(parent) {
|
||||
HavokVehiclePhysicsComponent::HavokVehiclePhysicsComponent(Entity* parent) : PhysicsComponent(parent) {
|
||||
m_Velocity = NiPoint3::ZERO;
|
||||
m_AngularVelocity = NiPoint3::ZERO;
|
||||
m_IsOnGround = true;
|
||||
@@ -12,45 +12,45 @@ VehiclePhysicsComponent::VehiclePhysicsComponent(Entity* parent) : PhysicsCompon
|
||||
m_EndBehavior = GeneralUtils::GenerateRandomNumber<uint32_t>(0, 7);
|
||||
}
|
||||
|
||||
void VehiclePhysicsComponent::SetVelocity(const NiPoint3& vel) {
|
||||
void HavokVehiclePhysicsComponent::SetVelocity(const NiPoint3& vel) {
|
||||
if (vel == m_Velocity) return;
|
||||
m_DirtyPosition = true;
|
||||
m_Velocity = vel;
|
||||
}
|
||||
|
||||
void VehiclePhysicsComponent::SetAngularVelocity(const NiPoint3& vel) {
|
||||
void HavokVehiclePhysicsComponent::SetAngularVelocity(const NiPoint3& vel) {
|
||||
if (vel == m_AngularVelocity) return;
|
||||
m_DirtyPosition = true;
|
||||
m_AngularVelocity = vel;
|
||||
}
|
||||
|
||||
void VehiclePhysicsComponent::SetIsOnGround(bool val) {
|
||||
void HavokVehiclePhysicsComponent::SetIsOnGround(bool val) {
|
||||
if (val == m_IsOnGround) return;
|
||||
m_DirtyPosition = true;
|
||||
m_IsOnGround = val;
|
||||
}
|
||||
|
||||
void VehiclePhysicsComponent::SetIsOnRail(bool val) {
|
||||
void HavokVehiclePhysicsComponent::SetIsOnRail(bool val) {
|
||||
if (val == m_IsOnRail) return;
|
||||
m_DirtyPosition = true;
|
||||
m_IsOnRail = val;
|
||||
}
|
||||
|
||||
void VehiclePhysicsComponent::SetRemoteInputInfo(const RemoteInputInfo& remoteInputInfo) {
|
||||
void HavokVehiclePhysicsComponent::SetRemoteInputInfo(const RemoteInputInfo& remoteInputInfo) {
|
||||
if (m_RemoteInputInfo == remoteInputInfo) return;
|
||||
this->m_RemoteInputInfo = remoteInputInfo;
|
||||
m_DirtyRemoteInput = true;
|
||||
}
|
||||
|
||||
void VehiclePhysicsComponent::SetDirtyVelocity(bool val) {
|
||||
void HavokVehiclePhysicsComponent::SetDirtyVelocity(bool val) {
|
||||
m_DirtyVelocity = val;
|
||||
}
|
||||
|
||||
void VehiclePhysicsComponent::SetDirtyAngularVelocity(bool val) {
|
||||
void HavokVehiclePhysicsComponent::SetDirtyAngularVelocity(bool val) {
|
||||
m_DirtyAngularVelocity = val;
|
||||
}
|
||||
|
||||
void VehiclePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void HavokVehiclePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
outBitStream->Write(bIsInitialUpdate || m_DirtyPosition);
|
||||
|
||||
if (bIsInitialUpdate || m_DirtyPosition) {
|
||||
@@ -111,7 +111,7 @@ void VehiclePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bI
|
||||
outBitStream->Write0();
|
||||
}
|
||||
|
||||
void VehiclePhysicsComponent::Update(float deltaTime) {
|
||||
void HavokVehiclePhysicsComponent::Update(float deltaTime) {
|
||||
if (m_SoftUpdate > 5) {
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
m_SoftUpdate = 0;
|
||||
@@ -6,6 +6,13 @@
|
||||
#include "eReplicaComponentType.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;
|
||||
@@ -26,11 +33,11 @@ struct RemoteInputInfo {
|
||||
/**
|
||||
* Physics component for vehicles.
|
||||
*/
|
||||
class VehiclePhysicsComponent : public PhysicsComponent {
|
||||
class HavokVehiclePhysicsComponent : public PhysicsComponent {
|
||||
public:
|
||||
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::VEHICLE_PHYSICS;
|
||||
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::HAVOK_VEHICLE_PHYSICS;
|
||||
|
||||
VehiclePhysicsComponent(Entity* parentEntity);
|
||||
HavokVehiclePhysicsComponent(Entity* parentEntity);
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "PossessorComponent.h"
|
||||
#include "PossessableComponent.h"
|
||||
#include "ModuleAssemblyComponent.h"
|
||||
#include "VehiclePhysicsComponent.h"
|
||||
#include "HavokVehiclePhysicsComponent.h"
|
||||
#include "CharacterComponent.h"
|
||||
#include "dZoneManager.h"
|
||||
#include "PropertyManagementComponent.h"
|
||||
@@ -981,7 +981,7 @@ void InventoryComponent::HandlePossession(Item* item) {
|
||||
auto* mount = Game::entityManager->CreateEntity(info, nullptr, m_Parent);
|
||||
|
||||
// Check to see if the mount is a vehicle, if so, flip it
|
||||
auto* vehicleComponent = mount->GetComponent<VehiclePhysicsComponent>();
|
||||
auto* vehicleComponent = mount->GetComponent<HavokVehiclePhysicsComponent>();
|
||||
if (vehicleComponent) characterComponent->SetIsRacing(true);
|
||||
|
||||
// Setup the destroyable stats
|
||||
|
||||
@@ -1,44 +1,24 @@
|
||||
#include "LUPExhibitComponent.h"
|
||||
|
||||
#include "EntityManager.h"
|
||||
|
||||
LUPExhibitComponent::LUPExhibitComponent(Entity* parent) : Component(parent) {
|
||||
m_Exhibits = { 11121, 11295, 11423, 11979 };
|
||||
|
||||
m_ExhibitIndex = 0;
|
||||
|
||||
m_Exhibit = m_Exhibits[m_ExhibitIndex];
|
||||
|
||||
|
||||
}
|
||||
|
||||
LUPExhibitComponent::~LUPExhibitComponent() {
|
||||
|
||||
}
|
||||
|
||||
void LUPExhibitComponent::Update(float deltaTime) {
|
||||
m_UpdateTimer += deltaTime;
|
||||
|
||||
if (m_UpdateTimer > 20.0f) {
|
||||
NextExhibit();
|
||||
|
||||
NextLUPExhibit();
|
||||
m_UpdateTimer = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
void LUPExhibitComponent::NextExhibit() {
|
||||
m_ExhibitIndex++;
|
||||
|
||||
if (m_ExhibitIndex >= m_Exhibits.size()) {
|
||||
m_ExhibitIndex = 0;
|
||||
}
|
||||
|
||||
m_Exhibit = m_Exhibits[m_ExhibitIndex];
|
||||
|
||||
void LUPExhibitComponent::NextLUPExhibit() {
|
||||
m_LUPExhibitIndex++;
|
||||
m_DirtyLUPExhibit = true;
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
|
||||
void LUPExhibitComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
outBitStream->Write1(); // Dirty flag?
|
||||
outBitStream->Write(m_Exhibit);
|
||||
outBitStream->Write(m_DirtyLUPExhibit);
|
||||
if (m_DirtyLUPExhibit) {
|
||||
outBitStream->Write(m_LUPExhibits[m_LUPExhibitIndex % m_LUPExhibits.size()]);
|
||||
if (!bIsInitialUpdate) m_DirtyLUPExhibit = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
#include "Component.h"
|
||||
#include "Entity.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include "dCommonVars.h"
|
||||
|
||||
/**
|
||||
* Component that handles the LOT that is shown in the LUP exhibit in the LUP world. Works by setting a timer and
|
||||
@@ -11,35 +14,15 @@
|
||||
class LUPExhibitComponent : public Component
|
||||
{
|
||||
public:
|
||||
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::EXHIBIT;
|
||||
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::LUP_EXHIBIT;
|
||||
|
||||
LUPExhibitComponent(Entity* parent);
|
||||
~LUPExhibitComponent();
|
||||
LUPExhibitComponent(Entity* parent) : Component(parent) {};
|
||||
void Update(float deltaTime) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
|
||||
/**
|
||||
* After the timer runs out, this changes the currently exhibited LOT to the next one
|
||||
*/
|
||||
void NextExhibit();
|
||||
void NextLUPExhibit();
|
||||
private:
|
||||
/**
|
||||
* The LOT that's currently on exhibit
|
||||
*/
|
||||
LOT m_Exhibit;
|
||||
|
||||
/**
|
||||
* The time since we've last updated the exhibit
|
||||
*/
|
||||
float m_UpdateTimer;
|
||||
|
||||
/**
|
||||
* The list of possible exhibits to show
|
||||
*/
|
||||
std::vector<LOT> m_Exhibits;
|
||||
|
||||
/**
|
||||
* The current index in the exhibit list
|
||||
*/
|
||||
size_t m_ExhibitIndex;
|
||||
float m_UpdateTimer = 0.0f;
|
||||
std::array<LOT, 4> m_LUPExhibits = { 11121, 11295, 11423, 11979 };
|
||||
uint8_t m_LUPExhibitIndex = 0;
|
||||
bool m_DirtyLUPExhibit = true;
|
||||
};
|
||||
|
||||
5
dGame/dComponents/MiniGameControlComponent.cpp
Normal file
5
dGame/dComponents/MiniGameControlComponent.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "MiniGameControlComponent.h"
|
||||
|
||||
void MiniGameControlComponent::Serialize(RakNet::BitStream* outBitStream, bool isConstruction) {
|
||||
outBitStream->Write<uint32_t>(0x40000000);
|
||||
}
|
||||
15
dGame/dComponents/MiniGameControlComponent.h
Normal file
15
dGame/dComponents/MiniGameControlComponent.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef __MINIGAMECONTROLCOMPONENT__H__
|
||||
#define __MINIGAMECONTROLCOMPONENT__H__
|
||||
|
||||
#include "Component.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
|
||||
class MiniGameControlComponent final : public Component {
|
||||
public:
|
||||
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::MINI_GAME_CONTROL;
|
||||
|
||||
MiniGameControlComponent(Entity* parent) : Component(parent) {}
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool isConstruction);
|
||||
};
|
||||
|
||||
#endif //!__MINIGAMECONTROLCOMPONENT__H__
|
||||
5
dGame/dComponents/MinigameComponent.cpp
Normal file
5
dGame/dComponents/MinigameComponent.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
#include "MinigameComponent.h"
|
||||
|
||||
void MinigameComponent::Serialize(RakNet::BitStream* outBitStream, bool isConstruction) {
|
||||
outBitStream->Write<uint32_t>(0x40000000);
|
||||
}
|
||||
@@ -145,8 +145,13 @@ void MissionComponent::RemoveMission(uint32_t missionId) {
|
||||
}
|
||||
|
||||
void MissionComponent::Progress(eMissionTaskType type, int32_t value, LWOOBJID associate, const std::string& targets, int32_t count, bool ignoreAchievements) {
|
||||
for (const auto& pair : m_Missions) {
|
||||
auto* mission = pair.second;
|
||||
std::vector<uint32_t> acceptedAchievements;
|
||||
if (count > 0 && !ignoreAchievements) {
|
||||
acceptedAchievements = LookForAchievements(type, value, true, associate, targets, count);
|
||||
}
|
||||
|
||||
for (const auto& [id, mission] : m_Missions) {
|
||||
if (!mission || std::find(acceptedAchievements.begin(), acceptedAchievements.end(), mission->GetMissionId()) != acceptedAchievements.end()) continue;
|
||||
|
||||
if (mission->IsAchievement() && ignoreAchievements) continue;
|
||||
|
||||
@@ -154,10 +159,6 @@ void MissionComponent::Progress(eMissionTaskType type, int32_t value, LWOOBJID a
|
||||
|
||||
mission->Progress(type, value, associate, targets, count);
|
||||
}
|
||||
|
||||
if (count > 0 && !ignoreAchievements) {
|
||||
LookForAchievements(type, value, true, associate, targets, count);
|
||||
}
|
||||
}
|
||||
|
||||
void MissionComponent::ForceProgress(const uint32_t missionId, const uint32_t taskId, const int32_t value, const bool acceptMission) {
|
||||
@@ -282,12 +283,12 @@ bool MissionComponent::GetMissionInfo(uint32_t missionId, CDMissions& result) {
|
||||
|
||||
#define MISSION_NEW_METHOD
|
||||
|
||||
bool MissionComponent::LookForAchievements(eMissionTaskType type, int32_t value, bool progress, LWOOBJID associate, const std::string& targets, int32_t count) {
|
||||
const std::vector<uint32_t> MissionComponent::LookForAchievements(eMissionTaskType type, int32_t value, bool progress, LWOOBJID associate, const std::string& targets, int32_t count) {
|
||||
#ifdef MISSION_NEW_METHOD
|
||||
// Query for achievments, using the cache
|
||||
const auto& result = QueryAchievements(type, value, targets);
|
||||
|
||||
bool any = false;
|
||||
std::vector<uint32_t> acceptedAchievements;
|
||||
|
||||
for (const uint32_t missionID : result) {
|
||||
// Check if we already have this achievement
|
||||
@@ -309,7 +310,7 @@ bool MissionComponent::LookForAchievements(eMissionTaskType type, int32_t value,
|
||||
|
||||
instance->Accept();
|
||||
|
||||
any = true;
|
||||
acceptedAchievements.push_back(missionID);
|
||||
|
||||
if (progress) {
|
||||
// Progress mission to bring it up to speed
|
||||
@@ -317,7 +318,7 @@ bool MissionComponent::LookForAchievements(eMissionTaskType type, int32_t value,
|
||||
}
|
||||
}
|
||||
|
||||
return any;
|
||||
return acceptedAchievements;
|
||||
#else
|
||||
auto* missionTasksTable = CDClientManager::Instance().GetTable<CDMissionTasksTable>();
|
||||
auto* missionsTable = CDClientManager::Instance().GetTable<CDMissionsTable>();
|
||||
@@ -326,7 +327,7 @@ bool MissionComponent::LookForAchievements(eMissionTaskType type, int32_t value,
|
||||
return entry.taskType == static_cast<unsigned>(type);
|
||||
});
|
||||
|
||||
auto any = false;
|
||||
std::vector<uint32_t> acceptedAchievements;
|
||||
|
||||
for (const auto& task : tasks) {
|
||||
if (GetMission(task.id) != nullptr) {
|
||||
@@ -380,14 +381,14 @@ bool MissionComponent::LookForAchievements(eMissionTaskType type, int32_t value,
|
||||
|
||||
instance->Accept();
|
||||
|
||||
any = true;
|
||||
acceptedAchievements.push_back(mission.id);
|
||||
|
||||
if (progress) {
|
||||
instance->Progress(type, value, associate, targets, count);
|
||||
}
|
||||
}
|
||||
|
||||
return any;
|
||||
return acceptedAchievements;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -457,7 +458,7 @@ const std::vector<uint32_t>& MissionComponent::QueryAchievements(eMissionTaskTyp
|
||||
bool MissionComponent::RequiresItem(const LOT lot) {
|
||||
auto query = CDClientDatabase::CreatePreppedStmt(
|
||||
"SELECT type FROM Objects WHERE id = ?;");
|
||||
query.bind(1, (int)lot);
|
||||
query.bind(1, static_cast<int>(lot));
|
||||
|
||||
auto result = query.execQuery();
|
||||
|
||||
@@ -499,7 +500,7 @@ bool MissionComponent::RequiresItem(const LOT lot) {
|
||||
|
||||
const auto required = LookForAchievements(eMissionTaskType::GATHER, lot, false);
|
||||
|
||||
return required;
|
||||
return !required.empty();
|
||||
}
|
||||
|
||||
|
||||
@@ -620,3 +621,12 @@ bool MissionComponent::HasCollectible(int32_t collectibleID) {
|
||||
bool MissionComponent::HasMission(uint32_t missionId) {
|
||||
return GetMission(missionId) != nullptr;
|
||||
}
|
||||
|
||||
void MissionComponent::ResetMission(const int32_t missionId) {
|
||||
auto* mission = GetMission(missionId);
|
||||
|
||||
if (!mission) return;
|
||||
|
||||
m_Missions.erase(missionId);
|
||||
GameMessages::SendResetMissions(m_Parent, m_Parent->GetSystemAddress(), missionId);
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ public:
|
||||
* @param count the number of values to progress by (differs by task type)
|
||||
* @return true if a achievement was accepted, false otherwise
|
||||
*/
|
||||
bool LookForAchievements(eMissionTaskType type, int32_t value, bool progress = true, LWOOBJID associate = LWOOBJID_EMPTY, const std::string& targets = "", int32_t count = 1);
|
||||
const std::vector<uint32_t> LookForAchievements(eMissionTaskType type, int32_t value, bool progress = true, LWOOBJID associate = LWOOBJID_EMPTY, const std::string& targets = "", int32_t count = 1);
|
||||
|
||||
/**
|
||||
* Checks if there's a mission active that requires the collection of the specified LOT
|
||||
@@ -170,6 +170,7 @@ public:
|
||||
*/
|
||||
bool HasMission(uint32_t missionId);
|
||||
|
||||
void ResetMission(const int32_t missionId);
|
||||
private:
|
||||
/**
|
||||
* All the missions owned by this entity, mapped by mission ID
|
||||
|
||||
@@ -29,11 +29,11 @@ uint32_t OfferedMission::GetMissionId() const {
|
||||
return this->missionId;
|
||||
}
|
||||
|
||||
bool OfferedMission::GetOfferMission() const {
|
||||
bool OfferedMission::GetOffersMission() const {
|
||||
return this->offersMission;
|
||||
}
|
||||
|
||||
bool OfferedMission::GetAcceptMission() const {
|
||||
bool OfferedMission::GetAcceptsMission() const {
|
||||
return this->acceptsMission;
|
||||
}
|
||||
|
||||
@@ -55,54 +55,39 @@ MissionOfferComponent::MissionOfferComponent(Entity* parent, const LOT parentLot
|
||||
});
|
||||
|
||||
for (auto& mission : missions) {
|
||||
auto* offeredMission = new OfferedMission(mission.missionID, mission.offersMission, mission.acceptsMission);
|
||||
this->offeredMissions.push_back(offeredMission);
|
||||
this->offeredMissions.emplace_back(mission.missionID, mission.offersMission, mission.acceptsMission);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
MissionOfferComponent::~MissionOfferComponent() {
|
||||
for (auto* mission : this->offeredMissions) {
|
||||
if (mission) {
|
||||
delete mission;
|
||||
mission = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
offeredMissions.clear();
|
||||
}
|
||||
|
||||
void MissionOfferComponent::OnUse(Entity* originator) {
|
||||
OfferMissions(originator);
|
||||
}
|
||||
|
||||
void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifiedMissionId) {
|
||||
// First, get the entity's MissionComponent. If there is not one, then we cannot offer missions to this entity.
|
||||
auto* missionComponent = static_cast<MissionComponent*>(entity->GetComponent(eReplicaComponentType::MISSION));
|
||||
auto* missionComponent = entity->GetComponent<MissionComponent>();
|
||||
|
||||
if (!missionComponent) {
|
||||
LOG("Unable to get mission component for Entity %llu", entity->GetObjectID());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<uint32_t> offered{};
|
||||
|
||||
CDMissions info{};
|
||||
|
||||
if (specifiedMissionId > 0 && !Mission::IsValidMission(specifiedMissionId, info)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto* offeredMission : this->offeredMissions) {
|
||||
for (const auto offeredMission : this->offeredMissions) {
|
||||
if (specifiedMissionId > 0) {
|
||||
if (offeredMission->GetMissionId() != specifiedMissionId && !info.isRandom) {
|
||||
if (offeredMission.GetMissionId() != specifiedMissionId && !info.isRandom) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// First, check if we already have the mission
|
||||
const auto missionId = offeredMission->GetMissionId();
|
||||
const auto missionId = offeredMission.GetMissionId();
|
||||
|
||||
auto* mission = missionComponent->GetMission(missionId);
|
||||
|
||||
@@ -118,8 +103,6 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi
|
||||
if (mission->IsActive() || mission->IsReadyToComplete()) {
|
||||
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), missionId, m_Parent->GetObjectID());
|
||||
|
||||
offered.push_back(missionId);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -127,20 +110,13 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi
|
||||
const auto canAccept = MissionPrerequisites::CanAccept(missionId, missionComponent->GetMissions());
|
||||
|
||||
// Mission has not yet been accepted - check the prereqs
|
||||
if (!canAccept)
|
||||
continue;
|
||||
|
||||
if (!Mission::IsValidMission(missionId, info)) {
|
||||
continue;
|
||||
}
|
||||
if (!canAccept || !Mission::IsValidMission(missionId, info)) continue;
|
||||
|
||||
const auto& randomPool = info.randomPool;
|
||||
const auto isRandom = info.isRandom;
|
||||
|
||||
if (isRandom && randomPool.empty()) // This means the mission is part of a random pool of missions.
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// This means the mission is part of a random pool of missions.
|
||||
if (isRandom && randomPool.empty()) continue;
|
||||
|
||||
if (isRandom && !randomPool.empty()) {
|
||||
std::istringstream stream(randomPool);
|
||||
@@ -180,9 +156,7 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi
|
||||
sample == specifiedMissionId) {
|
||||
mission = missionComponent->GetMission(sample);
|
||||
|
||||
if (mission == nullptr || mission->IsAchievement()) {
|
||||
continue;
|
||||
}
|
||||
if (mission == nullptr || mission->IsAchievement()) continue;
|
||||
|
||||
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), sample, m_Parent->GetObjectID());
|
||||
|
||||
@@ -191,19 +165,18 @@ void MissionOfferComponent::OfferMissions(Entity* entity, const uint32_t specifi
|
||||
break;
|
||||
}
|
||||
|
||||
if (std::find(offered.begin(), offered.end(), sample) == offered.end() && MissionPrerequisites::CanAccept(sample, missionComponent->GetMissions())) {
|
||||
if (MissionPrerequisites::CanAccept(sample, missionComponent->GetMissions())) {
|
||||
canAcceptPool.push_back(sample);
|
||||
}
|
||||
}
|
||||
|
||||
// If the mission is already active or we already completed one of them today
|
||||
if (canAcceptPool.empty())
|
||||
continue;
|
||||
if (canAcceptPool.empty()) continue;
|
||||
|
||||
const auto selected = canAcceptPool[GeneralUtils::GenerateRandomNumber<int>(0, canAcceptPool.size() - 1)];
|
||||
|
||||
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), selected, m_Parent->GetObjectID());
|
||||
} else if (std::find(offered.begin(), offered.end(), missionId) == offered.end() && offeredMission->GetOfferMission()) {
|
||||
} else if (offeredMission.GetOffersMission()) {
|
||||
GameMessages::SendOfferMission(entity->GetObjectID(), entity->GetSystemAddress(), missionId, m_Parent->GetObjectID());
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user