Merge branch 'main' into npc-pathing

This commit is contained in:
David Markowitz 2023-07-27 21:16:13 -07:00
commit 8388fdf2a7
321 changed files with 3729 additions and 3728 deletions

View File

@ -36,22 +36,16 @@ jobs:
testPreset: "ci-${{matrix.os}}" testPreset: "ci-${{matrix.os}}"
- name: artifacts - name: artifacts
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
if: ${{ github.ref == 'ref/head/main' }}
with: with:
name: build-${{matrix.os}} name: build-${{matrix.os}}
path: | path: |
build build/*Server*
!build/tests build/*.ini
!build/Testing build/*.so
!build/CMakeFiles build/*.dll
!build/DartConfiguration.tcl build/vanity/
!build/CTestTestfile.cmake build/navmeshes/
!build/CMakeCache.txt build/migrations/
!build/build.ninja build/*.dcf
!build/_deps !build/*.pdb
!build/cmake_install.cmake !build/d*/
!build/*.a
!build/*.lib
!build/*.dir
!build/*.vcxproj
!build/*.vcxproj.filters

View File

@ -97,15 +97,56 @@ make_directory(${CMAKE_BINARY_DIR}/logs)
# Copy resource files on first build # Copy resource files on first build
set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf") set(RESOURCE_FILES "sharedconfig.ini" "authconfig.ini" "chatconfig.ini" "worldconfig.ini" "masterconfig.ini" "blacklist.dcf")
message(STATUS "Checking resource file integrity")
foreach (resource_file ${RESOURCE_FILES}) foreach (resource_file ${RESOURCE_FILES})
if (NOT EXISTS ${PROJECT_BINARY_DIR}/${resource_file}) set(file_size 0)
if (EXISTS ${PROJECT_BINARY_DIR}/${resource_file})
file(SIZE ${PROJECT_BINARY_DIR}/${resource_file} file_size)
endif()
if (${file_size} EQUAL 0)
configure_file( configure_file(
${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file} ${CMAKE_SOURCE_DIR}/resources/${resource_file} ${PROJECT_BINARY_DIR}/${resource_file}
COPYONLY COPYONLY
) )
message("Moved ${resource_file} to project binary directory") message(STATUS "Moved " ${resource_file} " to project binary directory")
elseif (resource_file MATCHES ".ini")
message(STATUS "Checking " ${resource_file} " for missing config options")
file(READ ${PROJECT_BINARY_DIR}/${resource_file} current_file_contents)
string(REPLACE "\\\n" "" current_file_contents ${current_file_contents})
string(REPLACE "\n" ";" current_file_contents ${current_file_contents})
set(parsed_current_file_contents "")
# Remove comment lines so they do not interfere with the variable parsing
foreach (line ${current_file_contents})
string(FIND ${line} "#" is_comment)
if (NOT ${is_comment} EQUAL 0)
string(APPEND parsed_current_file_contents ${line})
endif() endif()
endforeach() endforeach()
file(READ ${CMAKE_SOURCE_DIR}/resources/${resource_file} depot_file_contents)
string(REPLACE "\\\n" "" depot_file_contents ${depot_file_contents})
string(REPLACE "\n" ";" depot_file_contents ${depot_file_contents})
set(line_to_add "")
foreach (line ${depot_file_contents})
string(FIND ${line} "#" is_comment)
if (NOT ${is_comment} EQUAL 0)
string(REPLACE "=" ";" line_split ${line})
list(GET line_split 0 variable_name)
if (NOT ${parsed_current_file_contents} MATCHES ${variable_name})
message(STATUS "Adding missing config option " ${variable_name} " to " ${resource_file})
set(line_to_add ${line_to_add} ${line})
foreach (line_to_append ${line_to_add})
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n" ${line_to_append})
endforeach()
file(APPEND ${PROJECT_BINARY_DIR}/${resource_file} "\n")
endif()
set(line_to_add "")
else()
set(line_to_add ${line_to_add} ${line})
endif()
endforeach()
endif()
endforeach()
message(STATUS "Resource file integrity check complete")
# Copy navmesh data on first build and extract it # Copy navmesh data on first build and extract it
if (NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes/) if (NOT EXISTS ${PROJECT_BINARY_DIR}/navmeshes/)

View File

@ -1,6 +1,6 @@
PROJECT_VERSION_MAJOR=1 PROJECT_VERSION_MAJOR=1
PROJECT_VERSION_MINOR=0 PROJECT_VERSION_MINOR=1
PROJECT_VERSION_PATCH=4 PROJECT_VERSION_PATCH=0
# LICENSE # LICENSE
LICENSE=AGPL-3.0 LICENSE=AGPL-3.0
# The network version. # The network version.

View File

@ -338,7 +338,7 @@ This is a Work in Progress, but below are some quick links to documentaion for s
## Former Contributors ## Former Contributors
* TheMachine * TheMachine
* Matthew * Matthew
* [Raine](https://github.com/Rainebannister) * [Raine](https://github.com/uwainium)
* Bricknave * Bricknave
## Special Thanks ## Special Thanks

View File

@ -29,6 +29,7 @@ namespace Game {
dServer* server = nullptr; dServer* server = nullptr;
dConfig* config = nullptr; dConfig* config = nullptr;
bool shouldShutdown = false; bool shouldShutdown = false;
std::mt19937 randomEngine;
} }
dLogger* SetupLogger(); dLogger* SetupLogger();
@ -83,6 +84,8 @@ int main(int argc, char** argv) {
delete res; delete res;
delete stmt; delete stmt;
Game::randomEngine = std::mt19937(time(0));
//It's safe to pass 'localhost' here, as the IP is only used as the external IP. //It's safe to pass 'localhost' here, as the IP is only used as the external IP.
uint32_t maxClients = 50; uint32_t maxClients = 50;
uint32_t ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default. uint32_t ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default.
@ -171,6 +174,8 @@ dLogger* SetupLogger() {
} }
void HandlePacket(Packet* packet) { void HandlePacket(Packet* packet) {
if (packet->length < 4) return;
if (packet->data[0] == ID_USER_PACKET_ENUM) { if (packet->data[0] == ID_USER_PACKET_ENUM) {
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::SERVER) { if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::SERVER) {
if (static_cast<eServerMessageType>(packet->data[3]) == eServerMessageType::VERSION_CONFIRM) { if (static_cast<eServerMessageType>(packet->data[3]) == eServerMessageType::VERSION_CONFIRM) {

View File

@ -22,10 +22,9 @@ extern PlayerContainer playerContainer;
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) { void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
//Get from the packet which player we want to do something with: //Get from the packet which player we want to do something with:
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = 0; LWOOBJID playerID = 0;
inStream.Read(playerID); inStream.Read(playerID);
inStream.Read(playerID);
auto player = playerContainer.GetPlayerData(playerID); auto player = playerContainer.GetPlayerData(playerID);
if (!player) return; if (!player) return;
@ -99,10 +98,9 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
auto maxNumberOfBestFriendsAsString = Game::config->GetValue("max_number_of_best_friends"); auto maxNumberOfBestFriendsAsString = Game::config->GetValue("max_number_of_best_friends");
// If this config option doesn't exist, default to 5 which is what live used. // If this config option doesn't exist, default to 5 which is what live used.
auto maxNumberOfBestFriends = maxNumberOfBestFriendsAsString != "" ? std::stoi(maxNumberOfBestFriendsAsString) : 5U; auto maxNumberOfBestFriends = maxNumberOfBestFriendsAsString != "" ? std::stoi(maxNumberOfBestFriendsAsString) : 5U;
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID requestorPlayerID; LWOOBJID requestorPlayerID;
inStream.Read(requestorPlayerID); inStream.Read(requestorPlayerID);
inStream.Read(requestorPlayerID);
uint32_t spacing{}; uint32_t spacing{};
inStream.Read(spacing); inStream.Read(spacing);
std::string playerName = ""; std::string playerName = "";
@ -247,10 +245,9 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
} }
void ChatPacketHandler::HandleFriendResponse(Packet* packet) { void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID; LWOOBJID playerID;
inStream.Read(playerID); inStream.Read(playerID);
inStream.Read(playerID);
eAddFriendResponseCode clientResponseCode = static_cast<eAddFriendResponseCode>(packet->data[0x14]); eAddFriendResponseCode clientResponseCode = static_cast<eAddFriendResponseCode>(packet->data[0x14]);
std::string friendName = PacketUtils::ReadString(0x15, packet, true); std::string friendName = PacketUtils::ReadString(0x15, packet, true);
@ -323,10 +320,9 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
} }
void ChatPacketHandler::HandleRemoveFriend(Packet* packet) { void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID; LWOOBJID playerID;
inStream.Read(playerID); inStream.Read(playerID);
inStream.Read(playerID);
std::string friendName = PacketUtils::ReadString(0x14, packet, true); std::string friendName = PacketUtils::ReadString(0x14, packet, true);
//we'll have to query the db here to find the user, since you can delete them while they're offline. //we'll have to query the db here to find the user, since you can delete them while they're offline.
@ -381,10 +377,9 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
} }
void ChatPacketHandler::HandleChatMessage(Packet* packet) { void ChatPacketHandler::HandleChatMessage(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
inStream.Read(playerID);
auto* sender = playerContainer.GetPlayerData(playerID); auto* sender = playerContainer.GetPlayerData(playerID);
@ -501,10 +496,9 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
} }
void ChatPacketHandler::HandleTeamInvite(Packet* packet) { void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID; LWOOBJID playerID;
inStream.Read(playerID); inStream.Read(playerID);
inStream.Read(playerID);
std::string invitedPlayer = PacketUtils::ReadString(0x14, packet, true); std::string invitedPlayer = PacketUtils::ReadString(0x14, packet, true);
auto* player = playerContainer.GetPlayerData(playerID); auto* player = playerContainer.GetPlayerData(playerID);
@ -542,10 +536,9 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
} }
void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) { void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
inStream.Read(playerID);
uint32_t size = 0; uint32_t size = 0;
inStream.Read(size); inStream.Read(size);
char declined = 0; char declined = 0;
@ -576,10 +569,9 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
} }
void ChatPacketHandler::HandleTeamLeave(Packet* packet) { void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
inStream.Read(playerID);
uint32_t size = 0; uint32_t size = 0;
inStream.Read(size); inStream.Read(size);
@ -593,10 +585,9 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
} }
void ChatPacketHandler::HandleTeamKick(Packet* packet) { void ChatPacketHandler::HandleTeamKick(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
inStream.Read(playerID);
std::string kickedPlayer = PacketUtils::ReadString(0x14, packet, true); std::string kickedPlayer = PacketUtils::ReadString(0x14, packet, true);
@ -624,10 +615,9 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet) {
} }
void ChatPacketHandler::HandleTeamPromote(Packet* packet) { void ChatPacketHandler::HandleTeamPromote(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
inStream.Read(playerID);
std::string promotedPlayer = PacketUtils::ReadString(0x14, packet, true); std::string promotedPlayer = PacketUtils::ReadString(0x14, packet, true);
@ -647,10 +637,9 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet) {
} }
void ChatPacketHandler::HandleTeamLootOption(Packet* packet) { void ChatPacketHandler::HandleTeamLootOption(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
inStream.Read(playerID);
uint32_t size = 0; uint32_t size = 0;
inStream.Read(size); inStream.Read(size);
@ -671,10 +660,9 @@ void ChatPacketHandler::HandleTeamLootOption(Packet* packet) {
} }
void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) { void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID = LWOOBJID_EMPTY; LWOOBJID playerID = LWOOBJID_EMPTY;
inStream.Read(playerID); inStream.Read(playerID);
inStream.Read(playerID);
auto* team = playerContainer.GetTeam(playerID); auto* team = playerContainer.GetTeam(playerID);
auto* data = playerContainer.GetPlayerData(playerID); auto* data = playerContainer.GetPlayerData(playerID);

View File

@ -203,6 +203,8 @@ void HandlePacket(Packet* packet) {
Game::logger->Log("ChatServer", "A server is connecting, awaiting user list."); Game::logger->Log("ChatServer", "A server is connecting, awaiting user list.");
} }
if (packet->length < 4) return; // Nothing left to process. Need 4 bytes to continue.
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) { if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) {
switch (static_cast<eChatInternalMessageType>(packet->data[3])) { switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION: case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:

View File

@ -19,9 +19,8 @@ PlayerContainer::~PlayerContainer() {
} }
void PlayerContainer::InsertPlayer(Packet* packet) { void PlayerContainer::InsertPlayer(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
PlayerData* data = new PlayerData(); PlayerData* data = new PlayerData();
inStream.SetReadOffset(inStream.GetReadOffset() + 64);
inStream.Read(data->playerID); inStream.Read(data->playerID);
uint32_t len; uint32_t len;
@ -52,9 +51,8 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
} }
void PlayerContainer::RemovePlayer(Packet* packet) { void PlayerContainer::RemovePlayer(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID; LWOOBJID playerID;
inStream.Read(playerID); //skip header
inStream.Read(playerID); inStream.Read(playerID);
//Before they get kicked, we need to also send a message to their friends saying that they disconnected. //Before they get kicked, we need to also send a message to their friends saying that they disconnected.
@ -97,9 +95,8 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
} }
void PlayerContainer::MuteUpdate(Packet* packet) { void PlayerContainer::MuteUpdate(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID; LWOOBJID playerID;
inStream.Read(playerID); //skip header
inStream.Read(playerID); inStream.Read(playerID);
time_t expire = 0; time_t expire = 0;
inStream.Read(expire); inStream.Read(expire);
@ -118,9 +115,8 @@ void PlayerContainer::MuteUpdate(Packet* packet) {
} }
void PlayerContainer::CreateTeamServer(Packet* packet) { void PlayerContainer::CreateTeamServer(Packet* packet) {
CINSTREAM; CINSTREAM_SKIP_HEADER;
LWOOBJID playerID; LWOOBJID playerID;
inStream.Read(playerID); //skip header
inStream.Read(playerID); inStream.Read(playerID);
size_t membersSize = 0; size_t membersSize = 0;
inStream.Read(membersSize); inStream.Read(membersSize);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

367
dCommon/Amf3.h Normal file
View File

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

184
dCommon/AmfSerialize.cpp Normal file
View File

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

50
dCommon/AmfSerialize.h Normal file
View File

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

View File

@ -1,6 +1,6 @@
set(DCOMMON_SOURCES "AMFFormat.cpp" set(DCOMMON_SOURCES
"AMFDeserialize.cpp" "AMFDeserialize.cpp"
"AMFFormat_BitStream.cpp" "AmfSerialize.cpp"
"BinaryIO.cpp" "BinaryIO.cpp"
"dConfig.cpp" "dConfig.cpp"
"Diagnostics.cpp" "Diagnostics.cpp"

12
dCommon/DluAssert.h Normal file
View File

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

View File

@ -10,6 +10,8 @@ class dConfig;
class RakPeerInterface; class RakPeerInterface;
class AssetManager; class AssetManager;
struct SystemAddress; struct SystemAddress;
class EntityManager;
class dZoneManager;
namespace Game { namespace Game {
extern dLogger* logger; extern dLogger* logger;
@ -22,4 +24,6 @@ namespace Game {
extern AssetManager* assetManager; extern AssetManager* assetManager;
extern SystemAddress chatSysAddr; extern SystemAddress chatSysAddr;
extern bool shouldShutdown; extern bool shouldShutdown;
extern EntityManager* entityManager;
extern dZoneManager* zoneManager;
} }

View File

@ -111,29 +111,6 @@ namespace GeneralUtils {
*/ */
bool CheckBit(int64_t value, uint32_t index); bool CheckBit(int64_t value, uint32_t index);
// MARK: Random Number Generation
//! Generates a random number
/*!
\param min The minimum the generate from
\param max The maximum to generate to
*/
template <typename T>
inline T GenerateRandomNumber(std::size_t min, std::size_t max) {
// Make sure it is a numeric type
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
if constexpr (std::is_integral_v<T>) { // constexpr only necessary on first statement
std::uniform_int_distribution<T> distribution(min, max);
return distribution(Game::randomEngine);
} else if (std::is_floating_point_v<T>) {
std::uniform_real_distribution<T> distribution(min, max);
return distribution(Game::randomEngine);
}
return T();
}
bool ReplaceInString(std::string& str, const std::string& from, const std::string& to); bool ReplaceInString(std::string& str, const std::string& from, const std::string& to);
std::u16string ReadWString(RakNet::BitStream* inStream); std::u16string ReadWString(RakNet::BitStream* inStream);
@ -223,4 +200,42 @@ namespace GeneralUtils {
std::hash<T> h; std::hash<T> h;
s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2); s ^= h(v) + 0x9e3779b9 + (s << 6) + (s >> 2);
} }
// MARK: Random Number Generation
//! Generates a random number
/*!
\param min The minimum the generate from
\param max The maximum to generate to
*/
template <typename T>
inline T GenerateRandomNumber(std::size_t min, std::size_t max) {
// Make sure it is a numeric type
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
if constexpr (std::is_integral_v<T>) { // constexpr only necessary on first statement
std::uniform_int_distribution<T> distribution(min, max);
return distribution(Game::randomEngine);
} else if (std::is_floating_point_v<T>) {
std::uniform_real_distribution<T> distribution(min, max);
return distribution(Game::randomEngine);
}
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
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());
}
} }

View File

@ -28,8 +28,10 @@ constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate);
//========== MACROS =========== //========== MACROS ===========
#define HEADER_SIZE 8
#define CBITSTREAM RakNet::BitStream bitStream; #define CBITSTREAM RakNet::BitStream bitStream;
#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false); #define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false);
#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits());
#define CMSGHEADER PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG); #define CMSGHEADER PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
#define SEND_PACKET Game::server->Send(&bitStream, sysAddr, false); #define SEND_PACKET Game::server->Send(&bitStream, sysAddr, false);
#define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true); #define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);

View File

@ -273,7 +273,7 @@ enum class eGameMessageType : uint16_t {
TEAM_SET_LEADER = 1557, TEAM_SET_LEADER = 1557,
TEAM_INVITE_CONFIRM = 1558, TEAM_INVITE_CONFIRM = 1558,
TEAM_GET_STATUS_RESPONSE = 1559, TEAM_GET_STATUS_RESPONSE = 1559,
TEAM_ADD_PLAYER = 1526, TEAM_ADD_PLAYER = 1562,
TEAM_REMOVE_PLAYER = 1563, TEAM_REMOVE_PLAYER = 1563,
START_CELEBRATION_EFFECT = 1618, START_CELEBRATION_EFFECT = 1618,
ADD_BUFF = 1647, ADD_BUFF = 1647,

View File

@ -107,7 +107,7 @@ enum class eReplicaComponentType : uint32_t {
DONATION_VENDOR, DONATION_VENDOR,
COMBAT_MEDIATOR, COMBAT_MEDIATOR,
COMMENDATION_VENDOR, COMMENDATION_VENDOR,
UNKNOWN_103, GATE_RUSH_CONTROL,
RAIL_ACTIVATOR, RAIL_ACTIVATOR,
ROLLER, ROLLER,
PLAYER_FORCED_MOVEMENT, PLAYER_FORCED_MOVEMENT,
@ -119,7 +119,7 @@ enum class eReplicaComponentType : uint32_t {
UNKNOWN_112, UNKNOWN_112,
PROPERTY_PLAQUE, PROPERTY_PLAQUE,
BUILD_BORDER, BUILD_BORDER,
UNKOWN_115, UNKNOWN_115,
CULLING_PLANE, CULLING_PLANE,
DESTROYABLE = 1000 // Actually 7 DESTROYABLE = 1000 // Actually 7
}; };

View File

@ -16,9 +16,6 @@
// Enable this to cache all entries in each table for fast access, comes with more memory cost // Enable this to cache all entries in each table for fast access, comes with more memory cost
//#define CDCLIENT_CACHE_ALL //#define CDCLIENT_CACHE_ALL
// Enable this to skip some unused columns in some tables
#define UNUSED(v)
/*! /*!
\file CDClientDatabase.hpp \file CDClientDatabase.hpp
\brief An interface between the CDClient.sqlite file and the server \brief An interface between the CDClient.sqlite file and the server

View File

@ -40,7 +40,7 @@
CDClientManager::CDClientManager() { CDClientManager::CDClientManager() {
CDActivityRewardsTable::Instance(); CDActivityRewardsTable::Instance();
UNUSED(CDAnimationsTable::Instance()); CDAnimationsTable::Instance();
CDBehaviorParameterTable::Instance(); CDBehaviorParameterTable::Instance();
CDBehaviorTemplateTable::Instance(); CDBehaviorTemplateTable::Instance();
CDComponentsRegistryTable::Instance(); CDComponentsRegistryTable::Instance();

View File

@ -4,6 +4,8 @@
#include "Singleton.h" #include "Singleton.h"
#define UNUSED_TABLE(v)
/** /**
* Initialize the CDClient tables so they are all loaded into memory. * Initialize the CDClient tables so they are all loaded into memory.
*/ */

View File

@ -1,56 +1,83 @@
#include "CDAnimationsTable.h" #include "CDAnimationsTable.h"
#include "GeneralUtils.h"
#include "Game.h"
CDAnimationsTable::CDAnimationsTable(void) { bool CDAnimationsTable::CacheData(CppSQLite3Statement& queryToCache) {
auto tableData = queryToCache.execQuery();
// If we received a bad lookup, cache it anyways so we do not run the query again.
if (tableData.eof()) return false;
// First, get the size of the table do {
unsigned int size = 0; std::string animation_type = tableData.getStringField("animation_type", "");
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM Animations"); DluAssert(!animation_type.empty());
while (!tableSize.eof()) { AnimationGroupID animationGroupID = tableData.getIntField("animationGroupID", -1);
size = tableSize.getIntField(0, 0); DluAssert(animationGroupID != -1);
tableSize.nextRow(); CDAnimation entry;
}
tableSize.finalize();
// Reserve the size
this->entries.reserve(size);
// Now get the data
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Animations");
while (!tableData.eof()) {
CDAnimations entry;
entry.animationGroupID = tableData.getIntField("animationGroupID", -1);
entry.animation_type = tableData.getStringField("animation_type", "");
entry.animation_name = tableData.getStringField("animation_name", ""); entry.animation_name = tableData.getStringField("animation_name", "");
entry.chance_to_play = tableData.getFloatField("chance_to_play", -1.0f); entry.chance_to_play = tableData.getFloatField("chance_to_play", 1.0f);
entry.min_loops = tableData.getIntField("min_loops", -1); UNUSED_COLUMN(entry.min_loops = tableData.getIntField("min_loops", 0);)
entry.max_loops = tableData.getIntField("max_loops", -1); UNUSED_COLUMN(entry.max_loops = tableData.getIntField("max_loops", 0);)
entry.animation_length = tableData.getFloatField("animation_length", -1.0f); entry.animation_length = tableData.getFloatField("animation_length", 0.0f);
entry.hideEquip = tableData.getIntField("hideEquip", -1) == 1 ? true : false; UNUSED_COLUMN(entry.hideEquip = tableData.getIntField("hideEquip", 0) == 1;)
entry.ignoreUpperBody = tableData.getIntField("ignoreUpperBody", -1) == 1 ? true : false; UNUSED_COLUMN(entry.ignoreUpperBody = tableData.getIntField("ignoreUpperBody", 0) == 1;)
entry.restartable = tableData.getIntField("restartable", -1) == 1 ? true : false; UNUSED_COLUMN(entry.restartable = tableData.getIntField("restartable", 0) == 1;)
entry.face_animation_name = tableData.getStringField("face_animation_name", ""); UNUSED_COLUMN(entry.face_animation_name = tableData.getStringField("face_animation_name", "");)
entry.priority = tableData.getFloatField("priority", -1.0f); UNUSED_COLUMN(entry.priority = tableData.getFloatField("priority", 0.0f);)
entry.blendTime = tableData.getFloatField("blendTime", -1.0f); UNUSED_COLUMN(entry.blendTime = tableData.getFloatField("blendTime", 0.0f);)
this->entries.push_back(entry); this->animations[CDAnimationKey(animation_type, animationGroupID)].push_back(entry);
tableData.nextRow(); tableData.nextRow();
} } while (!tableData.eof());
tableData.finalize(); tableData.finalize();
return true;
} }
std::vector<CDAnimations> CDAnimationsTable::Query(std::function<bool(CDAnimations)> predicate) { void CDAnimationsTable::CacheAnimations(const CDAnimationKey animationKey) {
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Animations WHERE animationGroupID = ? and animation_type = ?");
std::vector<CDAnimations> data = cpplinq::from(this->entries) query.bind(1, static_cast<int32_t>(animationKey.second));
>> cpplinq::where(predicate) query.bind(2, animationKey.first.c_str());
>> cpplinq::to_vector(); // If we received a bad lookup, cache it anyways so we do not run the query again.
if (!CacheData(query)) {
return data; this->animations[animationKey];
}
} }
std::vector<CDAnimations> CDAnimationsTable::GetEntries(void) const { void CDAnimationsTable::CacheAnimationGroup(AnimationGroupID animationGroupID) {
return this->entries; auto animationEntryCached = this->animations.find(CDAnimationKey("", animationGroupID));
if (animationEntryCached != this->animations.end()) {
return;
} }
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM Animations WHERE animationGroupID = ?");
query.bind(1, static_cast<int32_t>(animationGroupID));
// Cache the query so we don't run the query again.
CacheData(query);
this->animations[CDAnimationKey("", animationGroupID)];
}
CDAnimationLookupResult CDAnimationsTable::GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID) {
CDAnimationKey animationKey(animationType, animationGroupID);
auto animationEntryCached = this->animations.find(animationKey);
if (animationEntryCached == this->animations.end()) {
this->CacheAnimations(animationKey);
}
auto animationEntry = this->animations.find(animationKey);
// If we have only one animation, return it regardless of the chance to play.
if (animationEntry->second.size() == 1) {
return CDAnimationLookupResult(animationEntry->second.front());
}
auto randomAnimation = GeneralUtils::GenerateRandomNumber<float>(0, 1);
for (auto& animationEntry : animationEntry->second) {
randomAnimation -= animationEntry.chance_to_play;
// This is how the client gets the random animation.
if (animationEntry.animation_name != previousAnimationName && randomAnimation <= 0.0f) return CDAnimationLookupResult(animationEntry);
}
return CDAnimationLookupResult();
}

View File

@ -1,33 +1,66 @@
#pragma once #pragma once
// Custom Classes
#include "CDTable.h" #include "CDTable.h"
#include <list>
struct CDAnimations { struct CDAnimation {
unsigned int animationGroupID; //!< The animation group ID // unsigned int animationGroupID;
std::string animation_type; //!< The animation type // std::string animation_type;
// The above two are a pair to represent a primary key in the map.
std::string animation_name; //!< The animation name std::string animation_name; //!< The animation name
float chance_to_play; //!< The chance to play the animation float chance_to_play; //!< The chance to play the animation
unsigned int min_loops; //!< The minimum number of loops UNUSED_COLUMN(unsigned int min_loops;) //!< The minimum number of loops
unsigned int max_loops; //!< The maximum number of loops UNUSED_COLUMN(unsigned int max_loops;) //!< The maximum number of loops
float animation_length; //!< The animation length float animation_length; //!< The animation length
bool hideEquip; //!< Whether or not to hide the equip UNUSED_COLUMN(bool hideEquip;) //!< Whether or not to hide the equip
bool ignoreUpperBody; //!< Whether or not to ignore the upper body UNUSED_COLUMN(bool ignoreUpperBody;) //!< Whether or not to ignore the upper body
bool restartable; //!< Whether or not the animation is restartable UNUSED_COLUMN(bool restartable;) //!< Whether or not the animation is restartable
std::string face_animation_name; //!< The face animation name UNUSED_COLUMN(std::string face_animation_name;) //!< The face animation name
float priority; //!< The priority UNUSED_COLUMN(float priority;) //!< The priority
float blendTime; //!< The blend time UNUSED_COLUMN(float blendTime;) //!< The blend time
}; };
typedef LookupResult<CDAnimation> CDAnimationLookupResult;
class CDAnimationsTable : public CDTable<CDAnimationsTable> { class CDAnimationsTable : public CDTable<CDAnimationsTable> {
private: typedef int32_t AnimationGroupID;
std::vector<CDAnimations> entries; typedef std::string AnimationID;
typedef std::pair<std::string, AnimationGroupID> CDAnimationKey;
public: public:
CDAnimationsTable(); /**
// Queries the table with a custom "where" clause * Given an animationType and the previousAnimationName played, return the next animationType to play.
std::vector<CDAnimations> Query(std::function<bool(CDAnimations)> predicate); * If there are more than 1 animationTypes that can be played, one is selected at random but also does not allow
* the previousAnimationName to be played twice.
*
* @param animationType The animationID to lookup
* @param previousAnimationName The previously played animation
* @param animationGroupID The animationGroupID to lookup
* @return CDAnimationLookupResult
*/
[[nodiscard]] CDAnimationLookupResult GetAnimation(const AnimationID& animationType, const std::string& previousAnimationName, const AnimationGroupID animationGroupID);
std::vector<CDAnimations> GetEntries(void) const; /**
* Cache a full AnimationGroup by its ID.
*/
void CacheAnimationGroup(AnimationGroupID animationGroupID);
private:
/**
* Cache all animations given a premade key
*/
void CacheAnimations(const CDAnimationKey animationKey);
/**
* Run the query responsible for caching the data.
* @param queryToCache
* @return true
* @return false
*/
bool CacheData(CppSQLite3Statement& queryToCache);
/**
* Each animation is key'd by its animationName and its animationGroupID. Each
* animation has a possible list of animations. This is because there can be animations have a percent chance to play so one is selected at random.
*/
std::map<CDAnimationKey, std::list<CDAnimation>> animations;
}; };

View File

@ -2,6 +2,7 @@
#include "CDClientDatabase.h" #include "CDClientDatabase.h"
#include "Singleton.h" #include "Singleton.h"
#include "DluAssert.h"
#include <functional> #include <functional>
#include <string> #include <string>
@ -15,6 +16,12 @@
#endif #endif
#include "cpplinq.hpp" #include "cpplinq.hpp"
// Used for legacy
#define UNUSED(x)
// Enable this to skip some unused columns in some tables
#define UNUSED_COLUMN(v)
#pragma warning (disable : 4244) //Disable double to float conversion warnings #pragma warning (disable : 4244) //Disable double to float conversion warnings
#pragma warning (disable : 4715) //Disable "not all control paths return a value" #pragma warning (disable : 4715) //Disable "not all control paths return a value"
@ -23,3 +30,15 @@ class CDTable : public Singleton<Table> {
protected: protected:
virtual ~CDTable() = default; virtual ~CDTable() = default;
}; };
template<class T>
class LookupResult {
typedef std::pair<T, bool> DataType;
public:
LookupResult() { m_data.first = T(); m_data.second = false; };
LookupResult(T& data) { m_data.first = data; m_data.second = true; };
inline const T& Data() { return m_data.first; };
inline const bool& FoundData() { return m_data.second; };
private:
DataType m_data;
};

View File

@ -241,7 +241,7 @@ void Character::DoQuickXMLDataParse() {
//To try and fix the AG landing into: //To try and fix the AG landing into:
if (m_ZoneID == 1000 && Game::server->GetZoneID() == 1100) { if (m_ZoneID == 1000 && Game::server->GetZoneID() == 1100) {
//sneakily insert our position: //sneakily insert our position:
auto pos = dZoneManager::Instance()->GetZone()->GetSpawnPos(); auto pos = Game::zoneManager->GetZone()->GetSpawnPos();
character->SetAttribute("lzx", pos.x); character->SetAttribute("lzx", pos.x);
character->SetAttribute("lzy", pos.y); character->SetAttribute("lzy", pos.y);
character->SetAttribute("lzz", pos.z); character->SetAttribute("lzz", pos.z);
@ -290,13 +290,13 @@ void Character::DoQuickXMLDataParse() {
void Character::UnlockEmote(int emoteID) { void Character::UnlockEmote(int emoteID) {
m_UnlockedEmotes.push_back(emoteID); m_UnlockedEmotes.push_back(emoteID);
GameMessages::SendSetEmoteLockState(EntityManager::Instance()->GetEntity(m_ObjectID), false, emoteID); GameMessages::SendSetEmoteLockState(Game::entityManager->GetEntity(m_ObjectID), false, emoteID);
} }
void Character::SetBuildMode(bool buildMode) { void Character::SetBuildMode(bool buildMode) {
m_BuildMode = buildMode; m_BuildMode = buildMode;
auto* controller = dZoneManager::Instance()->GetZoneControlObject(); auto* controller = Game::zoneManager->GetZoneControlObject();
controller->OnFireEventServerSide(m_OurEntity, buildMode ? "OnBuildModeEnter" : "OnBuildModeLeave"); controller->OnFireEventServerSide(m_OurEntity, buildMode ? "OnBuildModeEnter" : "OnBuildModeLeave");
} }
@ -312,7 +312,7 @@ void Character::SaveXMLToDatabase() {
character->SetAttribute("gm", static_cast<uint32_t>(m_GMLevel)); character->SetAttribute("gm", static_cast<uint32_t>(m_GMLevel));
character->SetAttribute("cc", m_Coins); character->SetAttribute("cc", m_Coins);
auto zoneInfo = dZoneManager::Instance()->GetZone()->GetZoneID(); auto zoneInfo = Game::zoneManager->GetZone()->GetZoneID();
// lzid garbage, binary concat of zoneID, zoneInstance and zoneClone // lzid garbage, binary concat of zoneID, zoneInstance and zoneClone
if (zoneInfo.GetMapID() != 0 && zoneInfo.GetCloneID() == 0) { if (zoneInfo.GetMapID() != 0 && zoneInfo.GetCloneID() == 0) {
uint64_t lzidConcat = zoneInfo.GetCloneID(); uint64_t lzidConcat = zoneInfo.GetCloneID();
@ -373,7 +373,7 @@ void Character::SaveXMLToDatabase() {
//Call upon the entity to update our xmlDoc: //Call upon the entity to update our xmlDoc:
if (!m_OurEntity) { if (!m_OurEntity) {
Game::logger->Log("Character", "We didn't have an entity set while saving! CHARACTER WILL NOT BE SAVED!"); Game::logger->Log("Character", "%i:%s didn't have an entity set while saving! CHARACTER WILL NOT BE SAVED!", this->GetID(), this->GetName().c_str());
return; return;
} }
@ -384,7 +384,7 @@ void Character::SaveXMLToDatabase() {
//For metrics, log the time it took to save: //For metrics, log the time it took to save:
auto end = std::chrono::system_clock::now(); auto end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed = end - start; std::chrono::duration<double> elapsed = end - start;
Game::logger->Log("Character", "Saved character to Database in: %fs", elapsed.count()); Game::logger->Log("Character", "%i:%s Saved character to Database in: %fs", this->GetID(), this->GetName().c_str(), elapsed.count());
} }
void Character::SetIsNewLogin() { void Character::SetIsNewLogin() {
@ -396,7 +396,7 @@ void Character::SetIsNewLogin() {
while (currentChild) { while (currentChild) {
if (currentChild->Attribute("si")) { if (currentChild->Attribute("si")) {
flags->DeleteChild(currentChild); flags->DeleteChild(currentChild);
Game::logger->Log("Character", "Removed isLoggedIn flag from character %i, saving character to database", GetID()); Game::logger->Log("Character", "Removed isLoggedIn flag from character %i:%s, saving character to database", GetID(), GetName().c_str());
WriteToDatabase(); WriteToDatabase();
} }
currentChild = currentChild->NextSiblingElement(); currentChild = currentChild->NextSiblingElement();
@ -418,13 +418,13 @@ void Character::WriteToDatabase() {
delete printer; delete printer;
} }
void Character::SetPlayerFlag(const int32_t flagId, const bool value) { void Character::SetPlayerFlag(const uint32_t flagId, const bool value) {
// If the flag is already set, we don't have to recalculate it // If the flag is already set, we don't have to recalculate it
if (GetPlayerFlag(flagId) == value) return; if (GetPlayerFlag(flagId) == value) return;
if (value) { if (value) {
// Update the mission component: // Update the mission component:
auto* player = EntityManager::Instance()->GetEntity(m_ObjectID); auto* player = Game::entityManager->GetEntity(m_ObjectID);
if (player != nullptr) { if (player != nullptr) {
auto* missionComponent = player->GetComponent<MissionComponent>(); auto* missionComponent = player->GetComponent<MissionComponent>();
@ -465,7 +465,7 @@ void Character::SetPlayerFlag(const int32_t flagId, const bool value) {
GameMessages::SendNotifyClientFlagChange(m_ObjectID, flagId, value, m_ParentUser->GetSystemAddress()); GameMessages::SendNotifyClientFlagChange(m_ObjectID, flagId, value, m_ParentUser->GetSystemAddress());
} }
bool Character::GetPlayerFlag(const int32_t flagId) const { bool Character::GetPlayerFlag(const uint32_t flagId) const {
// Calculate the index first // Calculate the index first
const auto flagIndex = uint32_t(std::floor(flagId / 64)); const auto flagIndex = uint32_t(std::floor(flagId / 64));
@ -602,7 +602,7 @@ void Character::SetCoins(int64_t newCoins, eLootSourceType lootSource) {
m_Coins = newCoins; m_Coins = newCoins;
GameMessages::SendSetCurrency(EntityManager::Instance()->GetEntity(m_ObjectID), m_Coins, 0, 0, 0, 0, true, lootSource); GameMessages::SendSetCurrency(Game::entityManager->GetEntity(m_ObjectID), m_Coins, 0, 0, 0, 0, true, lootSource);
} }
bool Character::HasBeenToWorld(LWOMAPID mapID) const { bool Character::HasBeenToWorld(LWOMAPID mapID) const {

View File

@ -415,14 +415,14 @@ public:
* @param flagId the ID of the flag to set * @param flagId the ID of the flag to set
* @param value the value to set for the flag * @param value the value to set for the flag
*/ */
void SetPlayerFlag(int32_t flagId, bool value); void SetPlayerFlag(uint32_t flagId, bool value);
/** /**
* Gets the value for a certain character flag * Gets the value for a certain character flag
* @param flagId the ID of the flag to get a value for * @param flagId the ID of the flag to get a value for
* @return the value of the flag given the ID (the default is false, obviously) * @return the value of the flag given the ID (the default is false, obviously)
*/ */
bool GetPlayerFlag(int32_t flagId) const; bool GetPlayerFlag(uint32_t flagId) const;
/** /**
* Notifies the character that they're now muted * Notifies the character that they're now muted

View File

@ -263,17 +263,17 @@ void Entity::Initialize() {
NiQuaternion rot; NiQuaternion rot;
const auto& targetSceneName = m_Character->GetTargetScene(); const auto& targetSceneName = m_Character->GetTargetScene();
auto* targetScene = EntityManager::Instance()->GetSpawnPointEntity(targetSceneName); auto* targetScene = Game::entityManager->GetSpawnPointEntity(targetSceneName);
if (m_Character->HasBeenToWorld(mapID) && targetSceneName.empty()) { if (m_Character->HasBeenToWorld(mapID) && targetSceneName.empty()) {
pos = m_Character->GetRespawnPoint(mapID); pos = m_Character->GetRespawnPoint(mapID);
rot = dZoneManager::Instance()->GetZone()->GetSpawnRot(); rot = Game::zoneManager->GetZone()->GetSpawnRot();
} else if (targetScene != nullptr) { } else if (targetScene != nullptr) {
pos = targetScene->GetPosition(); pos = targetScene->GetPosition();
rot = targetScene->GetRotation(); rot = targetScene->GetRotation();
} else { } else {
pos = dZoneManager::Instance()->GetZone()->GetSpawnPos(); pos = Game::zoneManager->GetZone()->GetSpawnPos();
rot = dZoneManager::Instance()->GetZone()->GetSpawnRot(); rot = Game::zoneManager->GetZone()->GetSpawnRot();
} }
controllablePhysics->SetPosition(pos); controllablePhysics->SetPosition(pos);
@ -386,8 +386,8 @@ void Entity::Initialize() {
comp->SetMaxCoins(currencyValues[0].maxvalue); comp->SetMaxCoins(currencyValues[0].maxvalue);
} }
// extraInfo overrides // extraInfo overrides. Client ORs the database smashable and the luz smashable.
comp->SetIsSmashable(GetVarAs<int32_t>(u"is_smashable") != 0); comp->SetIsSmashable(comp->GetIsSmashable() | (GetVarAs<int32_t>(u"is_smashable") != 0));
} }
} else { } else {
comp->SetHealth(1); comp->SetHealth(1);
@ -505,7 +505,7 @@ void Entity::Initialize() {
// ZoneControl script // ZoneControl script
if (m_TemplateID == 2365) { if (m_TemplateID == 2365) {
CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>(); CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>();
const auto zoneID = dZoneManager::Instance()->GetZoneID(); const auto zoneID = Game::zoneManager->GetZoneID();
const CDZoneTable* zoneData = zoneTable->Query(zoneID.GetMapID()); const CDZoneTable* zoneData = zoneTable->Query(zoneID.GetMapID());
if (zoneData != nullptr) { if (zoneData != nullptr) {
@ -595,8 +595,9 @@ void Entity::Initialize() {
m_Components.insert(std::make_pair(eReplicaComponentType::BOUNCER, comp)); m_Components.insert(std::make_pair(eReplicaComponentType::BOUNCER, comp));
} }
if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RENDER) > 0 && m_TemplateID != 2365) || m_Character) { int32_t renderComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RENDER);
RenderComponent* render = new RenderComponent(this); if ((renderComponentId > 0 && m_TemplateID != 2365) || m_Character) {
RenderComponent* render = new RenderComponent(this, renderComponentId);
m_Components.insert(std::make_pair(eReplicaComponentType::RENDER, render)); m_Components.insert(std::make_pair(eReplicaComponentType::RENDER, render));
} }
@ -690,7 +691,7 @@ void Entity::Initialize() {
} }
std::string pathName = GetVarAsString(u"attached_path"); std::string pathName = GetVarAsString(u"attached_path");
const Path* path = dZoneManager::Instance()->GetZone()->GetPath(pathName); const Path* path = Game::zoneManager->GetZone()->GetPath(pathName);
//Check to see if we have an attached path and add the appropiate component to handle it: //Check to see if we have an attached path and add the appropiate component to handle it:
if (path){ if (path){
@ -707,6 +708,13 @@ void Entity::Initialize() {
// TODO: create movementAIcomp and set path // TODO: create movementAIcomp and set path
} }
}*/ }*/
} else {
// else we still need to setup moving platform if it has a moving platform comp but no path
int32_t movingPlatformComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MOVING_PLATFORM, -1);
if (movingPlatformComponentId >= 0) {
MovingPlatformComponent* plat = new MovingPlatformComponent(this, pathName);
m_Components.insert(std::make_pair(eReplicaComponentType::MOVING_PLATFORM, plat));
}
} }
int proximityMonitorID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROXIMITY_MONITOR); int proximityMonitorID = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROXIMITY_MONITOR);
@ -727,7 +735,7 @@ void Entity::Initialize() {
} }
}); });
if (!m_Character && EntityManager::Instance()->GetGhostingEnabled()) { if (!m_Character && Game::entityManager->GetGhostingEnabled()) {
// Don't ghost what is likely large scene elements // Don't ghost what is likely large scene elements
if (HasComponent(eReplicaComponentType::SIMPLE_PHYSICS) && HasComponent(eReplicaComponentType::RENDER) && (m_Components.size() == 2 || (HasComponent(eReplicaComponentType::TRIGGER) && m_Components.size() == 3))) { if (HasComponent(eReplicaComponentType::SIMPLE_PHYSICS) && HasComponent(eReplicaComponentType::RENDER) && (m_Components.size() == 2 || (HasComponent(eReplicaComponentType::TRIGGER) && m_Components.size() == 3))) {
goto no_ghosting; goto no_ghosting;
@ -1276,12 +1284,12 @@ void Entity::Update(const float deltaTime) {
} }
if (m_ShouldDestroyAfterUpdate) { if (m_ShouldDestroyAfterUpdate) {
EntityManager::Instance()->DestroyEntity(this->GetObjectID()); Game::entityManager->DestroyEntity(this->GetObjectID());
} }
} }
void Entity::OnCollisionProximity(LWOOBJID otherEntity, const std::string& proxName, const std::string& status) { void Entity::OnCollisionProximity(LWOOBJID otherEntity, const std::string& proxName, const std::string& status) {
Entity* other = EntityManager::Instance()->GetEntity(otherEntity); Entity* other = Game::entityManager->GetEntity(otherEntity);
if (!other) return; if (!other) return;
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
@ -1295,7 +1303,7 @@ void Entity::OnCollisionProximity(LWOOBJID otherEntity, const std::string& proxN
} }
void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) { void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) {
auto* other = EntityManager::Instance()->GetEntity(otherEntity); auto* other = Game::entityManager->GetEntity(otherEntity);
if (!other) return; if (!other) return;
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
@ -1342,7 +1350,7 @@ void Entity::OnCollisionPhantom(const LWOOBJID otherEntity) {
} }
void Entity::OnCollisionLeavePhantom(const LWOOBJID otherEntity) { void Entity::OnCollisionLeavePhantom(const LWOOBJID otherEntity) {
auto* other = EntityManager::Instance()->GetEntity(otherEntity); auto* other = Game::entityManager->GetEntity(otherEntity);
if (!other) return; if (!other) return;
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
@ -1485,18 +1493,24 @@ void Entity::OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16s
} }
} }
void Entity::RequestActivityExit(Entity* sender, LWOOBJID player, bool canceled) {
for (CppScripts::Script* script : CppScripts::GetEntityScripts(this)) {
script->OnRequestActivityExit(sender, player, canceled);
}
}
void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType) { void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u16string& deathType) {
if (!m_PlayerIsReadyForUpdates) return; if (!m_PlayerIsReadyForUpdates) return;
auto* destroyableComponent = GetComponent<DestroyableComponent>(); auto* destroyableComponent = GetComponent<DestroyableComponent>();
if (destroyableComponent == nullptr) { if (destroyableComponent == nullptr) {
Kill(EntityManager::Instance()->GetEntity(source)); Kill(Game::entityManager->GetEntity(source));
return; return;
} }
auto* possessorComponent = GetComponent<PossessorComponent>(); auto* possessorComponent = GetComponent<PossessorComponent>();
if (possessorComponent) { if (possessorComponent) {
if (possessorComponent->GetPossessable() != LWOOBJID_EMPTY) { if (possessorComponent->GetPossessable() != LWOOBJID_EMPTY) {
auto* mount = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); auto* mount = Game::entityManager->GetEntity(possessorComponent->GetPossessable());
if (mount) possessorComponent->Dismount(mount, true); if (mount) possessorComponent->Dismount(mount, true);
} }
} }
@ -1524,20 +1538,20 @@ void Entity::Kill(Entity* murderer) {
} }
if (!IsPlayer()) { if (!IsPlayer()) {
EntityManager::Instance()->DestroyEntity(this); Game::entityManager->DestroyEntity(this);
} }
const auto& grpNameQBShowBricks = GetVar<std::string>(u"grpNameQBShowBricks"); const auto& grpNameQBShowBricks = GetVar<std::string>(u"grpNameQBShowBricks");
if (!grpNameQBShowBricks.empty()) { if (!grpNameQBShowBricks.empty()) {
auto spawners = dZoneManager::Instance()->GetSpawnersByName(grpNameQBShowBricks); auto spawners = Game::zoneManager->GetSpawnersByName(grpNameQBShowBricks);
Spawner* spawner = nullptr; Spawner* spawner = nullptr;
if (!spawners.empty()) { if (!spawners.empty()) {
spawner = spawners[0]; spawner = spawners[0];
} else { } else {
spawners = dZoneManager::Instance()->GetSpawnersInGroup(grpNameQBShowBricks); spawners = Game::zoneManager->GetSpawnersInGroup(grpNameQBShowBricks);
if (!spawners.empty()) { if (!spawners.empty()) {
spawner = spawners[0]; spawner = spawners[0];
@ -1705,7 +1719,7 @@ void Entity::CancelCallbackTimers() {
void Entity::ScheduleKillAfterUpdate(Entity* murderer) { void Entity::ScheduleKillAfterUpdate(Entity* murderer) {
//if (m_Info.spawner) m_Info.spawner->ScheduleKill(this); //if (m_Info.spawner) m_Info.spawner->ScheduleKill(this);
EntityManager::Instance()->ScheduleForKill(this); Game::entityManager->ScheduleForKill(this);
if (murderer) m_ScheduleKiller = murderer; if (murderer) m_ScheduleKiller = murderer;
} }
@ -1749,7 +1763,7 @@ void Entity::TriggerEvent(eTriggerEventType event, Entity* optionalTarget) {
Entity* Entity::GetOwner() const { Entity* Entity::GetOwner() const {
if (m_OwnerOverride != LWOOBJID_EMPTY) { if (m_OwnerOverride != LWOOBJID_EMPTY) {
auto* other = EntityManager::Instance()->GetEntity(m_OwnerOverride); auto* other = Game::entityManager->GetEntity(m_OwnerOverride);
if (other != nullptr) { if (other != nullptr) {
return other->GetOwner(); return other->GetOwner();
@ -1813,8 +1827,6 @@ bool Entity::IsSleeping() const {
const NiPoint3& Entity::GetPosition() const { const NiPoint3& Entity::GetPosition() const {
if (!this) return NiPoint3::ZERO;
auto* controllable = GetComponent<ControllablePhysicsComponent>(); auto* controllable = GetComponent<ControllablePhysicsComponent>();
if (controllable != nullptr) { if (controllable != nullptr) {
@ -1895,7 +1907,7 @@ void Entity::SetPosition(NiPoint3 position) {
vehicel->SetPosition(position); vehicel->SetPosition(position);
} }
EntityManager::Instance()->SerializeEntity(this); Game::entityManager->SerializeEntity(this);
} }
void Entity::SetRotation(NiQuaternion rotation) { void Entity::SetRotation(NiQuaternion rotation) {
@ -1923,7 +1935,7 @@ void Entity::SetRotation(NiQuaternion rotation) {
vehicel->SetRotation(rotation); vehicel->SetRotation(rotation);
} }
EntityManager::Instance()->SerializeEntity(this); Game::entityManager->SerializeEntity(this);
} }
bool Entity::GetBoolean(const std::u16string& name) const { bool Entity::GetBoolean(const std::u16string& name) const {
@ -1975,7 +1987,7 @@ std::vector<LWOOBJID>& Entity::GetTargetsInPhantom() {
for (auto i = 0u; i < m_TargetsInPhantom.size(); ++i) { for (auto i = 0u; i < m_TargetsInPhantom.size(); ++i) {
const auto id = m_TargetsInPhantom.at(i); const auto id = m_TargetsInPhantom.at(i);
auto* entity = EntityManager::Instance()->GetEntity(id); auto* entity = Game::entityManager->GetEntity(id);
if (entity == nullptr) { if (entity == nullptr) {
continue; continue;

View File

@ -207,6 +207,7 @@ public:
void OnMessageBoxResponse(Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData); void OnMessageBoxResponse(Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData);
void OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier); void OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier);
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 Smash(const LWOOBJID source = LWOOBJID_EMPTY, const eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"");
void Kill(Entity* murderer = nullptr); void Kill(Entity* murderer = nullptr);

View File

@ -25,8 +25,6 @@
#include "eReplicaComponentType.h" #include "eReplicaComponentType.h"
#include "eReplicaPacketType.h" #include "eReplicaPacketType.h"
EntityManager* EntityManager::m_Address = nullptr;
// Configure which zones have ghosting disabled, mostly small worlds. // Configure which zones have ghosting disabled, mostly small worlds.
std::vector<LWOMAPID> EntityManager::m_GhostingExcludedZones = { std::vector<LWOMAPID> EntityManager::m_GhostingExcludedZones = {
// Small zones // Small zones
@ -62,7 +60,7 @@ void EntityManager::Initialize() {
m_GhostingEnabled = std::find( m_GhostingEnabled = std::find(
m_GhostingExcludedZones.begin(), m_GhostingExcludedZones.begin(),
m_GhostingExcludedZones.end(), m_GhostingExcludedZones.end(),
dZoneManager::Instance()->GetZoneID().GetMapID() Game::zoneManager->GetZoneID().GetMapID()
) == m_GhostingExcludedZones.end(); ) == m_GhostingExcludedZones.end();
// grab hardcore mode settings and load them with sane defaults // grab hardcore mode settings and load them with sane defaults
@ -77,10 +75,7 @@ void EntityManager::Initialize() {
// If cloneID is not zero, then hardcore mode is disabled // If cloneID is not zero, then hardcore mode is disabled
// aka minigames and props // aka minigames and props
if (dZoneManager::Instance()->GetZoneID().GetCloneID() != 0) m_HardcoreMode = false; if (Game::zoneManager->GetZoneID().GetCloneID() != 0) m_HardcoreMode = false;
}
EntityManager::~EntityManager() {
} }
Entity* EntityManager::CreateEntity(EntityInfo info, User* user, Entity* parentEntity, const bool controller, const LWOOBJID explicitId) { Entity* EntityManager::CreateEntity(EntityInfo info, User* user, Entity* parentEntity, const bool controller, const LWOOBJID explicitId) {
@ -161,9 +156,7 @@ void EntityManager::DestroyEntity(const LWOOBJID& objectID) {
} }
void EntityManager::DestroyEntity(Entity* entity) { void EntityManager::DestroyEntity(Entity* entity) {
if (entity == nullptr) { if (!entity) return;
return;
}
entity->TriggerEvent(eTriggerEventType::DESTROY, entity); entity->TriggerEvent(eTriggerEventType::DESTROY, entity);
@ -182,15 +175,11 @@ void EntityManager::DestroyEntity(Entity* entity) {
ScheduleForDeletion(id); ScheduleForDeletion(id);
} }
void EntityManager::UpdateEntities(const float deltaTime) { void EntityManager::SerializeEntities() {
for (const auto& e : m_Entities) {
e.second->Update(deltaTime);
}
for (auto entry = m_EntitiesToSerialize.begin(); entry != m_EntitiesToSerialize.end(); entry++) { for (auto entry = m_EntitiesToSerialize.begin(); entry != m_EntitiesToSerialize.end(); entry++) {
auto* entity = GetEntity(*entry); auto* entity = GetEntity(*entry);
if (entity == nullptr) continue; if (!entity) continue;
m_SerializationCounter++; m_SerializationCounter++;
@ -212,11 +201,16 @@ void EntityManager::UpdateEntities(const float deltaTime) {
} }
} }
m_EntitiesToSerialize.clear(); m_EntitiesToSerialize.clear();
}
void EntityManager::KillEntities() {
for (auto entry = m_EntitiesToKill.begin(); entry != m_EntitiesToKill.end(); entry++) { for (auto entry = m_EntitiesToKill.begin(); entry != m_EntitiesToKill.end(); entry++) {
auto* entity = GetEntity(*entry); auto* entity = GetEntity(*entry);
if (!entity) continue; if (!entity) {
Game::logger->Log("EntityManager", "Attempting to kill null entity %llu", *entry);
continue;
}
if (entity->GetScheduledKiller()) { if (entity->GetScheduledKiller()) {
entity->Smash(entity->GetScheduledKiller()->GetObjectID(), eKillType::SILENT); entity->Smash(entity->GetScheduledKiller()->GetObjectID(), eKillType::SILENT);
@ -225,32 +219,41 @@ void EntityManager::UpdateEntities(const float deltaTime) {
} }
} }
m_EntitiesToKill.clear(); m_EntitiesToKill.clear();
}
void EntityManager::DeleteEntities() {
for (auto entry = m_EntitiesToDelete.begin(); entry != m_EntitiesToDelete.end(); entry++) { for (auto entry = m_EntitiesToDelete.begin(); entry != m_EntitiesToDelete.end(); entry++) {
// Get all this info first before we delete the player.
auto entityToDelete = GetEntity(*entry); auto entityToDelete = GetEntity(*entry);
if (entityToDelete) {
// Get all this info first before we delete the player.
auto networkIdToErase = entityToDelete->GetNetworkId(); auto networkIdToErase = entityToDelete->GetNetworkId();
const auto& ghostingToDelete = std::find(m_EntitiesToGhost.begin(), m_EntitiesToGhost.end(), entityToDelete); const auto& ghostingToDelete = std::find(m_EntitiesToGhost.begin(), m_EntitiesToGhost.end(), entityToDelete);
if (entityToDelete) {
// If we are a player run through the player destructor.
if (entityToDelete->IsPlayer()) {
delete dynamic_cast<Player*>(entityToDelete);
} else {
delete entityToDelete; delete entityToDelete;
}
entityToDelete = nullptr; entityToDelete = nullptr;
if (networkIdToErase != 0) m_LostNetworkIds.push(networkIdToErase); if (networkIdToErase != 0) m_LostNetworkIds.push(networkIdToErase);
}
if (ghostingToDelete != m_EntitiesToGhost.end()) m_EntitiesToGhost.erase(ghostingToDelete); if (ghostingToDelete != m_EntitiesToGhost.end()) m_EntitiesToGhost.erase(ghostingToDelete);
} else {
Game::logger->Log("EntityManager", "Attempted to delete non-existent entity %llu", *entry);
}
m_Entities.erase(*entry); m_Entities.erase(*entry);
} }
m_EntitiesToDelete.clear(); m_EntitiesToDelete.clear();
} }
void EntityManager::UpdateEntities(const float deltaTime) {
for (const auto& e : m_Entities) {
e.second->Update(deltaTime);
}
SerializeEntities();
KillEntities();
DeleteEntities();
}
Entity* EntityManager::GetEntity(const LWOOBJID& objectId) const { Entity* EntityManager::GetEntity(const LWOOBJID& objectId) const {
const auto& index = m_Entities.find(objectId); const auto& index = m_Entities.find(objectId);
@ -316,6 +319,11 @@ const std::unordered_map<std::string, LWOOBJID>& EntityManager::GetSpawnPointEnt
} }
void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr, const bool skipChecks) { void EntityManager::ConstructEntity(Entity* entity, const SystemAddress& sysAddr, const bool skipChecks) {
if (!entity) {
Game::logger->Log("EntityManager", "Attempted to construct null entity");
return;
}
if (entity->GetNetworkId() == 0) { if (entity->GetNetworkId() == 0) {
uint16_t networkId; uint16_t networkId;
@ -395,9 +403,7 @@ void EntityManager::ConstructAllEntities(const SystemAddress& sysAddr) {
} }
void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr) { void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr) {
if (entity->GetNetworkId() == 0) { if (!entity || entity->GetNetworkId() == 0) return;
return;
}
RakNet::BitStream stream; RakNet::BitStream stream;
@ -414,9 +420,7 @@ void EntityManager::DestructEntity(Entity* entity, const SystemAddress& sysAddr)
} }
void EntityManager::SerializeEntity(Entity* entity) { void EntityManager::SerializeEntity(Entity* entity) {
if (entity->GetNetworkId() == 0) { if (!entity || entity->GetNetworkId() == 0) return;
return;
}
if (std::find(m_EntitiesToSerialize.begin(), m_EntitiesToSerialize.end(), entity->GetObjectID()) == m_EntitiesToSerialize.end()) { if (std::find(m_EntitiesToSerialize.begin(), m_EntitiesToSerialize.end(), entity->GetObjectID()) == m_EntitiesToSerialize.end()) {
m_EntitiesToSerialize.push_back(entity->GetObjectID()); m_EntitiesToSerialize.push_back(entity->GetObjectID());

View File

@ -1,12 +1,13 @@
#ifndef ENTITYMANAGER_H #ifndef ENTITYMANAGER_H
#define ENTITYMANAGER_H #define ENTITYMANAGER_H
#include "dCommonVars.h"
#include <map> #include <map>
#include <stack> #include <stack>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include "dCommonVars.h"
class Entity; class Entity;
class EntityInfo; class EntityInfo;
class Player; class Player;
@ -17,19 +18,8 @@ struct SystemAddress;
class EntityManager { class EntityManager {
public: public:
static EntityManager* Instance() {
if (!m_Address) {
m_Address = new EntityManager();
m_Address->Initialize();
}
return m_Address;
}
void Initialize(); void Initialize();
~EntityManager();
void UpdateEntities(float deltaTime); void UpdateEntities(float deltaTime);
Entity* CreateEntity(EntityInfo info, User* user = nullptr, Entity* parentEntity = nullptr, bool controller = false, LWOOBJID explicitId = LWOOBJID_EMPTY); Entity* CreateEntity(EntityInfo info, User* user = nullptr, Entity* parentEntity = nullptr, bool controller = false, LWOOBJID explicitId = LWOOBJID_EMPTY);
void DestroyEntity(const LWOOBJID& objectID); void DestroyEntity(const LWOOBJID& objectID);
@ -85,7 +75,10 @@ public:
const uint32_t GetHardcoreUscoreEnemiesMultiplier() { return m_HardcoreUscoreEnemiesMultiplier; }; const uint32_t GetHardcoreUscoreEnemiesMultiplier() { return m_HardcoreUscoreEnemiesMultiplier; };
private: private:
static EntityManager* m_Address; //For singleton method void SerializeEntities();
void KillEntities();
void DeleteEntities();
static std::vector<LWOMAPID> m_GhostingExcludedZones; static std::vector<LWOMAPID> m_GhostingExcludedZones;
static std::vector<LOT> m_GhostingExcludedLOTs; static std::vector<LOT> m_GhostingExcludedLOTs;

View File

@ -1,5 +1,8 @@
#include "LeaderboardManager.h" #include "LeaderboardManager.h"
#include <sstream>
#include <utility> #include <utility>
#include "Database.h" #include "Database.h"
#include "EntityManager.h" #include "EntityManager.h"
#include "Character.h" #include "Character.h"
@ -10,461 +13,400 @@
#include "CDClientManager.h" #include "CDClientManager.h"
#include "GeneralUtils.h" #include "GeneralUtils.h"
#include "Entity.h" #include "Entity.h"
#include "LDFFormat.h"
#include "DluAssert.h"
#include "CDActivitiesTable.h" #include "CDActivitiesTable.h"
#include "Metrics.hpp"
Leaderboard::Leaderboard(uint32_t gameID, uint32_t infoType, bool weekly, std::vector<LeaderboardEntry> entries, namespace LeaderboardManager {
LWOOBJID relatedPlayer, LeaderboardType leaderboardType) { std::map<GameID, Leaderboard::Type> leaderboardCache;
this->relatedPlayer = relatedPlayer; }
Leaderboard::Leaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, LWOOBJID relatedPlayer, const Leaderboard::Type leaderboardType) {
this->gameID = gameID; this->gameID = gameID;
this->weekly = weekly; this->weekly = weekly;
this->infoType = infoType; this->infoType = infoType;
this->entries = std::move(entries);
this->leaderboardType = leaderboardType; this->leaderboardType = leaderboardType;
this->relatedPlayer = relatedPlayer;
} }
std::u16string Leaderboard::ToString() const { Leaderboard::~Leaderboard() {
std::string leaderboard; Clear();
leaderboard += "ADO.Result=7:1\n";
leaderboard += "Result.Count=1:1\n";
leaderboard += "Result[0].Index=0:RowNumber\n";
leaderboard += "Result[0].RowCount=1:" + std::to_string(entries.size()) + "\n";
auto index = 0;
for (const auto& entry : entries) {
leaderboard += "Result[0].Row[" + std::to_string(index) + "].LastPlayed=8:" + std::to_string(entry.lastPlayed) + "\n";
leaderboard += "Result[0].Row[" + std::to_string(index) + "].CharacterID=8:" + std::to_string(entry.playerID) + "\n";
leaderboard += "Result[0].Row[" + std::to_string(index) + "].NumPlayed=1:1\n";
leaderboard += "Result[0].Row[" + std::to_string(index) + "].RowNumber=8:" + std::to_string(entry.placement) + "\n";
leaderboard += "Result[0].Row[" + std::to_string(index) + "].Time=1:" + std::to_string(entry.time) + "\n";
// Only these minigames have a points system
if (leaderboardType == Survival || leaderboardType == ShootingGallery) {
leaderboard += "Result[0].Row[" + std::to_string(index) + "].Points=1:" + std::to_string(entry.score) + "\n";
} else if (leaderboardType == SurvivalNS) {
leaderboard += "Result[0].Row[" + std::to_string(index) + "].Wave=1:" + std::to_string(entry.score) + "\n";
} }
leaderboard += "Result[0].Row[" + std::to_string(index) + "].name=0:" + entry.playerName + "\n"; void Leaderboard::Clear() {
index++; for (auto& entry : entries) for (auto ldfData : entry) delete ldfData;
} }
return GeneralUtils::UTF8ToUTF16(leaderboard); inline void WriteLeaderboardRow(std::ostringstream& leaderboard, const uint32_t& index, LDFBaseData* data) {
leaderboard << "\nResult[0].Row[" << index << "]." << data->GetString();
} }
std::vector<LeaderboardEntry> Leaderboard::GetEntries() { void Leaderboard::Serialize(RakNet::BitStream* bitStream) const {
return entries; bitStream->Write(gameID);
bitStream->Write(infoType);
std::ostringstream leaderboard;
leaderboard << "ADO.Result=7:1"; // Unused in 1.10.64, but is in captures
leaderboard << "\nResult.Count=1:1"; // number of results, always 1
if (!this->entries.empty()) leaderboard << "\nResult[0].Index=0:RowNumber"; // "Primary key". Live doesn't include this if there are no entries.
leaderboard << "\nResult[0].RowCount=1:" << entries.size();
int32_t rowNumber = 0;
for (auto& entry : entries) {
for (auto* data : entry) {
WriteLeaderboardRow(leaderboard, rowNumber, data);
}
rowNumber++;
} }
uint32_t Leaderboard::GetGameID() const { // Serialize the thing to a BitStream
return gameID; uint32_t leaderboardSize = leaderboard.tellp();
bitStream->Write<uint32_t>(leaderboardSize);
// Doing this all in 1 call so there is no possbility of a dangling pointer.
bitStream->WriteAlignedBytes(reinterpret_cast<const unsigned char*>(GeneralUtils::ASCIIToUTF16(leaderboard.str()).c_str()), leaderboardSize * sizeof(char16_t));
if (leaderboardSize > 0) bitStream->Write<uint16_t>(0);
bitStream->Write0();
bitStream->Write0();
} }
uint32_t Leaderboard::GetInfoType() const { void Leaderboard::QueryToLdf(std::unique_ptr<sql::ResultSet>& rows) {
return infoType; Clear();
if (rows->rowsCount() == 0) return;
this->entries.reserve(rows->rowsCount());
while (rows->next()) {
constexpr int32_t MAX_NUM_DATA_PER_ROW = 9;
this->entries.push_back(std::vector<LDFBaseData*>());
auto& entry = this->entries.back();
entry.reserve(MAX_NUM_DATA_PER_ROW);
entry.push_back(new LDFData<uint64_t>(u"CharacterID", rows->getInt("character_id")));
entry.push_back(new LDFData<uint64_t>(u"LastPlayed", rows->getUInt64("lastPlayed")));
entry.push_back(new LDFData<int32_t>(u"NumPlayed", rows->getInt("timesPlayed")));
entry.push_back(new LDFData<std::u16string>(u"name", GeneralUtils::ASCIIToUTF16(rows->getString("name").c_str())));
entry.push_back(new LDFData<uint64_t>(u"RowNumber", rows->getInt("ranking")));
switch (leaderboardType) {
case Type::ShootingGallery:
entry.push_back(new LDFData<int32_t>(u"Score", rows->getInt("primaryScore")));
// Score:1
entry.push_back(new LDFData<int32_t>(u"Streak", rows->getInt("secondaryScore")));
// Streak:1
entry.push_back(new LDFData<float>(u"HitPercentage", (rows->getInt("tertiaryScore") / 100.0f)));
// HitPercentage:3 between 0 and 1
break;
case Type::Racing:
entry.push_back(new LDFData<float>(u"BestTime", rows->getDouble("primaryScore")));
// BestLapTime:3
entry.push_back(new LDFData<float>(u"BestLapTime", rows->getDouble("secondaryScore")));
// BestTime:3
entry.push_back(new LDFData<int32_t>(u"License", 1));
// License:1 - 1 if player has completed mission 637 and 0 otherwise
entry.push_back(new LDFData<int32_t>(u"NumWins", rows->getInt("numWins")));
// NumWins:1
break;
case Type::UnusedLeaderboard4:
entry.push_back(new LDFData<int32_t>(u"Points", rows->getInt("primaryScore")));
// Points:1
break;
case Type::MonumentRace:
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("primaryScore")));
// Time:1(?)
break;
case Type::FootRace:
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("primaryScore")));
// Time:1
break;
case Type::Survival:
entry.push_back(new LDFData<int32_t>(u"Points", rows->getInt("primaryScore")));
// Points:1
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("secondaryScore")));
// Time:1
break;
case Type::SurvivalNS:
entry.push_back(new LDFData<int32_t>(u"Wave", rows->getInt("primaryScore")));
// Wave:1
entry.push_back(new LDFData<int32_t>(u"Time", rows->getInt("secondaryScore")));
// Time:1
break;
case Type::Donations:
entry.push_back(new LDFData<int32_t>(u"Points", rows->getInt("primaryScore")));
// Score:1
break;
case Type::None:
// This type is included here simply to resolve a compiler warning on mac about unused enum types
break;
default:
break;
}
}
} }
void Leaderboard::Send(LWOOBJID targetID) const { const std::string_view Leaderboard::GetOrdering(Leaderboard::Type leaderboardType) {
auto* player = EntityManager::Instance()->GetEntity(relatedPlayer); // Use a switch case and return desc for all 3 columns if higher is better and asc if lower is better
switch (leaderboardType) {
case Type::Racing:
case Type::MonumentRace:
return "primaryScore ASC, secondaryScore ASC, tertiaryScore ASC";
case Type::Survival:
return Game::config->GetValue("classic_survival_scoring") == "1" ?
"secondaryScore DESC, primaryScore DESC, tertiaryScore DESC" :
"primaryScore DESC, secondaryScore DESC, tertiaryScore DESC";
case Type::SurvivalNS:
return "primaryScore DESC, secondaryScore ASC, tertiaryScore DESC";
case Type::ShootingGallery:
case Type::FootRace:
case Type::UnusedLeaderboard4:
case Type::Donations:
case Type::None:
default:
return "primaryScore DESC, secondaryScore DESC, tertiaryScore DESC";
}
}
void Leaderboard::SetupLeaderboard(bool weekly, uint32_t resultStart, uint32_t resultEnd) {
resultStart++;
resultEnd++;
// We need everything except 1 column so i'm selecting * from leaderboard
const std::string queryBase =
R"QUERY(
WITH leaderboardsRanked AS (
SELECT leaderboard.*, charinfo.name,
RANK() OVER
(
ORDER BY %s, UNIX_TIMESTAMP(last_played) ASC, id DESC
) AS ranking
FROM leaderboard JOIN charinfo on charinfo.id = leaderboard.character_id
WHERE game_id = ? %s
),
myStanding AS (
SELECT
ranking as myRank
FROM leaderboardsRanked
WHERE id = ?
),
lowestRanking AS (
SELECT MAX(ranking) AS lowestRank
FROM leaderboardsRanked
)
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)
AND
LEAST(GREATEST(myRank + 5, %i), lowestRanking.lowestRank)
ORDER BY ranking ASC;
)QUERY";
std::string friendsFilter =
R"QUERY(
AND (
character_id IN (
SELECT fr.requested_player FROM (
SELECT CASE
WHEN player_id = ? THEN friend_id
WHEN friend_id = ? THEN player_id
END AS requested_player
FROM friends
) AS fr
JOIN charinfo AS ci
ON ci.id = fr.requested_player
WHERE fr.requested_player IS NOT NULL
)
OR character_id = ?
)
)QUERY";
std::string weeklyFilter = " AND UNIX_TIMESTAMP(last_played) BETWEEN UNIX_TIMESTAMP(date_sub(now(),INTERVAL 1 WEEK)) AND UNIX_TIMESTAMP(now()) ";
std::string filter;
// Setup our filter based on the query type
if (this->infoType == InfoType::Friends) filter += friendsFilter;
if (this->weekly) filter += weeklyFilter;
const auto orderBase = GetOrdering(this->leaderboardType);
// For top query, we want to just rank all scores, but for all others we need the scores around a specific player
std::string baseLookup;
if (this->infoType == InfoType::Top) {
baseLookup = "SELECT id, last_played FROM leaderboard WHERE game_id = ? " + (this->weekly ? weeklyFilter : std::string("")) + " ORDER BY ";
baseLookup += orderBase.data();
} else {
baseLookup = "SELECT id, last_played FROM leaderboard WHERE game_id = ? " + (this->weekly ? weeklyFilter : std::string("")) + " AND character_id = ";
baseLookup += std::to_string(static_cast<uint32_t>(this->relatedPlayer));
}
baseLookup += " LIMIT 1";
Game::logger->LogDebug("LeaderboardManager", "query is %s", baseLookup.c_str());
std::unique_ptr<sql::PreparedStatement> baseQuery(Database::CreatePreppedStmt(baseLookup));
baseQuery->setInt(1, this->gameID);
std::unique_ptr<sql::ResultSet> baseResult(baseQuery->executeQuery());
if (!baseResult->next()) return; // In this case, there are no entries in the leaderboard for this game.
uint32_t relatedPlayerLeaderboardId = baseResult->getInt("id");
// Create and execute the actual save here. Using a heap allocated buffer to avoid stack overflow
constexpr uint16_t STRING_LENGTH = 4096;
std::unique_ptr<char[]> lookupBuffer = std::make_unique<char[]>(STRING_LENGTH);
int32_t res = snprintf(lookupBuffer.get(), STRING_LENGTH, queryBase.c_str(), orderBase.data(), filter.c_str(), resultStart, resultEnd);
DluAssert(res != -1);
std::unique_ptr<sql::PreparedStatement> query(Database::CreatePreppedStmt(lookupBuffer.get()));
Game::logger->LogDebug("LeaderboardManager", "Query is %s vars are %i %i %i", lookupBuffer.get(), this->gameID, this->relatedPlayer, relatedPlayerLeaderboardId);
query->setInt(1, this->gameID);
if (this->infoType == InfoType::Friends) {
query->setInt(2, this->relatedPlayer);
query->setInt(3, this->relatedPlayer);
query->setInt(4, this->relatedPlayer);
query->setInt(5, relatedPlayerLeaderboardId);
} else {
query->setInt(2, relatedPlayerLeaderboardId);
}
std::unique_ptr<sql::ResultSet> result(query->executeQuery());
QueryToLdf(result);
}
void Leaderboard::Send(const LWOOBJID targetID) const {
auto* player = Game::entityManager->GetEntity(relatedPlayer);
if (player != nullptr) { if (player != nullptr) {
GameMessages::SendActivitySummaryLeaderboardData(targetID, this, player->GetSystemAddress()); GameMessages::SendActivitySummaryLeaderboardData(targetID, this, player->GetSystemAddress());
} }
} }
void LeaderboardManager::SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t score, uint32_t time) { std::string FormatInsert(const Leaderboard::Type& type, const Score& score, const bool useUpdate) {
const auto* player = EntityManager::Instance()->GetEntity(playerID); std::string insertStatement;
if (player == nullptr) if (useUpdate) {
return; insertStatement =
R"QUERY(
UPDATE leaderboard
SET primaryScore = %f, secondaryScore = %f, tertiaryScore = %f,
timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;
)QUERY";
} else {
insertStatement =
R"QUERY(
INSERT leaderboard SET
primaryScore = %f, secondaryScore = %f, tertiaryScore = %f,
character_id = ?, game_id = ?;
)QUERY";
}
auto* character = player->GetCharacter(); constexpr uint16_t STRING_LENGTH = 400;
if (character == nullptr) // Then fill in our score
return; char finishedQuery[STRING_LENGTH];
int32_t res = snprintf(finishedQuery, STRING_LENGTH, insertStatement.c_str(), score.GetPrimaryScore(), score.GetSecondaryScore(), score.GetTertiaryScore());
DluAssert(res != -1);
return finishedQuery;
}
auto* select = Database::CreatePreppedStmt("SELECT time, score FROM leaderboard WHERE character_id = ? AND game_id = ?;"); void LeaderboardManager::SaveScore(const LWOOBJID& playerID, const GameID activityId, const float primaryScore, const float secondaryScore, const float tertiaryScore) {
const Leaderboard::Type leaderboardType = GetLeaderboardType(activityId);
auto* lookup = "SELECT * FROM leaderboard WHERE character_id = ? AND game_id = ?;";
select->setUInt64(1, character->GetID()); std::unique_ptr<sql::PreparedStatement> query(Database::CreatePreppedStmt(lookup));
select->setInt(2, gameID); query->setInt(1, playerID);
query->setInt(2, activityId);
auto any = false; std::unique_ptr<sql::ResultSet> myScoreResult(query->executeQuery());
auto* result = select->executeQuery();
auto leaderboardType = GetLeaderboardType(gameID);
// Check if the new score is a high score
while (result->next()) {
any = true;
const auto storedTime = result->getInt(1);
const auto storedScore = result->getInt(2);
auto highscore = true;
bool classicSurvivalScoring = Game::config->GetValue("classic_survival_scoring") == "1";
std::string saveQuery("UPDATE leaderboard SET timesPlayed = timesPlayed + 1 WHERE character_id = ? AND game_id = ?;");
Score newScore(primaryScore, secondaryScore, tertiaryScore);
if (myScoreResult->next()) {
Score oldScore;
bool lowerScoreBetter = false;
switch (leaderboardType) { switch (leaderboardType) {
case ShootingGallery: // Higher score better
if (score <= storedScore) case Leaderboard::Type::ShootingGallery: {
highscore = false; oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
oldScore.SetTertiaryScore(myScoreResult->getInt("tertiaryScore"));
break; break;
case Racing: }
if (time >= storedTime) case Leaderboard::Type::FootRace: {
highscore = false; oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
break; break;
case MonumentRace: }
if (time >= storedTime) case Leaderboard::Type::Survival: {
highscore = false; oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
break; break;
case FootRace: }
if (time <= storedTime) case Leaderboard::Type::SurvivalNS: {
highscore = false; oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
break; break;
case Survival: }
if (classicSurvivalScoring) { case Leaderboard::Type::UnusedLeaderboard4:
if (time <= storedTime) { // Based on time (LU live) case Leaderboard::Type::Donations: {
highscore = false; oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
break;
}
case Leaderboard::Type::Racing: {
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
oldScore.SetSecondaryScore(myScoreResult->getInt("secondaryScore"));
// For wins we dont care about the score, just the time, so zero out the tertiary.
// Wins are updated later.
oldScore.SetTertiaryScore(0);
newScore.SetTertiaryScore(0);
lowerScoreBetter = true;
break;
}
case Leaderboard::Type::MonumentRace: {
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
lowerScoreBetter = true;
// Do score checking here
break;
}
case Leaderboard::Type::None:
default:
Game::logger->Log("LeaderboardManager", "Unknown leaderboard type %i for game %i. Cannot save score!", leaderboardType, activityId);
return;
}
bool newHighScore = lowerScoreBetter ? newScore < oldScore : newScore > oldScore;
// Nimbus station has a weird leaderboard where we need a custom scoring system
if (leaderboardType == Leaderboard::Type::SurvivalNS) {
newHighScore = newScore.GetPrimaryScore() > oldScore.GetPrimaryScore() ||
(newScore.GetPrimaryScore() == oldScore.GetPrimaryScore() && newScore.GetSecondaryScore() < oldScore.GetSecondaryScore());
} else if (leaderboardType == Leaderboard::Type::Survival && Game::config->GetValue("classic_survival_scoring") == "1") {
Score oldScoreFlipped(oldScore.GetSecondaryScore(), oldScore.GetPrimaryScore());
Score newScoreFlipped(newScore.GetSecondaryScore(), newScore.GetPrimaryScore());
newHighScore = newScoreFlipped > oldScoreFlipped;
}
if (newHighScore) {
saveQuery = FormatInsert(leaderboardType, newScore, true);
} }
} else { } else {
if (score <= storedScore) // Based on score (DLU) saveQuery = FormatInsert(leaderboardType, newScore, false);
highscore = false;
}
break;
case SurvivalNS:
if (!(score > storedScore || (time < storedTime && score >= storedScore)))
highscore = false;
break;
default:
highscore = false;
} }
Game::logger->Log("LeaderboardManager", "save query %s %i %i", saveQuery.c_str(), playerID, activityId);
std::unique_ptr<sql::PreparedStatement> saveStatement(Database::CreatePreppedStmt(saveQuery));
saveStatement->setInt(1, playerID);
saveStatement->setInt(2, activityId);
saveStatement->execute();
if (!highscore) { // track wins separately
delete select; if (leaderboardType == Leaderboard::Type::Racing && tertiaryScore != 0.0f) {
delete result; std::unique_ptr<sql::PreparedStatement> winUpdate(Database::CreatePreppedStmt("UPDATE leaderboard SET numWins = numWins + 1 WHERE character_id = ? AND game_id = ?;"));
return; winUpdate->setInt(1, playerID);
winUpdate->setInt(2, activityId);
winUpdate->execute();
} }
} }
delete select; void LeaderboardManager::SendLeaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, const LWOOBJID playerID, const LWOOBJID targetID, const uint32_t resultStart, const uint32_t resultEnd) {
delete result; Leaderboard leaderboard(gameID, infoType, weekly, playerID, GetLeaderboardType(gameID));
leaderboard.SetupLeaderboard(weekly, resultStart, resultEnd);
if (any) { leaderboard.Send(targetID);
auto* statement = Database::CreatePreppedStmt("UPDATE leaderboard SET time = ?, score = ?, last_played=SYSDATE() WHERE character_id = ? AND game_id = ?;");
statement->setInt(1, time);
statement->setInt(2, score);
statement->setUInt64(3, character->GetID());
statement->setInt(4, gameID);
statement->execute();
delete statement;
} else {
// Note: last_played will be set to SYSDATE() by default when inserting into leaderboard
auto* statement = Database::CreatePreppedStmt("INSERT INTO leaderboard (character_id, game_id, time, score) VALUES (?, ?, ?, ?);");
statement->setUInt64(1, character->GetID());
statement->setInt(2, gameID);
statement->setInt(3, time);
statement->setInt(4, score);
statement->execute();
delete statement;
}
} }
Leaderboard* LeaderboardManager::GetLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID playerID) { Leaderboard::Type LeaderboardManager::GetLeaderboardType(const GameID gameID) {
auto leaderboardType = GetLeaderboardType(gameID); auto lookup = leaderboardCache.find(gameID);
if (lookup != leaderboardCache.end()) return lookup->second;
std::string query;
bool classicSurvivalScoring = Game::config->GetValue("classic_survival_scoring") == "1";
switch (infoType) {
case InfoType::Standings:
switch (leaderboardType) {
case ShootingGallery:
query = standingsScoreQuery; // Shooting gallery is based on the highest score.
break;
case FootRace:
query = standingsTimeQuery; // The higher your time, the better for FootRace.
break;
case Survival:
query = classicSurvivalScoring ? standingsTimeQuery : standingsScoreQuery;
break;
case SurvivalNS:
query = standingsScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time.
break;
default:
query = standingsTimeQueryAsc; // MonumentRace and Racing are based on the shortest time.
}
break;
case InfoType::Friends:
switch (leaderboardType) {
case ShootingGallery:
query = friendsScoreQuery; // Shooting gallery is based on the highest score.
break;
case FootRace:
query = friendsTimeQuery; // The higher your time, the better for FootRace.
break;
case Survival:
query = classicSurvivalScoring ? friendsTimeQuery : friendsScoreQuery;
break;
case SurvivalNS:
query = friendsScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time.
break;
default:
query = friendsTimeQueryAsc; // MonumentRace and Racing are based on the shortest time.
}
break;
default:
switch (leaderboardType) {
case ShootingGallery:
query = topPlayersScoreQuery; // Shooting gallery is based on the highest score.
break;
case FootRace:
query = topPlayersTimeQuery; // The higher your time, the better for FootRace.
break;
case Survival:
query = classicSurvivalScoring ? topPlayersTimeQuery : topPlayersScoreQuery;
break;
case SurvivalNS:
query = topPlayersScoreQueryAsc; // BoNS is scored by highest wave (score) first, then time.
break;
default:
query = topPlayersTimeQueryAsc; // MonumentRace and Racing are based on the shortest time.
}
}
auto* statement = Database::CreatePreppedStmt(query);
statement->setUInt(1, gameID);
// Only the standings and friends leaderboards require the character ID to be set
if (infoType == Standings || infoType == Friends) {
auto characterID = 0;
const auto* player = EntityManager::Instance()->GetEntity(playerID);
if (player != nullptr) {
auto* character = player->GetCharacter();
if (character != nullptr)
characterID = character->GetID();
}
statement->setUInt64(2, characterID);
}
auto* res = statement->executeQuery();
std::vector<LeaderboardEntry> entries{};
uint32_t index = 0;
while (res->next()) {
LeaderboardEntry entry;
entry.playerID = res->getUInt64(4);
entry.playerName = res->getString(5);
entry.time = res->getUInt(1);
entry.score = res->getUInt(2);
entry.placement = res->getUInt(3);
entry.lastPlayed = res->getUInt(6);
entries.push_back(entry);
index++;
}
delete res;
delete statement;
return new Leaderboard(gameID, infoType, weekly, entries, playerID, leaderboardType);
}
void LeaderboardManager::SendLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID targetID,
LWOOBJID playerID) {
const auto* leaderboard = LeaderboardManager::GetLeaderboard(gameID, infoType, weekly, playerID);
leaderboard->Send(targetID);
delete leaderboard;
}
LeaderboardType LeaderboardManager::GetLeaderboardType(uint32_t gameID) {
auto* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>(); auto* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
std::vector<CDActivities> activities = activitiesTable->Query([=](const CDActivities& entry) { std::vector<CDActivities> activities = activitiesTable->Query([gameID](const CDActivities& entry) {
return (entry.ActivityID == gameID); return entry.ActivityID == gameID;
}); });
auto type = !activities.empty() ? static_cast<Leaderboard::Type>(activities.at(0).leaderboardType) : Leaderboard::Type::None;
for (const auto& activity : activities) { leaderboardCache.insert_or_assign(gameID, type);
return static_cast<LeaderboardType>(activity.leaderboardType); return type;
} }
return LeaderboardType::None;
}
const std::string LeaderboardManager::topPlayersScoreQuery =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
"RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
"INNER JOIN charinfo c ON l.character_id = c.id "
"WHERE l.game_id = ? "
"ORDER BY leaderboard_rank) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales LIMIT 11;";
const std::string LeaderboardManager::friendsScoreQuery =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, "
" RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" INNER JOIN friends f ON f.player_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
" personal_values AS ( "
" SELECT id as related_player_id, "
" GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);";
const std::string LeaderboardManager::standingsScoreQuery =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
" RANK() OVER ( ORDER BY l.score DESC, l.time DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
"personal_values AS ( "
" SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;";
const std::string LeaderboardManager::topPlayersScoreQueryAsc =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
"RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank "
" FROM leaderboard l "
"INNER JOIN charinfo c ON l.character_id = c.id "
"WHERE l.game_id = ? "
"ORDER BY leaderboard_rank) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales LIMIT 11;";
const std::string LeaderboardManager::friendsScoreQueryAsc =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, "
" RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" INNER JOIN friends f ON f.player_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
" personal_values AS ( "
" SELECT id as related_player_id, "
" GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);";
const std::string LeaderboardManager::standingsScoreQueryAsc =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
" RANK() OVER ( ORDER BY l.score DESC, l.time ASC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
"personal_values AS ( "
" SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;";
const std::string LeaderboardManager::topPlayersTimeQuery =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
"RANK() OVER ( ORDER BY l.time DESC, l.score DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
"INNER JOIN charinfo c ON l.character_id = c.id "
"WHERE l.game_id = ? "
"ORDER BY leaderboard_rank) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales LIMIT 11;";
const std::string LeaderboardManager::friendsTimeQuery =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, "
" RANK() OVER ( ORDER BY l.time DESC, l.score DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" INNER JOIN friends f ON f.player_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
" personal_values AS ( "
" SELECT id as related_player_id, "
" GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);";
const std::string LeaderboardManager::standingsTimeQuery =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
" RANK() OVER ( ORDER BY l.time DESC, l.score DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
"personal_values AS ( "
" SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;";
const std::string LeaderboardManager::topPlayersTimeQueryAsc =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
"RANK() OVER ( ORDER BY l.time ASC, l.score DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
"INNER JOIN charinfo c ON l.character_id = c.id "
"WHERE l.game_id = ? "
"ORDER BY leaderboard_rank) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales LIMIT 11;";
const std::string LeaderboardManager::friendsTimeQueryAsc =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, f.friend_id, f.player_id, "
" RANK() OVER ( ORDER BY l.time ASC, l.score DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" INNER JOIN friends f ON f.player_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
" personal_values AS ( "
" SELECT id as related_player_id, "
" GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE leaderboard_vales.id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank AND (player_id = related_player_id OR friend_id = related_player_id);";
const std::string LeaderboardManager::standingsTimeQueryAsc =
"WITH leaderboard_vales AS ( "
" SELECT l.time, l.score, UNIX_TIMESTAMP(l.last_played) last_played, c.name, c.id, "
" RANK() OVER ( ORDER BY l.time ASC, l.score DESC, last_played ) leaderboard_rank "
" FROM leaderboard l "
" INNER JOIN charinfo c ON l.character_id = c.id "
" WHERE l.game_id = ? "
" ORDER BY leaderboard_rank), "
"personal_values AS ( "
" SELECT GREATEST(CAST(leaderboard_rank AS SIGNED) - 5, 1) AS min_rank, "
" GREATEST(leaderboard_rank + 5, 11) AS max_rank "
" FROM leaderboard_vales WHERE id = ? LIMIT 1) "
"SELECT time, score, leaderboard_rank, id, name, last_played "
"FROM leaderboard_vales, personal_values "
"WHERE leaderboard_rank BETWEEN min_rank AND max_rank;";

View File

@ -1,80 +1,134 @@
#pragma once #ifndef __LEADERBOARDMANAGER__H__
#include <vector> #define __LEADERBOARDMANAGER__H__
#include <climits>
#include "dCommonVars.h"
struct LeaderboardEntry { #include <map>
uint64_t playerID; #include <memory>
std::string playerName; #include <string_view>
uint32_t time; #include <vector>
uint32_t score;
uint32_t placement; #include "Singleton.h"
time_t lastPlayed; #include "dCommonVars.h"
#include "LDFFormat.h"
namespace sql {
class ResultSet;
}; };
namespace RakNet {
class BitStream;
};
class Score {
public:
Score() {
primaryScore = 0;
secondaryScore = 0;
tertiaryScore = 0;
}
Score(const float primaryScore, const float secondaryScore = 0, const float tertiaryScore = 0) {
this->primaryScore = primaryScore;
this->secondaryScore = secondaryScore;
this->tertiaryScore = tertiaryScore;
}
bool operator<(const Score& rhs) const {
return primaryScore < rhs.primaryScore || (primaryScore == rhs.primaryScore && secondaryScore < rhs.secondaryScore) || (primaryScore == rhs.primaryScore && secondaryScore == rhs.secondaryScore && tertiaryScore < rhs.tertiaryScore);
}
bool operator>(const Score& rhs) const {
return primaryScore > rhs.primaryScore || (primaryScore == rhs.primaryScore && secondaryScore > rhs.secondaryScore) || (primaryScore == rhs.primaryScore && secondaryScore == rhs.secondaryScore && tertiaryScore > rhs.tertiaryScore);
}
void SetPrimaryScore(const float score) { primaryScore = score; }
float GetPrimaryScore() const { return primaryScore; }
void SetSecondaryScore(const float score) { secondaryScore = score; }
float GetSecondaryScore() const { return secondaryScore; }
void SetTertiaryScore(const float score) { tertiaryScore = score; }
float GetTertiaryScore() const { return tertiaryScore; }
private:
float primaryScore;
float secondaryScore;
float tertiaryScore;
};
using GameID = uint32_t;
class Leaderboard {
public:
// Enums for leaderboards
enum InfoType : uint32_t { enum InfoType : uint32_t {
Top, // Top 11 all time players Top, // Top 11 all time players
Standings, // Ranking of the current player MyStanding, // Ranking of the current player
Friends // Ranking between friends Friends // Ranking between friends
}; };
enum LeaderboardType : uint32_t { enum Type : uint32_t {
ShootingGallery, ShootingGallery,
Racing, Racing,
MonumentRace, MonumentRace,
FootRace, FootRace,
Survival = 5, UnusedLeaderboard4, // There is no 4 defined anywhere in the cdclient, but it takes a Score.
SurvivalNS = 6, Survival,
None = UINT_MAX SurvivalNS,
Donations,
None
}; };
Leaderboard() = delete;
Leaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, LWOOBJID relatedPlayer, const Leaderboard::Type = None);
class Leaderboard { ~Leaderboard();
public:
Leaderboard(uint32_t gameID, uint32_t infoType, bool weekly, std::vector<LeaderboardEntry> entries, /**
LWOOBJID relatedPlayer = LWOOBJID_EMPTY, LeaderboardType = None); * @brief Resets the leaderboard state and frees its allocated memory
std::vector<LeaderboardEntry> GetEntries(); *
[[nodiscard]] std::u16string ToString() const; */
[[nodiscard]] uint32_t GetGameID() const; void Clear();
[[nodiscard]] uint32_t GetInfoType() const;
void Send(LWOOBJID targetID) const; /**
* Serialize the Leaderboard to a BitStream
*
* Expensive! Leaderboards are very string intensive so be wary of performatnce calling this method.
*/
void Serialize(RakNet::BitStream* bitStream) const;
/**
* Builds the leaderboard from the database based on the associated gameID
*
* @param resultStart The index to start the leaderboard at. Zero indexed.
* @param resultEnd The index to end the leaderboard at. Zero indexed.
*/
void SetupLeaderboard(bool weekly, uint32_t resultStart = 0, uint32_t resultEnd = 10);
/**
* Sends the leaderboard to the client specified by targetID.
*/
void Send(const LWOOBJID targetID) const;
// Helper function to get the columns, ordering and insert format for a leaderboard
static const std::string_view GetOrdering(Type leaderboardType);
private: private:
std::vector<LeaderboardEntry> entries{}; // Takes the resulting query from a leaderboard lookup and converts it to the LDF we need
// to send it to a client.
void QueryToLdf(std::unique_ptr<sql::ResultSet>& rows);
using LeaderboardEntry = std::vector<LDFBaseData*>;
using LeaderboardEntries = std::vector<LeaderboardEntry>;
LeaderboardEntries entries;
LWOOBJID relatedPlayer; LWOOBJID relatedPlayer;
uint32_t gameID; GameID gameID;
uint32_t infoType; InfoType infoType;
LeaderboardType leaderboardType; Leaderboard::Type leaderboardType;
bool weekly; bool weekly;
}; };
class LeaderboardManager { namespace LeaderboardManager {
public: void SendLeaderboard(const GameID gameID, const Leaderboard::InfoType infoType, const bool weekly, const LWOOBJID playerID, const LWOOBJID targetID, const uint32_t resultStart = 0, const uint32_t resultEnd = 10);
static LeaderboardManager* Instance() {
if (address == nullptr)
address = new LeaderboardManager;
return address;
}
static void SendLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID targetID,
LWOOBJID playerID = LWOOBJID_EMPTY);
static Leaderboard* GetLeaderboard(uint32_t gameID, InfoType infoType, bool weekly, LWOOBJID playerID = LWOOBJID_EMPTY);
static void SaveScore(LWOOBJID playerID, uint32_t gameID, uint32_t score, uint32_t time);
static LeaderboardType GetLeaderboardType(uint32_t gameID);
private:
static LeaderboardManager* address;
// Modified 12/12/2021: Existing queries were renamed to be more descriptive. void SaveScore(const LWOOBJID& playerID, const GameID activityId, const float primaryScore, const float secondaryScore = 0, const float tertiaryScore = 0);
static const std::string topPlayersScoreQuery;
static const std::string friendsScoreQuery;
static const std::string standingsScoreQuery;
static const std::string topPlayersScoreQueryAsc;
static const std::string friendsScoreQueryAsc;
static const std::string standingsScoreQueryAsc;
// Added 12/12/2021: Queries dictated by time are needed for certain minigames. Leaderboard::Type GetLeaderboardType(const GameID gameID);
static const std::string topPlayersTimeQuery; extern std::map<GameID, Leaderboard::Type> leaderboardCache;
static const std::string friendsTimeQuery;
static const std::string standingsTimeQuery;
static const std::string topPlayersTimeQueryAsc;
static const std::string friendsTimeQueryAsc;
static const std::string standingsTimeQueryAsc;
}; };
#endif //!__LEADERBOARDMANAGER__H__

View File

@ -62,7 +62,7 @@ void Player::SetSystemAddress(const SystemAddress& value) {
void Player::SetRespawnPos(const NiPoint3 position) { void Player::SetRespawnPos(const NiPoint3 position) {
m_respawnPos = position; m_respawnPos = position;
m_Character->SetRespawnPoint(dZoneManager::Instance()->GetZone()->GetWorldID(), position); m_Character->SetRespawnPoint(Game::zoneManager->GetZone()->GetWorldID(), position);
} }
void Player::SetRespawnRot(const NiQuaternion rotation) { void Player::SetRespawnRot(const NiQuaternion rotation) {
@ -85,7 +85,7 @@ void Player::SendToZone(LWOMAPID zoneId, LWOCLONEID cloneId) {
const auto objid = GetObjectID(); const auto objid = GetObjectID();
ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, zoneId, cloneId, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, zoneId, cloneId, false, [objid](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) {
auto* entity = EntityManager::Instance()->GetEntity(objid); auto* entity = Game::entityManager->GetEntity(objid);
if (entity == nullptr) { if (entity == nullptr) {
return; return;
@ -108,7 +108,7 @@ void Player::SendToZone(LWOMAPID zoneId, LWOCLONEID cloneId) {
WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift); WorldPackets::SendTransferToWorld(sysAddr, serverIP, serverPort, mythranShift);
EntityManager::Instance()->DestructEntity(entity); Game::entityManager->DestructEntity(entity);
return; return;
}); });
} }
@ -135,13 +135,13 @@ void Player::RemoveLimboConstruction(LWOOBJID objectId) {
void Player::ConstructLimboEntities() { void Player::ConstructLimboEntities() {
for (const auto objectId : m_LimboConstructions) { for (const auto objectId : m_LimboConstructions) {
auto* entity = EntityManager::Instance()->GetEntity(objectId); auto* entity = Game::entityManager->GetEntity(objectId);
if (entity == nullptr) { if (entity == nullptr) {
continue; continue;
} }
EntityManager::Instance()->ConstructEntity(entity, m_SystemAddress); Game::entityManager->ConstructEntity(entity, m_SystemAddress);
} }
m_LimboConstructions.clear(); m_LimboConstructions.clear();
@ -224,7 +224,7 @@ Player* Player::GetPlayer(const SystemAddress& sysAddr) {
} }
Player* Player::GetPlayer(const std::string& name) { Player* Player::GetPlayer(const std::string& name) {
const auto characters = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CHARACTER); const auto characters = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CHARACTER);
for (auto* character : characters) { for (auto* character : characters) {
if (!character->IsPlayer()) continue; if (!character->IsPlayer()) continue;
@ -269,7 +269,7 @@ Player::~Player() {
continue; continue;
} }
auto* entity = EntityManager::Instance()->GetGhostCandidate(id); auto* entity = Game::entityManager->GetGhostCandidate(id);
if (entity != nullptr) { if (entity != nullptr) {
entity->SetObservers(entity->GetObservers() - 1); entity->SetObservers(entity->GetObservers() - 1);
@ -285,12 +285,12 @@ Player::~Player() {
} }
if (IsPlayer()) { if (IsPlayer()) {
Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); Entity* zoneControl = Game::entityManager->GetZoneControlEntity();
for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) {
script->OnPlayerExit(zoneControl, this); script->OnPlayerExit(zoneControl, this);
} }
std::vector<Entity*> scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); std::vector<Entity*> scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY);
for (Entity* scriptEntity : scriptedActs) { for (Entity* scriptEntity : scriptedActs) {
if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds
for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) {

View File

@ -40,11 +40,11 @@ LWOOBJID Trade::GetParticipantB() const {
} }
Entity* Trade::GetParticipantAEntity() const { Entity* Trade::GetParticipantAEntity() const {
return EntityManager::Instance()->GetEntity(m_ParticipantA); return Game::entityManager->GetEntity(m_ParticipantA);
} }
Entity* Trade::GetParticipantBEntity() const { Entity* Trade::GetParticipantBEntity() const {
return EntityManager::Instance()->GetEntity(m_ParticipantB); return Game::entityManager->GetEntity(m_ParticipantB);
} }
void Trade::SetCoins(LWOOBJID participant, uint64_t coins) { void Trade::SetCoins(LWOOBJID participant, uint64_t coins) {

View File

@ -220,7 +220,7 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
skillComponent->Reset(); skillComponent->Reset();
} }
EntityManager::Instance()->DestroyEntity(chars[i]->GetEntity()); Game::entityManager->DestroyEntity(chars[i]->GetEntity());
chars[i]->SaveXMLToDatabase(); chars[i]->SaveXMLToDatabase();

View File

@ -39,7 +39,7 @@ void AirMovementBehavior::Sync(BehaviorContext* context, RakNet::BitStream* bitS
auto* behavior = CreateBehavior(behaviorId); auto* behavior = CreateBehavior(behaviorId);
if (EntityManager::Instance()->GetEntity(target) != nullptr) { if (Game::entityManager->GetEntity(target) != nullptr) {
branch.target = target; branch.target = target;
} }

View File

@ -6,7 +6,7 @@
void ApplyBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void ApplyBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* entity = EntityManager::Instance()->GetEntity(branch.target == LWOOBJID_EMPTY ? context->originator : branch.target); auto* entity = Game::entityManager->GetEntity(branch.target == LWOOBJID_EMPTY ? context->originator : branch.target);
if (entity == nullptr) return; if (entity == nullptr) return;
@ -19,7 +19,7 @@ void ApplyBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS
} }
void ApplyBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { void ApplyBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
auto* entity = EntityManager::Instance()->GetEntity(branch.target); auto* entity = Game::entityManager->GetEntity(branch.target);
if (entity == nullptr) return; if (entity == nullptr) return;

View File

@ -47,7 +47,7 @@ void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* b
} }
void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* self = EntityManager::Instance()->GetEntity(context->caster); auto* self = Game::entityManager->GetEntity(context->caster);
if (self == nullptr) { if (self == nullptr) {
Game::logger->Log("AreaOfEffectBehavior", "Invalid self for (%llu)!", context->originator); Game::logger->Log("AreaOfEffectBehavior", "Invalid self for (%llu)!", context->originator);
@ -58,7 +58,7 @@ void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream
std::vector<Entity*> targets; std::vector<Entity*> targets;
auto* presetTarget = EntityManager::Instance()->GetEntity(branch.target); auto* presetTarget = Game::entityManager->GetEntity(branch.target);
if (presetTarget != nullptr) { if (presetTarget != nullptr) {
if (this->m_radius * this->m_radius >= Vector3::DistanceSquared(reference, presetTarget->GetPosition())) { if (this->m_radius * this->m_radius >= Vector3::DistanceSquared(reference, presetTarget->GetPosition())) {
@ -75,7 +75,7 @@ void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream
// Gets all of the valid targets, passing in if should target enemies and friends // Gets all of the valid targets, passing in if should target enemies and friends
for (auto validTarget : context->GetValidTargets(m_ignoreFaction, includeFaction, m_TargetSelf == 1, m_targetEnemy == 1, m_targetFriend == 1)) { for (auto validTarget : context->GetValidTargets(m_ignoreFaction, includeFaction, m_TargetSelf == 1, m_targetEnemy == 1, m_targetFriend == 1)) {
auto* entity = EntityManager::Instance()->GetEntity(validTarget); auto* entity = Game::entityManager->GetEntity(validTarget);
if (entity == nullptr) { if (entity == nullptr) {
Game::logger->Log("AreaOfEffectBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator); Game::logger->Log("AreaOfEffectBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator);

View File

@ -9,7 +9,7 @@
void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
if (context->unmanaged) { if (context->unmanaged) {
auto* entity = EntityManager::Instance()->GetEntity(branch.target); auto* entity = Game::entityManager->GetEntity(branch.target);
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>(); auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
if (destroyableComponent != nullptr) { if (destroyableComponent != nullptr) {
@ -38,7 +38,7 @@ void BasicAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bi
} }
void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* targetEntity = EntityManager::Instance()->GetEntity(branch.target); auto* targetEntity = Game::entityManager->GetEntity(branch.target);
if (!targetEntity) { if (!targetEntity) {
Game::logger->Log("BasicAttackBehavior", "Target targetEntity %llu not found.", branch.target); Game::logger->Log("BasicAttackBehavior", "Target targetEntity %llu not found.", branch.target);
return; return;
@ -61,7 +61,7 @@ void BasicAttackBehavior::DoHandleBehavior(BehaviorContext* context, RakNet::Bit
if (isBlocked) { if (isBlocked) {
destroyableComponent->SetAttacksToBlock(std::min(destroyableComponent->GetAttacksToBlock() - 1, 0U)); destroyableComponent->SetAttacksToBlock(std::min(destroyableComponent->GetAttacksToBlock() - 1, 0U));
EntityManager::Instance()->SerializeEntity(targetEntity); Game::entityManager->SerializeEntity(targetEntity);
this->m_OnFailBlocked->Handle(context, bitStream, branch); this->m_OnFailBlocked->Handle(context, bitStream, branch);
return; return;
} }
@ -155,7 +155,7 @@ void BasicAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream*
} }
void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* targetEntity = EntityManager::Instance()->GetEntity(branch.target); auto* targetEntity = Game::entityManager->GetEntity(branch.target);
if (!targetEntity) { if (!targetEntity) {
Game::logger->Log("BasicAttackBehavior", "Target entity %llu is null!", branch.target); Game::logger->Log("BasicAttackBehavior", "Target entity %llu is null!", branch.target);
return; return;
@ -173,7 +173,7 @@ void BasicAttackBehavior::DoBehaviorCalculation(BehaviorContext* context, RakNet
if (isBlocking) { if (isBlocking) {
destroyableComponent->SetAttacksToBlock(destroyableComponent->GetAttacksToBlock() - 1); destroyableComponent->SetAttacksToBlock(destroyableComponent->GetAttacksToBlock() - 1);
EntityManager::Instance()->SerializeEntity(targetEntity); Game::entityManager->SerializeEntity(targetEntity);
this->m_OnFailBlocked->Calculate(context, bitStream, branch); this->m_OnFailBlocked->Calculate(context, bitStream, branch);
return; return;
} }

View File

@ -61,6 +61,7 @@
#include "SpeedBehavior.h" #include "SpeedBehavior.h"
#include "DamageReductionBehavior.h" #include "DamageReductionBehavior.h"
#include "JetPackBehavior.h" #include "JetPackBehavior.h"
#include "FallSpeedBehavior.h"
#include "ChangeIdleFlagsBehavior.h" #include "ChangeIdleFlagsBehavior.h"
#include "DarkInspirationBehavior.h" #include "DarkInspirationBehavior.h"
@ -164,7 +165,9 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) {
case BehaviorTemplates::BEHAVIOR_CAR_BOOST: case BehaviorTemplates::BEHAVIOR_CAR_BOOST:
behavior = new CarBoostBehavior(behaviorId); behavior = new CarBoostBehavior(behaviorId);
break; break;
case BehaviorTemplates::BEHAVIOR_FALL_SPEED: break; case BehaviorTemplates::BEHAVIOR_FALL_SPEED:
behavior = new FallSpeedBehavior(behaviorId);
break;
case BehaviorTemplates::BEHAVIOR_SHIELD: break; case BehaviorTemplates::BEHAVIOR_SHIELD: break;
case BehaviorTemplates::BEHAVIOR_REPAIR_ARMOR: case BehaviorTemplates::BEHAVIOR_REPAIR_ARMOR:
behavior = new RepairBehavior(behaviorId); behavior = new RepairBehavior(behaviorId);
@ -311,7 +314,7 @@ BehaviorTemplates Behavior::GetBehaviorTemplate(const uint32_t behaviorId) {
// For use with enemies, to display the correct damage animations on the players // For use with enemies, to display the correct damage animations on the players
void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID secondary) { void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID secondary) {
auto* targetEntity = EntityManager::Instance()->GetEntity(target); auto* targetEntity = Game::entityManager->GetEntity(target);
if (targetEntity == nullptr) { if (targetEntity == nullptr) {
return; return;

View File

@ -27,7 +27,7 @@ BehaviorEndEntry::BehaviorEndEntry() {
} }
uint32_t BehaviorContext::GetUniqueSkillId() const { uint32_t BehaviorContext::GetUniqueSkillId() const {
auto* entity = EntityManager::Instance()->GetEntity(this->originator); auto* entity = Game::entityManager->GetEntity(this->originator);
if (entity == nullptr) { if (entity == nullptr) {
Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!", this->originator); Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!", this->originator);
@ -94,11 +94,11 @@ void BehaviorContext::ScheduleUpdate(const LWOOBJID id) {
void BehaviorContext::ExecuteUpdates() { void BehaviorContext::ExecuteUpdates() {
for (const auto& id : this->scheduledUpdates) { for (const auto& id : this->scheduledUpdates) {
auto* entity = EntityManager::Instance()->GetEntity(id); auto* entity = Game::entityManager->GetEntity(id);
if (entity == nullptr) continue; if (entity == nullptr) continue;
EntityManager::Instance()->SerializeEntity(entity); Game::entityManager->SerializeEntity(entity);
} }
this->scheduledUpdates.clear(); this->scheduledUpdates.clear();
@ -308,7 +308,7 @@ void BehaviorContext::Reset() {
} }
std::vector<LWOOBJID> BehaviorContext::GetValidTargets(int32_t ignoreFaction, int32_t includeFaction, bool targetSelf, bool targetEnemy, bool targetFriend) const { std::vector<LWOOBJID> BehaviorContext::GetValidTargets(int32_t ignoreFaction, int32_t includeFaction, bool targetSelf, bool targetEnemy, bool targetFriend) const {
auto* entity = EntityManager::Instance()->GetEntity(this->caster); auto* entity = Game::entityManager->GetEntity(this->caster);
std::vector<LWOOBJID> targets; std::vector<LWOOBJID> targets;
@ -320,7 +320,7 @@ std::vector<LWOOBJID> BehaviorContext::GetValidTargets(int32_t ignoreFaction, in
if (!ignoreFaction && !includeFaction) { if (!ignoreFaction && !includeFaction) {
for (auto entry : entity->GetTargetsInPhantom()) { for (auto entry : entity->GetTargetsInPhantom()) {
auto* instance = EntityManager::Instance()->GetEntity(entry); auto* instance = Game::entityManager->GetEntity(entry);
if (instance == nullptr) { if (instance == nullptr) {
continue; continue;
@ -336,7 +336,7 @@ std::vector<LWOOBJID> BehaviorContext::GetValidTargets(int32_t ignoreFaction, in
return targets; return targets;
} }
auto entities = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS); auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS);
for (auto* candidate : entities) { for (auto* candidate : entities) {
const auto id = candidate->GetObjectID(); const auto id = candidate->GetObjectID();

View File

@ -10,7 +10,7 @@
void BlockBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void BlockBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
const auto target = context->originator; const auto target = context->originator;
auto* entity = EntityManager::Instance()->GetEntity(target); auto* entity = Game::entityManager->GetEntity(target);
if (entity == nullptr) { if (entity == nullptr) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target); Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
@ -40,7 +40,7 @@ void BlockBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitSt
void BlockBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { void BlockBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
const auto target = context->originator; const auto target = context->originator;
auto* entity = EntityManager::Instance()->GetEntity(target); auto* entity = Game::entityManager->GetEntity(target);
if (entity == nullptr) { if (entity == nullptr) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target); Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);

View File

@ -10,7 +10,7 @@
void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator;
auto* entity = EntityManager::Instance()->GetEntity(target); auto* entity = Game::entityManager->GetEntity(target);
if (entity == nullptr) { if (entity == nullptr) {
Game::logger->Log("BuffBehavior", "Invalid target (%llu)!", target); Game::logger->Log("BuffBehavior", "Invalid target (%llu)!", target);
@ -30,7 +30,7 @@ void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream
component->SetMaxArmor(component->GetMaxArmor() + this->m_armor); component->SetMaxArmor(component->GetMaxArmor() + this->m_armor);
component->SetMaxImagination(component->GetMaxImagination() + this->m_imagination); component->SetMaxImagination(component->GetMaxImagination() + this->m_imagination);
EntityManager::Instance()->SerializeEntity(entity); Game::entityManager->SerializeEntity(entity);
if (!context->unmanaged) { if (!context->unmanaged) {
if (branch.duration > 0) { if (branch.duration > 0) {
@ -44,7 +44,7 @@ void BuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream
void BuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { void BuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator; const auto target = branch.target != LWOOBJID_EMPTY ? branch.target : context->originator;
auto* entity = EntityManager::Instance()->GetEntity(target); auto* entity = Game::entityManager->GetEntity(target);
if (entity == nullptr) { if (entity == nullptr) {
Game::logger->Log("BuffBehavior", "Invalid target (%llu)!", target); Game::logger->Log("BuffBehavior", "Invalid target (%llu)!", target);
@ -64,7 +64,7 @@ void BuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch
component->SetMaxArmor(component->GetMaxArmor() - this->m_armor); component->SetMaxArmor(component->GetMaxArmor() - this->m_armor);
component->SetMaxImagination(component->GetMaxImagination() - this->m_imagination); component->SetMaxImagination(component->GetMaxImagination() - this->m_imagination);
EntityManager::Instance()->SerializeEntity(entity); Game::entityManager->SerializeEntity(entity);
} }
void BuffBehavior::Timer(BehaviorContext* context, const BehaviorBranchContext branch, LWOOBJID second) { void BuffBehavior::Timer(BehaviorContext* context, const BehaviorBranchContext branch, LWOOBJID second) {

View File

@ -22,6 +22,7 @@ set(DGAME_DBEHAVIORS_SOURCES "AirMovementBehavior.cpp"
"DurationBehavior.cpp" "DurationBehavior.cpp"
"EmptyBehavior.cpp" "EmptyBehavior.cpp"
"EndBehavior.cpp" "EndBehavior.cpp"
"FallSpeedBehavior.cpp"
"ForceMovementBehavior.cpp" "ForceMovementBehavior.cpp"
"HealBehavior.cpp" "HealBehavior.cpp"
"ImaginationBehavior.cpp" "ImaginationBehavior.cpp"

View File

@ -11,7 +11,7 @@
void CarBoostBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void CarBoostBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
GameMessages::SendVehicleAddPassiveBoostAction(branch.target, UNASSIGNED_SYSTEM_ADDRESS); GameMessages::SendVehicleAddPassiveBoostAction(branch.target, UNASSIGNED_SYSTEM_ADDRESS);
auto* entity = EntityManager::Instance()->GetEntity(context->originator); auto* entity = Game::entityManager->GetEntity(context->originator);
if (entity == nullptr) { if (entity == nullptr) {
return; return;
@ -22,7 +22,7 @@ void CarBoostBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitSt
auto* possessableComponent = entity->GetComponent<PossessableComponent>(); auto* possessableComponent = entity->GetComponent<PossessableComponent>();
if (possessableComponent != nullptr) { if (possessableComponent != nullptr) {
auto* possessor = EntityManager::Instance()->GetEntity(possessableComponent->GetPossessor()); auto* possessor = Game::entityManager->GetEntity(possessableComponent->GetPossessor());
if (possessor != nullptr) { if (possessor != nullptr) {
auto* characterComponent = possessor->GetComponent<CharacterComponent>(); auto* characterComponent = possessor->GetComponent<CharacterComponent>();

View File

@ -5,14 +5,14 @@
void ChangeOrientationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void ChangeOrientationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
Entity* sourceEntity; Entity* sourceEntity;
if (this->m_orientCaster) sourceEntity = EntityManager::Instance()->GetEntity(context->originator); if (this->m_orientCaster) sourceEntity = Game::entityManager->GetEntity(context->originator);
else sourceEntity = EntityManager::Instance()->GetEntity(branch.target); else sourceEntity = Game::entityManager->GetEntity(branch.target);
if (!sourceEntity) return; if (!sourceEntity) return;
if (this->m_toTarget) { if (this->m_toTarget) {
Entity* destinationEntity; Entity* destinationEntity;
if (this->m_orientCaster) destinationEntity = EntityManager::Instance()->GetEntity(branch.target); if (this->m_orientCaster) destinationEntity = Game::entityManager->GetEntity(branch.target);
else destinationEntity = EntityManager::Instance()->GetEntity(context->originator); else destinationEntity = Game::entityManager->GetEntity(context->originator);
if (!destinationEntity) return; if (!destinationEntity) return;
sourceEntity->SetRotation( sourceEntity->SetRotation(
@ -23,7 +23,7 @@ void ChangeOrientationBehavior::Calculate(BehaviorContext* context, RakNet::BitS
if (this->m_relative) baseAngle += sourceEntity->GetRotation().GetForwardVector(); if (this->m_relative) baseAngle += sourceEntity->GetRotation().GetForwardVector();
sourceEntity->SetRotation(NiQuaternion::FromEulerAngles(baseAngle)); sourceEntity->SetRotation(NiQuaternion::FromEulerAngles(baseAngle));
} else return; } else return;
EntityManager::Instance()->SerializeEntity(sourceEntity); Game::entityManager->SerializeEntity(sourceEntity);
return; return;
} }

View File

@ -8,7 +8,7 @@
#include "DestroyableComponent.h" #include "DestroyableComponent.h"
void DamageAbsorptionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { void DamageAbsorptionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) { if (target == nullptr) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target); Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
@ -34,7 +34,7 @@ void DamageAbsorptionBehavior::Calculate(BehaviorContext* context, RakNet::BitSt
} }
void DamageAbsorptionBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) { void DamageAbsorptionBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) {
auto* target = EntityManager::Instance()->GetEntity(second); auto* target = Game::entityManager->GetEntity(second);
if (target == nullptr) { if (target == nullptr) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second); Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second);

View File

@ -8,7 +8,7 @@
#include "DestroyableComponent.h" #include "DestroyableComponent.h"
void DamageReductionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { void DamageReductionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) { if (target == nullptr) {
Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!", branch.target); Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!", branch.target);
@ -32,7 +32,7 @@ void DamageReductionBehavior::Calculate(BehaviorContext* context, RakNet::BitStr
} }
void DamageReductionBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) { void DamageReductionBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) {
auto* target = EntityManager::Instance()->GetEntity(second); auto* target = Game::entityManager->GetEntity(second);
if (target == nullptr) { if (target == nullptr) {
Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!", second); Game::logger->Log("DamageReductionBehavior", "Failed to find target (%llu)!", second);

View File

@ -7,7 +7,7 @@
#include "BehaviorContext.h" #include "BehaviorContext.h"
void DarkInspirationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { void DarkInspirationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) { if (target == nullptr) {
Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target); Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target);
@ -26,7 +26,7 @@ void DarkInspirationBehavior::Handle(BehaviorContext* context, RakNet::BitStream
} }
void DarkInspirationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void DarkInspirationBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) { if (target == nullptr) {
Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target); Game::logger->LogDebug("DarkInspirationBehavior", "Failed to find target (%llu)!", branch.target);

View File

@ -0,0 +1,50 @@
#include "FallSpeedBehavior.h"
#include "ControllablePhysicsComponent.h"
#include "BehaviorContext.h"
#include "BehaviorBranchContext.h"
void FallSpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
// make sure required parameter has non-default value
if (m_PercentSlowed == 0.0f) return;
auto* target = Game::entityManager->GetEntity(branch.target);
if (!target) return;
auto* controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>();
if (!controllablePhysicsComponent) return;
controllablePhysicsComponent->SetGravityScale(m_PercentSlowed);
Game::entityManager->SerializeEntity(target);
if (branch.duration > 0.0f) {
context->RegisterTimerBehavior(this, branch);
} else if (branch.start > 0) {
context->RegisterEndBehavior(this, branch);
}
}
void FallSpeedBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
Handle(context, bitStream, branch);
}
void FallSpeedBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) {
End(context, branch, second);
}
void FallSpeedBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
End(context, branch, LWOOBJID_EMPTY);
}
void FallSpeedBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) {
auto* target = Game::entityManager->GetEntity(branch.target);
if (!target) return;
auto* controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>();
if (!controllablePhysicsComponent) return;
controllablePhysicsComponent->SetGravityScale(1);
Game::entityManager->SerializeEntity(target);
}
void FallSpeedBehavior::Load(){
m_PercentSlowed = GetFloat("percent_slowed");
}

View File

@ -0,0 +1,18 @@
#pragma once
#include "Behavior.h"
class FallSpeedBehavior final : public Behavior
{
public:
explicit FallSpeedBehavior(const uint32_t behaviorId) : Behavior(behaviorId) {}
void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
void Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override;
void End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) override;
void UnCast(BehaviorContext* context, BehaviorBranchContext branch) override;
void Load() override;
private:
float m_PercentSlowed;
};

View File

@ -42,7 +42,7 @@ void ForceMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStrea
return; return;
} }
auto* casterEntity = EntityManager::Instance()->GetEntity(context->caster); auto* casterEntity = Game::entityManager->GetEntity(context->caster);
if (casterEntity != nullptr) { if (casterEntity != nullptr) {
auto* controllablePhysicsComponent = casterEntity->GetComponent<ControllablePhysicsComponent>(); auto* controllablePhysicsComponent = casterEntity->GetComponent<ControllablePhysicsComponent>();
if (controllablePhysicsComponent != nullptr) { if (controllablePhysicsComponent != nullptr) {
@ -51,7 +51,7 @@ void ForceMovementBehavior::Calculate(BehaviorContext* context, RakNet::BitStrea
controllablePhysicsComponent->SetVelocity(controllablePhysicsComponent->GetRotation().GetForwardVector() * 25); controllablePhysicsComponent->SetVelocity(controllablePhysicsComponent->GetRotation().GetForwardVector() * 25);
} }
EntityManager::Instance()->SerializeEntity(casterEntity); Game::entityManager->SerializeEntity(casterEntity);
} }
} }
@ -72,7 +72,7 @@ void ForceMovementBehavior::Load() {
} }
void ForceMovementBehavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void ForceMovementBehavior::SyncCalculation(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* casterEntity = EntityManager::Instance()->GetEntity(context->caster); auto* casterEntity = Game::entityManager->GetEntity(context->caster);
if (casterEntity != nullptr) { if (casterEntity != nullptr) {
auto* controllablePhysicsComponent = casterEntity->GetComponent<ControllablePhysicsComponent>(); auto* controllablePhysicsComponent = casterEntity->GetComponent<ControllablePhysicsComponent>();
if (controllablePhysicsComponent != nullptr) { if (controllablePhysicsComponent != nullptr) {
@ -80,7 +80,7 @@ void ForceMovementBehavior::SyncCalculation(BehaviorContext* context, RakNet::Bi
controllablePhysicsComponent->SetPosition(controllablePhysicsComponent->GetPosition() + controllablePhysicsComponent->GetVelocity() * m_Duration); controllablePhysicsComponent->SetPosition(controllablePhysicsComponent->GetPosition() + controllablePhysicsComponent->GetVelocity() * m_Duration);
controllablePhysicsComponent->SetVelocity({}); controllablePhysicsComponent->SetVelocity({});
EntityManager::Instance()->SerializeEntity(casterEntity); Game::entityManager->SerializeEntity(casterEntity);
} }
} }

View File

@ -8,7 +8,7 @@
void HealBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { void HealBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) {
auto* entity = EntityManager::Instance()->GetEntity(branch.target); auto* entity = Game::entityManager->GetEntity(branch.target);
if (entity == nullptr) { if (entity == nullptr) {
Game::logger->Log("HealBehavior", "Failed to find entity for (%llu)!", branch.target); Game::logger->Log("HealBehavior", "Failed to find entity for (%llu)!", branch.target);

View File

@ -7,7 +7,7 @@
void ImaginationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { void ImaginationBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) {
auto* entity = EntityManager::Instance()->GetEntity(branch.target); auto* entity = Game::entityManager->GetEntity(branch.target);
if (entity == nullptr) { if (entity == nullptr) {
return; return;

View File

@ -10,7 +10,7 @@
#include "eStateChangeType.h" #include "eStateChangeType.h"
void ImmunityBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { void ImmunityBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (!target) { if (!target) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target); Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", branch.target);
@ -56,7 +56,7 @@ void ImmunityBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bi
} }
void ImmunityBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) { void ImmunityBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, const LWOOBJID second) {
auto* target = EntityManager::Instance()->GetEntity(second); auto* target = Game::entityManager->GetEntity(second);
if (!target) { if (!target) {
Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second); Game::logger->Log("DamageAbsorptionBehavior", "Failed to find target (%llu)!", second);

View File

@ -42,7 +42,7 @@ void InterruptBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS
if (branch.target == context->originator) return; if (branch.target == context->originator) return;
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) return; if (target == nullptr) return;
@ -67,7 +67,7 @@ void InterruptBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* b
if (branch.target == context->originator) return; if (branch.target == context->originator) return;
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) return; if (target == nullptr) return;

View File

@ -6,7 +6,7 @@
#include "Character.h" #include "Character.h"
void JetPackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { void JetPackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) {
auto* entity = EntityManager::Instance()->GetEntity(branch.target); auto* entity = Game::entityManager->GetEntity(branch.target);
GameMessages::SendSetJetPackMode(entity, true, this->m_BypassChecks, this->m_EnableHover, this->m_effectId, this->m_Airspeed, this->m_MaxAirspeed, this->m_VerticalVelocity, this->m_WarningEffectID); GameMessages::SendSetJetPackMode(entity, true, this->m_BypassChecks, this->m_EnableHover, this->m_effectId, this->m_Airspeed, this->m_MaxAirspeed, this->m_VerticalVelocity, this->m_WarningEffectID);
@ -20,7 +20,7 @@ void JetPackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_st
} }
void JetPackBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { void JetPackBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
auto* entity = EntityManager::Instance()->GetEntity(branch.target); auto* entity = Game::entityManager->GetEntity(branch.target);
GameMessages::SendSetJetPackMode(entity, false); GameMessages::SendSetJetPackMode(entity, false);

View File

@ -21,7 +21,7 @@ void KnockbackBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitS
void KnockbackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void KnockbackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
bool blocked = false; bool blocked = false;
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (target != nullptr) { if (target != nullptr) {
auto* destroyableComponent = target->GetComponent<DestroyableComponent>(); auto* destroyableComponent = target->GetComponent<DestroyableComponent>();

View File

@ -1,14 +1,14 @@
#include "LootBuffBehavior.h" #include "LootBuffBehavior.h"
void LootBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void LootBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto target = EntityManager::Instance()->GetEntity(context->caster); auto target = Game::entityManager->GetEntity(context->caster);
if (!target) return; if (!target) return;
auto controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>(); auto controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>();
if (!controllablePhysicsComponent) return; if (!controllablePhysicsComponent) return;
controllablePhysicsComponent->AddPickupRadiusScale(m_Scale); controllablePhysicsComponent->AddPickupRadiusScale(m_Scale);
EntityManager::Instance()->SerializeEntity(target); Game::entityManager->SerializeEntity(target);
if (branch.duration > 0) context->RegisterTimerBehavior(this, branch); if (branch.duration > 0) context->RegisterTimerBehavior(this, branch);
@ -19,14 +19,14 @@ void LootBuffBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bi
} }
void LootBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { void LootBuffBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
auto target = EntityManager::Instance()->GetEntity(context->caster); auto target = Game::entityManager->GetEntity(context->caster);
if (!target) return; if (!target) return;
auto controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>(); auto controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>();
if (!controllablePhysicsComponent) return; if (!controllablePhysicsComponent) return;
controllablePhysicsComponent->RemovePickupRadiusScale(m_Scale); controllablePhysicsComponent->RemovePickupRadiusScale(m_Scale);
EntityManager::Instance()->SerializeEntity(target); Game::entityManager->SerializeEntity(target);
} }
void LootBuffBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { void LootBuffBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) {

View File

@ -14,13 +14,13 @@
void OverTimeBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void OverTimeBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
const auto originator = context->originator; const auto originator = context->originator;
auto* entity = EntityManager::Instance()->GetEntity(originator); auto* entity = Game::entityManager->GetEntity(originator);
if (entity == nullptr) return; if (entity == nullptr) return;
for (size_t i = 0; i < m_NumIntervals; i++) { for (size_t i = 0; i < m_NumIntervals; i++) {
entity->AddCallbackTimer((i + 1) * m_Delay, [originator, branch, this]() { entity->AddCallbackTimer((i + 1) * m_Delay, [originator, branch, this]() {
auto* entity = EntityManager::Instance()->GetEntity(originator); auto* entity = Game::entityManager->GetEntity(originator);
if (entity == nullptr) return; if (entity == nullptr) return;

View File

@ -16,7 +16,7 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea
return; return;
}; };
auto* entity = EntityManager::Instance()->GetEntity(context->originator); auto* entity = Game::entityManager->GetEntity(context->originator);
if (entity == nullptr) { if (entity == nullptr) {
Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator); Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator);
@ -40,7 +40,7 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea
}; };
} }
auto* targetEntity = EntityManager::Instance()->GetEntity(target); auto* targetEntity = Game::entityManager->GetEntity(target);
for (auto i = 0u; i < this->m_projectileCount; ++i) { for (auto i = 0u; i < this->m_projectileCount; ++i) {
LWOOBJID projectileId{}; LWOOBJID projectileId{};
@ -61,7 +61,7 @@ void ProjectileAttackBehavior::Handle(BehaviorContext* context, RakNet::BitStrea
void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
bitStream->Write(branch.target); bitStream->Write(branch.target);
auto* entity = EntityManager::Instance()->GetEntity(context->originator); auto* entity = Game::entityManager->GetEntity(context->originator);
if (entity == nullptr) { if (entity == nullptr) {
Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator); Game::logger->Log("ProjectileAttackBehavior", "Failed to find originator (%llu)!", context->originator);
@ -78,7 +78,7 @@ void ProjectileAttackBehavior::Calculate(BehaviorContext* context, RakNet::BitSt
} }
auto* other = EntityManager::Instance()->GetEntity(branch.target); auto* other = Game::entityManager->GetEntity(branch.target);
if (other == nullptr) { if (other == nullptr) {
Game::logger->Log("ProjectileAttackBehavior", "Invalid projectile target (%llu)!", branch.target); Game::logger->Log("ProjectileAttackBehavior", "Invalid projectile target (%llu)!", branch.target);

View File

@ -12,7 +12,7 @@
#include "dZoneManager.h" #include "dZoneManager.h"
void PropertyTeleportBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void PropertyTeleportBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* caster = EntityManager::Instance()->GetEntity(context->caster); auto* caster = Game::entityManager->GetEntity(context->caster);
if (!caster) return; if (!caster) return;
auto* character = caster->GetCharacter(); auto* character = caster->GetCharacter();
@ -23,16 +23,16 @@ void PropertyTeleportBehavior::Handle(BehaviorContext* context, RakNet::BitStrea
LWOMAPID targetMapId = m_MapId; LWOMAPID targetMapId = m_MapId;
LWOCLONEID targetCloneId = character->GetPropertyCloneID(); LWOCLONEID targetCloneId = character->GetPropertyCloneID();
if (dZoneManager::Instance()->GetZoneID().GetCloneID() == character->GetPropertyCloneID()) { if (Game::zoneManager->GetZoneID().GetCloneID() == character->GetPropertyCloneID()) {
targetMapId = character->GetLastNonInstanceZoneID(); targetMapId = character->GetLastNonInstanceZoneID();
targetCloneId = 0; targetCloneId = 0;
} else { } else {
character->SetLastNonInstanceZoneID(dZoneManager::Instance()->GetZoneID().GetMapID()); character->SetLastNonInstanceZoneID(Game::zoneManager->GetZoneID().GetMapID());
} }
ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, targetMapId, targetCloneId, false, [objId](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) { ZoneInstanceManager::Instance()->RequestZoneTransfer(Game::server, targetMapId, targetCloneId, false, [objId](bool mythranShift, uint32_t zoneID, uint32_t zoneInstance, uint32_t zoneClone, std::string serverIP, uint16_t serverPort) {
auto* entity = EntityManager::Instance()->GetEntity(objId); auto* entity = Game::entityManager->GetEntity(objId);
if (!entity) return; if (!entity) return;
const auto sysAddr = entity->GetSystemAddress(); const auto sysAddr = entity->GetSystemAddress();

View File

@ -6,9 +6,9 @@
#include "MovementAIComponent.h" #include "MovementAIComponent.h"
void PullToPointBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void PullToPointBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* entity = EntityManager::Instance()->GetEntity(context->originator); auto* entity = Game::entityManager->GetEntity(context->originator);
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (entity == nullptr || target == nullptr) { if (entity == nullptr || target == nullptr) {
return; return;

View File

@ -6,7 +6,7 @@
#include "BuffComponent.h" #include "BuffComponent.h"
void RemoveBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void RemoveBuffBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* entity = EntityManager::Instance()->GetEntity(context->caster); auto* entity = Game::entityManager->GetEntity(context->caster);
if (!entity) return; if (!entity) return;
auto* buffComponent = entity->GetComponent<BuffComponent>(); auto* buffComponent = entity->GetComponent<BuffComponent>();

View File

@ -8,7 +8,7 @@
#include "eReplicaComponentType.h" #include "eReplicaComponentType.h"
void RepairBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) { void RepairBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit_stream, const BehaviorBranchContext branch) {
auto* entity = EntityManager::Instance()->GetEntity(branch.target); auto* entity = Game::entityManager->GetEntity(branch.target);
if (entity == nullptr) { if (entity == nullptr) {
Game::logger->Log("RepairBehavior", "Failed to find entity for (%llu)!", branch.target); Game::logger->Log("RepairBehavior", "Failed to find entity for (%llu)!", branch.target);

View File

@ -5,8 +5,8 @@
#include "CppScripts.h" #include "CppScripts.h"
void SkillEventBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void SkillEventBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
auto* caster = EntityManager::Instance()->GetEntity(context->originator); auto* caster = Game::entityManager->GetEntity(context->originator);
if (caster != nullptr && target != nullptr && this->m_effectHandle != nullptr && !this->m_effectHandle->empty()) { if (caster != nullptr && target != nullptr && this->m_effectHandle != nullptr && !this->m_effectHandle->empty()) {
for (CppScripts::Script* script : CppScripts::GetEntityScripts(target)) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(target)) {
@ -17,8 +17,8 @@ void SkillEventBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bit
void void
SkillEventBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { SkillEventBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
auto* caster = EntityManager::Instance()->GetEntity(context->originator); auto* caster = Game::entityManager->GetEntity(context->originator);
if (caster != nullptr && target != nullptr && this->m_effectHandle != nullptr && !this->m_effectHandle->empty()) { if (caster != nullptr && target != nullptr && this->m_effectHandle != nullptr && !this->m_effectHandle->empty()) {
for (CppScripts::Script* script : CppScripts::GetEntityScripts(target)) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(target)) {

View File

@ -12,7 +12,7 @@
#include "eReplicaComponentType.h" #include "eReplicaComponentType.h"
void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* origin = EntityManager::Instance()->GetEntity(context->originator); auto* origin = Game::entityManager->GetEntity(context->originator);
if (origin == nullptr) { if (origin == nullptr) {
Game::logger->Log("SpawnBehavior", "Failed to find self entity (%llu)!", context->originator); Game::logger->Log("SpawnBehavior", "Failed to find self entity (%llu)!", context->originator);
@ -21,7 +21,7 @@ void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea
} }
if (branch.isProjectile) { if (branch.isProjectile) {
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (target != nullptr) { if (target != nullptr) {
origin = target; origin = target;
@ -38,10 +38,10 @@ void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea
info.spawnerNodeID = 0; info.spawnerNodeID = 0;
info.pos = info.pos + (info.rot.GetForwardVector() * m_Distance); info.pos = info.pos + (info.rot.GetForwardVector() * m_Distance);
auto* entity = EntityManager::Instance()->CreateEntity( auto* entity = Game::entityManager->CreateEntity(
info, info,
nullptr, nullptr,
EntityManager::Instance()->GetEntity(context->originator) Game::entityManager->GetEntity(context->originator)
); );
if (entity == nullptr) { if (entity == nullptr) {
@ -59,7 +59,7 @@ void SpawnBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea
rebuildComponent->SetRepositionPlayer(false); rebuildComponent->SetRepositionPlayer(false);
} }
EntityManager::Instance()->ConstructEntity(entity); Game::entityManager->ConstructEntity(entity);
if (branch.duration > 0) { if (branch.duration > 0) {
context->RegisterTimerBehavior(this, branch, entity->GetObjectID()); context->RegisterTimerBehavior(this, branch, entity->GetObjectID());
@ -79,7 +79,7 @@ void SpawnBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitSt
} }
void SpawnBehavior::Timer(BehaviorContext* context, const BehaviorBranchContext branch, const LWOOBJID second) { void SpawnBehavior::Timer(BehaviorContext* context, const BehaviorBranchContext branch, const LWOOBJID second) {
auto* entity = EntityManager::Instance()->GetEntity(second); auto* entity = Game::entityManager->GetEntity(second);
if (entity == nullptr) { if (entity == nullptr) {
Game::logger->Log("SpawnBehavior", "Failed to find spawned entity (%llu)!", second); Game::logger->Log("SpawnBehavior", "Failed to find spawned entity (%llu)!", second);

View File

@ -9,14 +9,14 @@
void SpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void SpeedBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
if (m_AffectsCaster) branch.target = context->caster; if (m_AffectsCaster) branch.target = context->caster;
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (!target) return; if (!target) return;
auto* controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>(); auto* controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>();
if (!controllablePhysicsComponent) return; if (!controllablePhysicsComponent) return;
controllablePhysicsComponent->AddSpeedboost(m_RunSpeed); controllablePhysicsComponent->AddSpeedboost(m_RunSpeed);
EntityManager::Instance()->SerializeEntity(target); Game::entityManager->SerializeEntity(target);
if (branch.duration > 0.0f) { if (branch.duration > 0.0f) {
context->RegisterTimerBehavior(this, branch); context->RegisterTimerBehavior(this, branch);
@ -38,14 +38,14 @@ void SpeedBehavior::Timer(BehaviorContext* context, BehaviorBranchContext branch
} }
void SpeedBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) { void SpeedBehavior::End(BehaviorContext* context, BehaviorBranchContext branch, LWOOBJID second) {
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (!target) return; if (!target) return;
auto* controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>(); auto* controllablePhysicsComponent = target->GetComponent<ControllablePhysicsComponent>();
if (!controllablePhysicsComponent) return; if (!controllablePhysicsComponent) return;
controllablePhysicsComponent->RemoveSpeedboost(m_RunSpeed); controllablePhysicsComponent->RemoveSpeedboost(m_RunSpeed);
EntityManager::Instance()->SerializeEntity(target); Game::entityManager->SerializeEntity(target);
} }
void SpeedBehavior::Load() { void SpeedBehavior::Load() {

View File

@ -21,7 +21,7 @@ void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream
return; return;
}; };
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) { if (target == nullptr) {
Game::logger->Log("StunBehavior", "Failed to find target (%llu)!", branch.target); Game::logger->Log("StunBehavior", "Failed to find target (%llu)!", branch.target);
@ -44,7 +44,7 @@ void StunBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream
void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) { void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, const BehaviorBranchContext branch) {
if (this->m_stunCaster || branch.target == context->originator) { if (this->m_stunCaster || branch.target == context->originator) {
auto* self = EntityManager::Instance()->GetEntity(context->originator); auto* self = Game::entityManager->GetEntity(context->originator);
if (self == nullptr) { if (self == nullptr) {
Game::logger->Log("StunBehavior", "Invalid self entity (%llu)!", context->originator); Game::logger->Log("StunBehavior", "Invalid self entity (%llu)!", context->originator);
@ -69,7 +69,7 @@ void StunBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStr
bool blocked = false; bool blocked = false;
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (target != nullptr) { if (target != nullptr) {
auto* destroyableComponent = target->GetComponent<DestroyableComponent>(); auto* destroyableComponent = target->GetComponent<DestroyableComponent>();

View File

@ -16,7 +16,7 @@ void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
}; };
} }
auto* entity = EntityManager::Instance()->GetEntity(context->originator); auto* entity = Game::entityManager->GetEntity(context->originator);
if (entity == nullptr) { if (entity == nullptr) {
return; return;
@ -30,7 +30,7 @@ void SwitchBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
Game::logger->LogDebug("SwitchBehavior", "[%i] State: (%d), imagination: (%i) / (%f)", entity->GetLOT(), state, destroyableComponent->GetImagination(), destroyableComponent->GetMaxImagination()); Game::logger->LogDebug("SwitchBehavior", "[%i] State: (%d), imagination: (%i) / (%f)", entity->GetLOT(), state, destroyableComponent->GetImagination(), destroyableComponent->GetMaxImagination());
if (state || (entity->GetLOT() == 8092 && destroyableComponent->GetImagination() >= m_imagination)) { if (state) {
this->m_actionTrue->Handle(context, bitStream, branch); this->m_actionTrue->Handle(context, bitStream, branch);
} else { } else {
this->m_actionFalse->Handle(context, bitStream, branch); this->m_actionFalse->Handle(context, bitStream, branch);
@ -41,7 +41,7 @@ void SwitchBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
auto state = true; auto state = true;
if (this->m_imagination > 0 || !this->m_isEnemyFaction) { if (this->m_imagination > 0 || !this->m_isEnemyFaction) {
auto* entity = EntityManager::Instance()->GetEntity(branch.target); auto* entity = Game::entityManager->GetEntity(branch.target);
state = entity != nullptr; state = entity != nullptr;

View File

@ -76,7 +76,7 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
} }
void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* self = EntityManager::Instance()->GetEntity(context->originator); auto* self = Game::entityManager->GetEntity(context->originator);
if (self == nullptr) { if (self == nullptr) {
Game::logger->Log("TacArcBehavior", "Invalid self for (%llu)!", context->originator); Game::logger->Log("TacArcBehavior", "Invalid self for (%llu)!", context->originator);
return; return;
@ -85,7 +85,7 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
const auto* destroyableComponent = self->GetComponent<DestroyableComponent>(); const auto* destroyableComponent = self->GetComponent<DestroyableComponent>();
if ((this->m_usePickedTarget || context->clientInitalized) && branch.target > 0) { if ((this->m_usePickedTarget || context->clientInitalized) && branch.target > 0) {
const auto* target = EntityManager::Instance()->GetEntity(branch.target); const auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) { if (target == nullptr) {
return; return;
@ -120,7 +120,7 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
// Find all valid targets, based on whether we target enemies or friends // Find all valid targets, based on whether we target enemies or friends
for (const auto& contextTarget : context->GetValidTargets()) { for (const auto& contextTarget : context->GetValidTargets()) {
if (destroyableComponent != nullptr) { if (destroyableComponent != nullptr) {
const auto* targetEntity = EntityManager::Instance()->GetEntity(contextTarget); const auto* targetEntity = Game::entityManager->GetEntity(contextTarget);
if (m_targetEnemy && destroyableComponent->IsEnemy(targetEntity) if (m_targetEnemy && destroyableComponent->IsEnemy(targetEntity)
|| m_targetFriend && destroyableComponent->IsFriend(targetEntity)) { || m_targetFriend && destroyableComponent->IsFriend(targetEntity)) {
@ -136,7 +136,7 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
break; break;
} }
auto* entity = EntityManager::Instance()->GetEntity(validTarget); auto* entity = Game::entityManager->GetEntity(validTarget);
if (entity == nullptr) { if (entity == nullptr) {
Game::logger->Log("TacArcBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator); Game::logger->Log("TacArcBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator);

View File

@ -7,7 +7,7 @@
void TauntBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void TauntBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) { if (target == nullptr) {
Game::logger->Log("TauntBehavior", "Failed to find target (%llu)!", branch.target); Game::logger->Log("TauntBehavior", "Failed to find target (%llu)!", branch.target);
@ -23,7 +23,7 @@ void TauntBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStrea
} }
void TauntBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void TauntBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* target = EntityManager::Instance()->GetEntity(branch.target); auto* target = Game::entityManager->GetEntity(branch.target);
if (target == nullptr) { if (target == nullptr) {
Game::logger->Log("TauntBehavior", "Failed to find target (%llu)!", branch.target); Game::logger->Log("TauntBehavior", "Failed to find target (%llu)!", branch.target);

View File

@ -5,7 +5,7 @@
void VentureVisionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void VentureVisionBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
const auto targetEntity = EntityManager::Instance()->GetEntity(branch.target); const auto targetEntity = Game::entityManager->GetEntity(branch.target);
if (targetEntity) { if (targetEntity) {
auto characterComponent = targetEntity->GetComponent<CharacterComponent>(); auto characterComponent = targetEntity->GetComponent<CharacterComponent>();
@ -21,7 +21,7 @@ void VentureVisionBehavior::Handle(BehaviorContext* context, RakNet::BitStream*
} }
void VentureVisionBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) { void VentureVisionBehavior::UnCast(BehaviorContext* context, BehaviorBranchContext branch) {
const auto targetEntity = EntityManager::Instance()->GetEntity(branch.target); const auto targetEntity = Game::entityManager->GetEntity(branch.target);
if (targetEntity) { if (targetEntity) {
auto characterComponent = targetEntity->GetComponent<CharacterComponent>(); auto characterComponent = targetEntity->GetComponent<CharacterComponent>();

View File

@ -8,14 +8,14 @@
void VerifyBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) { void VerifyBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
auto* entity = EntityManager::Instance()->GetEntity(branch.target); auto* entity = Game::entityManager->GetEntity(branch.target);
auto success = true; auto success = true;
if (entity == nullptr) { if (entity == nullptr) {
success = false; success = false;
} else if (this->m_rangeCheck) { } else if (this->m_rangeCheck) {
auto* self = EntityManager::Instance()->GetEntity(context->originator); auto* self = Game::entityManager->GetEntity(context->originator);
if (self == nullptr) { if (self == nullptr) {
Game::logger->Log("VerifyBehavior", "Invalid self for (%llu)", context->originator); Game::logger->Log("VerifyBehavior", "Invalid self for (%llu)", context->originator);

View File

@ -173,7 +173,7 @@ void BaseCombatAIComponent::Update(const float deltaTime) {
} }
if (m_SoftTimer <= 0.0f) { if (m_SoftTimer <= 0.0f) {
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
m_SoftTimer = 5.0f; m_SoftTimer = 5.0f;
} else { } else {
@ -305,7 +305,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) {
} }
if (serilizationRequired) { if (serilizationRequired) {
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), 6270, u"tether", "tether"); GameMessages::SendPlayFXEffect(m_Parent->GetObjectID(), 6270, u"tether", "tether");
@ -412,7 +412,7 @@ LWOOBJID BaseCombatAIComponent::FindTarget() {
float biggestThreat = 0; float biggestThreat = 0;
for (const auto& entry : possibleTargets) { for (const auto& entry : possibleTargets) {
auto* entity = EntityManager::Instance()->GetEntity(entry); auto* entity = Game::entityManager->GetEntity(entry);
if (entity == nullptr) { if (entity == nullptr) {
continue; continue;
@ -458,7 +458,7 @@ LWOOBJID BaseCombatAIComponent::FindTarget() {
std::vector<LWOOBJID> deadThreats{}; std::vector<LWOOBJID> deadThreats{};
for (const auto& threatTarget : m_ThreatEntries) { for (const auto& threatTarget : m_ThreatEntries) {
auto* entity = EntityManager::Instance()->GetEntity(threatTarget.first); auto* entity = Game::entityManager->GetEntity(threatTarget.first);
if (entity == nullptr) { if (entity == nullptr) {
deadThreats.push_back(threatTarget.first); deadThreats.push_back(threatTarget.first);
@ -497,7 +497,7 @@ std::vector<LWOOBJID> BaseCombatAIComponent::GetTargetWithinAggroRange() const {
std::vector<LWOOBJID> targets; std::vector<LWOOBJID> targets;
for (auto id : m_Parent->GetTargetsInPhantom()) { for (auto id : m_Parent->GetTargetsInPhantom()) {
auto* other = EntityManager::Instance()->GetEntity(id); auto* other = Game::entityManager->GetEntity(id);
const auto distance = Vector3::DistanceSquared(m_Parent->GetPosition(), other->GetPosition()); const auto distance = Vector3::DistanceSquared(m_Parent->GetPosition(), other->GetPosition());
@ -535,11 +535,11 @@ void BaseCombatAIComponent::SetAiState(AiState newState) {
if (newState == this->m_State) return; if (newState == this->m_State) return;
this->m_State = newState; this->m_State = newState;
m_DirtyStateOrTarget = true; m_DirtyStateOrTarget = true;
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const { bool BaseCombatAIComponent::IsEnemy(LWOOBJID target) const {
auto* entity = EntityManager::Instance()->GetEntity(target); auto* entity = Game::entityManager->GetEntity(target);
if (entity == nullptr) { if (entity == nullptr) {
Game::logger->Log("BaseCombatAIComponent", "Invalid entity for checking validity (%llu)!", target); Game::logger->Log("BaseCombatAIComponent", "Invalid entity for checking validity (%llu)!", target);
@ -588,11 +588,11 @@ void BaseCombatAIComponent::SetTarget(const LWOOBJID target) {
if (this->m_Target == target) return; if (this->m_Target == target) return;
m_Target = target; m_Target = target;
m_DirtyStateOrTarget = true; m_DirtyStateOrTarget = true;
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
Entity* BaseCombatAIComponent::GetTargetEntity() const { Entity* BaseCombatAIComponent::GetTargetEntity() const {
return EntityManager::Instance()->GetEntity(m_Target); return Game::entityManager->GetEntity(m_Target);
} }
void BaseCombatAIComponent::Taunt(LWOOBJID offender, float threat) { void BaseCombatAIComponent::Taunt(LWOOBJID offender, float threat) {

View File

@ -36,7 +36,7 @@ Entity* BouncerComponent::GetParentEntity() const {
void BouncerComponent::SetPetEnabled(bool value) { void BouncerComponent::SetPetEnabled(bool value) {
m_PetEnabled = value; m_PetEnabled = value;
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void BouncerComponent::SetPetBouncerEnabled(bool value) { void BouncerComponent::SetPetBouncerEnabled(bool value) {
@ -44,7 +44,7 @@ void BouncerComponent::SetPetBouncerEnabled(bool value) {
GameMessages::SendBouncerActiveStatus(m_Parent->GetObjectID(), value, UNASSIGNED_SYSTEM_ADDRESS); GameMessages::SendBouncerActiveStatus(m_Parent->GetObjectID(), value, UNASSIGNED_SYSTEM_ADDRESS);
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
if (value) { if (value) {
m_Parent->TriggerEvent(eTriggerEventType::PET_ON_SWITCH, m_Parent); m_Parent->TriggerEvent(eTriggerEventType::PET_ON_SWITCH, m_Parent);
@ -68,7 +68,7 @@ void BouncerComponent::LookupPetSwitch() {
const auto& groups = m_Parent->GetGroups(); const auto& groups = m_Parent->GetGroups();
for (const auto& group : groups) { for (const auto& group : groups) {
const auto& entities = EntityManager::Instance()->GetEntitiesInGroup(group); const auto& entities = Game::entityManager->GetEntitiesInGroup(group);
for (auto* entity : entities) { for (auto* entity : entities) {
auto* switchComponent = entity->GetComponent<SwitchComponent>(); auto* switchComponent = entity->GetComponent<SwitchComponent>();
@ -79,7 +79,7 @@ void BouncerComponent::LookupPetSwitch() {
m_PetSwitchLoaded = true; m_PetSwitchLoaded = true;
m_PetEnabled = true; m_PetEnabled = true;
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
Game::logger->Log("BouncerComponent", "Loaded pet bouncer"); Game::logger->Log("BouncerComponent", "Loaded pet bouncer");
} }

View File

@ -17,7 +17,7 @@ BuildBorderComponent::~BuildBorderComponent() {
void BuildBorderComponent::OnUse(Entity* originator) { void BuildBorderComponent::OnUse(Entity* originator) {
if (originator->GetCharacter()) { if (originator->GetCharacter()) {
const auto& entities = EntityManager::Instance()->GetEntitiesInGroup("PropertyPlaque"); const auto& entities = Game::entityManager->GetEntitiesInGroup("PropertyPlaque");
auto buildArea = m_Parent->GetObjectID(); auto buildArea = m_Parent->GetObjectID();

View File

@ -13,7 +13,7 @@
#include "VehiclePhysicsComponent.h" #include "VehiclePhysicsComponent.h"
#include "GameMessages.h" #include "GameMessages.h"
#include "Item.h" #include "Item.h"
#include "AMFFormat.h" #include "Amf3.h"
#include "eGameMasterLevel.h" #include "eGameMasterLevel.h"
#include "eGameActivity.h" #include "eGameActivity.h"
@ -419,7 +419,7 @@ void CharacterComponent::TrackMissionCompletion(bool isAchievement) {
// Achievements are tracked separately for the zone // Achievements are tracked separately for the zone
if (isAchievement) { if (isAchievement) {
const auto mapID = dZoneManager::Instance()->GetZoneID().GetMapID(); const auto mapID = Game::zoneManager->GetZoneID().GetMapID();
GetZoneStatisticsForMap(mapID).m_AchievementsCollected++; GetZoneStatisticsForMap(mapID).m_AchievementsCollected++;
} }
} }
@ -480,7 +480,7 @@ void CharacterComponent::TrackArmorDelta(int32_t armor) {
void CharacterComponent::TrackRebuildComplete() { void CharacterComponent::TrackRebuildComplete() {
UpdatePlayerStatistic(QuickBuildsCompleted); UpdatePlayerStatistic(QuickBuildsCompleted);
const auto mapID = dZoneManager::Instance()->GetZoneID().GetMapID(); const auto mapID = Game::zoneManager->GetZoneID().GetMapID();
GetZoneStatisticsForMap(mapID).m_QuickBuildsCompleted++; GetZoneStatisticsForMap(mapID).m_QuickBuildsCompleted++;
} }
@ -734,6 +734,6 @@ void CharacterComponent::RemoveVentureVisionEffect(std::string ventureVisionType
void CharacterComponent::UpdateClientMinimap(bool showFaction, std::string ventureVisionType) const { void CharacterComponent::UpdateClientMinimap(bool showFaction, std::string ventureVisionType) const {
if (!m_Parent) return; if (!m_Parent) return;
AMFArrayValue arrayToSend; AMFArrayValue arrayToSend;
arrayToSend.InsertValue(ventureVisionType, showFaction ? static_cast<AMFValue*>(new AMFTrueValue()) : static_cast<AMFValue*>(new AMFFalseValue())); arrayToSend.Insert(ventureVisionType, showFaction);
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent ? m_Parent->GetSystemAddress() : UNASSIGNED_SYSTEM_ADDRESS, "SetFactionVisibility", &arrayToSend); GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent ? m_Parent->GetSystemAddress() : UNASSIGNED_SYSTEM_ADDRESS, "SetFactionVisibility", arrayToSend);
} }

View File

@ -194,7 +194,7 @@ void ControllablePhysicsComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
return; return;
} }
auto zoneInfo = dZoneManager::Instance()->GetZone()->GetZoneID(); auto zoneInfo = Game::zoneManager->GetZone()->GetZoneID();
if (zoneInfo.GetMapID() != 0 && zoneInfo.GetCloneID() == 0) { if (zoneInfo.GetMapID() != 0 && zoneInfo.GetCloneID() == 0) {
character->SetAttribute("lzx", m_Position.x); character->SetAttribute("lzx", m_Position.x);
@ -300,7 +300,7 @@ void ControllablePhysicsComponent::RemovePickupRadiusScale(float value) {
auto candidateRadius = m_ActivePickupRadiusScales[i]; auto candidateRadius = m_ActivePickupRadiusScales[i];
if (m_PickupRadius < candidateRadius) m_PickupRadius = candidateRadius; if (m_PickupRadius < candidateRadius) m_PickupRadius = candidateRadius;
} }
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void ControllablePhysicsComponent::AddSpeedboost(float value) { void ControllablePhysicsComponent::AddSpeedboost(float value) {
@ -320,14 +320,14 @@ void ControllablePhysicsComponent::RemoveSpeedboost(float value) {
// Recalculate speedboost since we removed one // Recalculate speedboost since we removed one
m_SpeedBoost = 0.0f; m_SpeedBoost = 0.0f;
if (m_ActiveSpeedBoosts.size() == 0) { // no active speed boosts left, so return to base speed if (m_ActiveSpeedBoosts.empty()) { // no active speed boosts left, so return to base speed
auto* levelProgressionComponent = m_Parent->GetComponent<LevelProgressionComponent>(); auto* levelProgressionComponent = m_Parent->GetComponent<LevelProgressionComponent>();
if (levelProgressionComponent) m_SpeedBoost = levelProgressionComponent->GetSpeedBase(); if (levelProgressionComponent) m_SpeedBoost = levelProgressionComponent->GetSpeedBase();
} else { // Used the last applied speedboost } else { // Used the last applied speedboost
m_SpeedBoost = m_ActiveSpeedBoosts.back(); m_SpeedBoost = m_ActiveSpeedBoosts.back();
} }
SetSpeedMultiplier(m_SpeedBoost / 500.0f); // 500 being the base speed SetSpeedMultiplier(m_SpeedBoost / 500.0f); // 500 being the base speed
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void ControllablePhysicsComponent::ActivateBubbleBuff(eBubbleType bubbleType, bool specialAnims){ void ControllablePhysicsComponent::ActivateBubbleBuff(eBubbleType bubbleType, bool specialAnims){
@ -339,13 +339,13 @@ void ControllablePhysicsComponent::ActivateBubbleBuff(eBubbleType bubbleType, bo
m_IsInBubble = true; m_IsInBubble = true;
m_DirtyBubble = true; m_DirtyBubble = true;
m_SpecialAnims = specialAnims; m_SpecialAnims = specialAnims;
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void ControllablePhysicsComponent::DeactivateBubbleBuff(){ void ControllablePhysicsComponent::DeactivateBubbleBuff(){
m_DirtyBubble = true; m_DirtyBubble = true;
m_IsInBubble = false; m_IsInBubble = false;
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
}; };
void ControllablePhysicsComponent::SetStunImmunity( void ControllablePhysicsComponent::SetStunImmunity(

View File

@ -276,7 +276,7 @@ public:
* The speed boosts of this component. * The speed boosts of this component.
* @return All active Speed boosts for this component. * @return All active Speed boosts for this component.
*/ */
std::vector<float> GetActiveSpeedboosts() { return m_ActivePickupRadiusScales; }; std::vector<float> GetActiveSpeedboosts() { return m_ActiveSpeedBoosts; };
/** /**
* Activates the Bubble Buff * Activates the Bubble Buff

View File

@ -4,8 +4,8 @@
#include "Game.h" #include "Game.h"
#include "dConfig.h" #include "dConfig.h"
#include "AMFFormat.h" #include "Amf3.h"
#include "AMFFormat_BitStream.h" #include "AmfSerialize.h"
#include "GameMessages.h" #include "GameMessages.h"
#include "User.h" #include "User.h"
#include "CDClientManager.h" #include "CDClientManager.h"
@ -51,7 +51,7 @@ DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) {
m_IsGMImmune = false; m_IsGMImmune = false;
m_IsShielded = false; m_IsShielded = false;
m_DamageToAbsorb = 0; m_DamageToAbsorb = 0;
m_HasBricks = false; m_IsModuleAssembly = m_Parent->HasComponent(eReplicaComponentType::MODULE_ASSEMBLY);
m_DirtyThreatList = false; m_DirtyThreatList = false;
m_HasThreats = false; m_HasThreats = false;
m_ExplodeFactor = 1.0f; m_ExplodeFactor = 1.0f;
@ -163,7 +163,7 @@ void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsIn
outBitStream->Write(m_IsSmashed); outBitStream->Write(m_IsSmashed);
if (m_IsSmashable) { if (m_IsSmashable) {
outBitStream->Write(m_HasBricks); outBitStream->Write(m_IsModuleAssembly);
outBitStream->Write(m_ExplodeFactor != 1.0f); outBitStream->Write(m_ExplodeFactor != 1.0f);
if (m_ExplodeFactor != 1.0f) outBitStream->Write(m_ExplodeFactor); if (m_ExplodeFactor != 1.0f) outBitStream->Write(m_ExplodeFactor);
} }
@ -245,19 +245,15 @@ void DestroyableComponent::SetMaxHealth(float value, bool playAnim) {
if (playAnim) { if (playAnim) {
// Now update the player bar // Now update the player bar
if (!m_Parent->GetParentUser()) return; if (!m_Parent->GetParentUser()) return;
AMFStringValue* amount = new AMFStringValue();
amount->SetStringValue(std::to_string(difference));
AMFStringValue* type = new AMFStringValue();
type->SetStringValue("health");
AMFArrayValue args; AMFArrayValue args;
args.InsertValue("amount", amount); args.Insert("amount", std::to_string(difference));
args.InsertValue("type", type); args.Insert("type", "health");
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args); GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", args);
} }
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void DestroyableComponent::SetArmor(int32_t value) { void DestroyableComponent::SetArmor(int32_t value) {
@ -290,19 +286,15 @@ void DestroyableComponent::SetMaxArmor(float value, bool playAnim) {
if (playAnim) { if (playAnim) {
// Now update the player bar // Now update the player bar
if (!m_Parent->GetParentUser()) return; if (!m_Parent->GetParentUser()) return;
AMFStringValue* amount = new AMFStringValue();
amount->SetStringValue(std::to_string(value));
AMFStringValue* type = new AMFStringValue();
type->SetStringValue("armor");
AMFArrayValue args; AMFArrayValue args;
args.InsertValue("amount", amount); args.Insert("amount", std::to_string(value));
args.InsertValue("type", type); args.Insert("type", "armor");
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args); GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", args);
} }
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void DestroyableComponent::SetImagination(int32_t value) { void DestroyableComponent::SetImagination(int32_t value) {
@ -334,18 +326,14 @@ void DestroyableComponent::SetMaxImagination(float value, bool playAnim) {
if (playAnim) { if (playAnim) {
// Now update the player bar // Now update the player bar
if (!m_Parent->GetParentUser()) return; if (!m_Parent->GetParentUser()) return;
AMFStringValue* amount = new AMFStringValue();
amount->SetStringValue(std::to_string(difference));
AMFStringValue* type = new AMFStringValue();
type->SetStringValue("imagination");
AMFArrayValue args; AMFArrayValue args;
args.InsertValue("amount", amount); args.Insert("amount", std::to_string(difference));
args.InsertValue("type", type); args.Insert("type", "imagination");
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", &args); GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent->GetParentUser()->GetSystemAddress(), "MaxPlayerBarUpdate", args);
} }
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void DestroyableComponent::SetDamageToAbsorb(int32_t value) { void DestroyableComponent::SetDamageToAbsorb(int32_t value) {
@ -494,11 +482,11 @@ LWOOBJID DestroyableComponent::GetKillerID() const {
} }
Entity* DestroyableComponent::GetKiller() const { Entity* DestroyableComponent::GetKiller() const {
return EntityManager::Instance()->GetEntity(m_KillerID); return Game::entityManager->GetEntity(m_KillerID);
} }
bool DestroyableComponent::CheckValidity(const LWOOBJID target, const bool ignoreFactions, const bool targetEnemy, const bool targetFriend) const { bool DestroyableComponent::CheckValidity(const LWOOBJID target, const bool ignoreFactions, const bool targetEnemy, const bool targetFriend) const {
auto* targetEntity = EntityManager::Instance()->GetEntity(target); auto* targetEntity = Game::entityManager->GetEntity(target);
if (targetEntity == nullptr) { if (targetEntity == nullptr) {
Game::logger->Log("DestroyableComponent", "Invalid entity for checking validity (%llu)!", target); Game::logger->Log("DestroyableComponent", "Invalid entity for checking validity (%llu)!", target);
@ -544,7 +532,7 @@ void DestroyableComponent::Heal(const uint32_t health) {
SetHealth(current); SetHealth(current);
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
@ -562,7 +550,7 @@ void DestroyableComponent::Imagine(const int32_t deltaImagination) {
SetImagination(current); SetImagination(current);
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
@ -576,7 +564,7 @@ void DestroyableComponent::Repair(const uint32_t armor) {
SetArmor(current); SetArmor(current);
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
@ -638,7 +626,7 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
if (possessor) { if (possessor) {
auto possessableId = possessor->GetPossessable(); auto possessableId = possessor->GetPossessable();
if (possessableId != LWOOBJID_EMPTY) { if (possessableId != LWOOBJID_EMPTY) {
auto possessable = EntityManager::Instance()->GetEntity(possessableId); auto possessable = Game::entityManager->GetEntity(possessableId);
if (possessable) { if (possessable) {
possessor->Dismount(possessable); possessor->Dismount(possessable);
} }
@ -650,10 +638,10 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
} }
if (echo) { if (echo) {
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
auto* attacker = EntityManager::Instance()->GetEntity(source); auto* attacker = Game::entityManager->GetEntity(source);
m_Parent->OnHit(attacker); m_Parent->OnHit(attacker);
m_Parent->OnHitOrHealResult(attacker, sourceDamage); m_Parent->OnHitOrHealResult(attacker, sourceDamage);
NotifySubscribers(attacker, sourceDamage); NotifySubscribers(attacker, sourceDamage);
@ -673,7 +661,7 @@ void DestroyableComponent::Damage(uint32_t damage, const LWOOBJID source, uint32
} }
//check if hardcore mode is enabled //check if hardcore mode is enabled
if (EntityManager::Instance()->GetHardcoreMode()) { if (Game::entityManager->GetHardcoreMode()) {
DoHardcoreModeDrops(source); DoHardcoreModeDrops(source);
} }
@ -708,12 +696,12 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
SetArmor(0); SetArmor(0);
SetHealth(0); SetHealth(0);
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
m_KillerID = source; m_KillerID = source;
auto* owner = EntityManager::Instance()->GetEntity(source); auto* owner = Game::entityManager->GetEntity(source);
if (owner != nullptr) { if (owner != nullptr) {
owner = owner->GetOwner(); // If the owner is overwritten, we collect that here owner = owner->GetOwner(); // If the owner is overwritten, we collect that here
@ -733,7 +721,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
if (missions != nullptr) { if (missions != nullptr) {
if (team != nullptr) { if (team != nullptr) {
for (const auto memberId : team->members) { for (const auto memberId : team->members) {
auto* member = EntityManager::Instance()->GetEntity(memberId); auto* member = Game::entityManager->GetEntity(memberId);
if (member == nullptr) continue; if (member == nullptr) continue;
@ -773,12 +761,12 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
if (team->lootOption == 0) { // Round robin if (team->lootOption == 0) { // Round robin
specificOwner = TeamManager::Instance()->GetNextLootOwner(team); specificOwner = TeamManager::Instance()->GetNextLootOwner(team);
auto* member = EntityManager::Instance()->GetEntity(specificOwner); auto* member = Game::entityManager->GetEntity(specificOwner);
if (member) LootGenerator::Instance().DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins()); if (member) LootGenerator::Instance().DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins());
} else { } else {
for (const auto memberId : team->members) { // Free for all for (const auto memberId : team->members) { // Free for all
auto* member = EntityManager::Instance()->GetEntity(memberId); auto* member = Game::entityManager->GetEntity(memberId);
if (member == nullptr) continue; if (member == nullptr) continue;
@ -791,13 +779,13 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
} }
} else { } else {
//Check if this zone allows coin drops //Check if this zone allows coin drops
if (dZoneManager::Instance()->GetPlayerLoseCoinOnDeath()) { if (Game::zoneManager->GetPlayerLoseCoinOnDeath()) {
auto* character = m_Parent->GetCharacter(); auto* character = m_Parent->GetCharacter();
uint64_t coinsTotal = character->GetCoins(); uint64_t coinsTotal = character->GetCoins();
const uint64_t minCoinsToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathMin; const uint64_t minCoinsToLose = Game::zoneManager->GetWorldConfig()->coinsLostOnDeathMin;
if (coinsTotal >= minCoinsToLose) { if (coinsTotal >= minCoinsToLose) {
const uint64_t maxCoinsToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathMax; const uint64_t maxCoinsToLose = Game::zoneManager->GetWorldConfig()->coinsLostOnDeathMax;
const float coinPercentageToLose = dZoneManager::Instance()->GetWorldConfig()->coinsLostOnDeathPercent; const float coinPercentageToLose = Game::zoneManager->GetWorldConfig()->coinsLostOnDeathPercent;
uint64_t coinsToLose = std::max(static_cast<uint64_t>(coinsTotal * coinPercentageToLose), minCoinsToLose); uint64_t coinsToLose = std::max(static_cast<uint64_t>(coinsTotal * coinPercentageToLose), minCoinsToLose);
coinsToLose = std::min(maxCoinsToLose, coinsToLose); coinsToLose = std::min(maxCoinsToLose, coinsToLose);
@ -809,12 +797,12 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
} }
} }
Entity* zoneControl = EntityManager::Instance()->GetZoneControlEntity(); Entity* zoneControl = Game::entityManager->GetZoneControlEntity();
for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControl)) {
script->OnPlayerDied(zoneControl, m_Parent); script->OnPlayerDied(zoneControl, m_Parent);
} }
std::vector<Entity*> scriptedActs = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY); std::vector<Entity*> scriptedActs = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::SCRIPTED_ACTIVITY);
for (Entity* scriptEntity : scriptedActs) { for (Entity* scriptEntity : scriptedActs) {
if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds if (scriptEntity->GetObjectID() != zoneControl->GetObjectID()) { // Don't want to trigger twice on instance worlds
for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(scriptEntity)) {
@ -977,7 +965,7 @@ void DestroyableComponent::FixStats() {
destroyableComponent->SetImagination(currentImagination); destroyableComponent->SetImagination(currentImagination);
// Serialize the entity // Serialize the entity
EntityManager::Instance()->SerializeEntity(entity); Game::entityManager->SerializeEntity(entity);
} }
void DestroyableComponent::AddOnHitCallback(const std::function<void(Entity*)>& callback) { void DestroyableComponent::AddOnHitCallback(const std::function<void(Entity*)>& callback) {
@ -991,12 +979,12 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source){
auto* character = m_Parent->GetComponent<CharacterComponent>(); auto* character = m_Parent->GetComponent<CharacterComponent>();
auto uscore = character->GetUScore(); auto uscore = character->GetUScore();
auto uscoreToLose = uscore * (EntityManager::Instance()->GetHardcoreLoseUscoreOnDeathPercent() / 100); auto uscoreToLose = uscore * (Game::entityManager->GetHardcoreLoseUscoreOnDeathPercent() / 100);
character->SetUScore(uscore - uscoreToLose); character->SetUScore(uscore - uscoreToLose);
GameMessages::SendModifyLEGOScore(m_Parent, m_Parent->GetSystemAddress(), -uscoreToLose, eLootSourceType::MISSION); GameMessages::SendModifyLEGOScore(m_Parent, m_Parent->GetSystemAddress(), -uscoreToLose, eLootSourceType::MISSION);
if (EntityManager::Instance()->GetHardcoreDropinventoryOnDeath()) { if (Game::entityManager->GetHardcoreDropinventoryOnDeath()) {
//drop all items from inventory: //drop all items from inventory:
auto* inventory = m_Parent->GetComponent<InventoryComponent>(); auto* inventory = m_Parent->GetComponent<InventoryComponent>();
if (inventory) { if (inventory) {
@ -1013,7 +1001,7 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source){
GameMessages::SendDropClientLoot(m_Parent, source, item.second->GetLot(), 0, m_Parent->GetPosition(), item.second->GetCount()); GameMessages::SendDropClientLoot(m_Parent, source, item.second->GetLot(), 0, m_Parent->GetPosition(), item.second->GetCount());
item.second->SetCount(0, false, false); item.second->SetCount(0, false, false);
} }
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
} }
} }
@ -1033,25 +1021,25 @@ void DestroyableComponent::DoHardcoreModeDrops(const LWOOBJID source){
// Reload the player since we can't normally reduce uscore from the server and we want the UI to update // Reload the player since we can't normally reduce uscore from the server and we want the UI to update
// do this last so we don't get killed.... again // do this last so we don't get killed.... again
EntityManager::Instance()->DestructEntity(m_Parent); Game::entityManager->DestructEntity(m_Parent);
EntityManager::Instance()->ConstructEntity(m_Parent); Game::entityManager->ConstructEntity(m_Parent);
return; return;
} }
//award the player some u-score: //award the player some u-score:
auto* player = EntityManager::Instance()->GetEntity(source); auto* player = Game::entityManager->GetEntity(source);
if (player && player->IsPlayer()) { if (player && player->IsPlayer()) {
auto* playerStats = player->GetComponent<CharacterComponent>(); auto* playerStats = player->GetComponent<CharacterComponent>();
if (playerStats) { if (playerStats) {
//get the maximum health from this enemy: //get the maximum health from this enemy:
auto maxHealth = GetMaxHealth(); auto maxHealth = GetMaxHealth();
int uscore = maxHealth * EntityManager::Instance()->GetHardcoreUscoreEnemiesMultiplier(); int uscore = maxHealth * Game::entityManager->GetHardcoreUscoreEnemiesMultiplier();
playerStats->SetUScore(playerStats->GetUScore() + uscore); playerStats->SetUScore(playerStats->GetUScore() + uscore);
GameMessages::SendModifyLEGOScore(player, player->GetSystemAddress(), uscore, eLootSourceType::MISSION); GameMessages::SendModifyLEGOScore(player, player->GetSystemAddress(), uscore, eLootSourceType::MISSION);
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
} }
} }

View File

@ -239,7 +239,7 @@ public:
* Returns whether or not this entity has bricks flying out when smashed * Returns whether or not this entity has bricks flying out when smashed
* @return whether or not this entity has bricks flying out when smashed * @return whether or not this entity has bricks flying out when smashed
*/ */
bool GetHasBricks() const { return m_HasBricks; } bool GetHasBricks() const { return m_IsModuleAssembly; }
/** /**
* Sets the multiplier for the explosion that's visible when the bricks fly out when this entity is smashed * Sets the multiplier for the explosion that's visible when the bricks fly out when this entity is smashed
@ -546,7 +546,7 @@ private:
/** /**
* Whether this entity has bricks flying out when smashed (causes the client to look up the files) * Whether this entity has bricks flying out when smashed (causes the client to look up the files)
*/ */
bool m_HasBricks; bool m_IsModuleAssembly;
/** /**
* The rate at which bricks fly out when smashed * The rate at which bricks fly out when smashed

View File

@ -826,18 +826,26 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) {
if (character != nullptr && !skipChecks) { if (character != nullptr && !skipChecks) {
// Hacky proximity rocket // Hacky proximity rocket
if (item->GetLot() == 6416) { if (item->GetLot() == 6416) {
const auto rocketLauchPads = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::ROCKET_LAUNCH); const auto rocketLauchPads = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::ROCKET_LAUNCH);
const auto position = m_Parent->GetPosition(); const auto position = m_Parent->GetPosition();
for (auto* lauchPad : rocketLauchPads) { for (auto* launchPad : rocketLauchPads) {
if (Vector3::DistanceSquared(lauchPad->GetPosition(), position) > 13 * 13) continue; if (!launchPad) continue;
auto prereq = launchPad->GetVarAsString(u"rocketLaunchPreCondition");
if (!prereq.empty()) {
PreconditionExpression expression(prereq);
if (!expression.Check(m_Parent)) continue;
}
if (Vector3::DistanceSquared(launchPad->GetPosition(), position) > 13 * 13) continue;
auto* characterComponent = m_Parent->GetComponent<CharacterComponent>(); auto* characterComponent = m_Parent->GetComponent<CharacterComponent>();
if (characterComponent != nullptr) characterComponent->SetLastRocketItemID(item->GetId()); if (characterComponent != nullptr) characterComponent->SetLastRocketItemID(item->GetId());
lauchPad->OnUse(m_Parent); launchPad->OnUse(m_Parent);
break; break;
} }
@ -879,7 +887,7 @@ void InventoryComponent::EquipItem(Item* item, const bool skipChecks) {
EquipScripts(item); EquipScripts(item);
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void InventoryComponent::UnEquipItem(Item* item) { void InventoryComponent::UnEquipItem(Item* item) {
@ -909,12 +917,12 @@ void InventoryComponent::UnEquipItem(Item* item) {
UnequipScripts(item); UnequipScripts(item);
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
// Trigger property event // Trigger property event
if (PropertyManagementComponent::Instance() != nullptr && item->GetCount() > 0 && Inventory::FindInventoryTypeForLot(item->GetLot()) == MODELS) { if (PropertyManagementComponent::Instance() != nullptr && item->GetCount() > 0 && Inventory::FindInventoryTypeForLot(item->GetLot()) == MODELS) {
PropertyManagementComponent::Instance()->GetParent()->OnZonePropertyModelRemovedWhileEquipped(m_Parent); PropertyManagementComponent::Instance()->GetParent()->OnZonePropertyModelRemovedWhileEquipped(m_Parent);
dZoneManager::Instance()->GetZoneControlObject()->OnZonePropertyModelRemovedWhileEquipped(m_Parent); Game::zoneManager->GetZoneControlObject()->OnZonePropertyModelRemovedWhileEquipped(m_Parent);
} }
} }
@ -960,7 +968,7 @@ void InventoryComponent::HandlePossession(Item* item) {
if (possessorComponent->GetIsDismounting()) return; if (possessorComponent->GetIsDismounting()) return;
// Check to see if we are already mounting something // Check to see if we are already mounting something
auto* currentlyPossessedEntity = EntityManager::Instance()->GetEntity(possessorComponent->GetPossessable()); auto* currentlyPossessedEntity = Game::entityManager->GetEntity(possessorComponent->GetPossessable());
auto currentlyPossessedItem = possessorComponent->GetMountItemID(); auto currentlyPossessedItem = possessorComponent->GetMountItemID();
if (currentlyPossessedItem) { if (currentlyPossessedItem) {
@ -983,26 +991,15 @@ void InventoryComponent::HandlePossession(Item* item) {
info.rot = startRotation; info.rot = startRotation;
info.spawnerID = m_Parent->GetObjectID(); info.spawnerID = m_Parent->GetObjectID();
auto* mount = EntityManager::Instance()->CreateEntity(info, nullptr, m_Parent); auto* mount = Game::entityManager->CreateEntity(info, nullptr, m_Parent);
// Check to see if the mount is a vehicle, if so, flip it // Check to see if the mount is a vehicle, if so, flip it
auto* vehicleComponent = mount->GetComponent<VehiclePhysicsComponent>(); auto* vehicleComponent = mount->GetComponent<VehiclePhysicsComponent>();
if (vehicleComponent) { if (vehicleComponent) characterComponent->SetIsRacing(true);
auto angles = startRotation.GetEulerAngles();
// Make it right side up
angles.x -= PI;
// Make it going in the direction of the player
angles.y -= PI;
startRotation = NiQuaternion::FromEulerAngles(angles);
mount->SetRotation(startRotation);
// We're pod racing now
characterComponent->SetIsRacing(true);
}
// Setup the destroyable stats // Setup the destroyable stats
auto* destroyableComponent = mount->GetComponent<DestroyableComponent>(); auto* destroyableComponent = mount->GetComponent<DestroyableComponent>();
if (destroyableComponent) { if (destroyableComponent) {
destroyableComponent->SetIsSmashable(false);
destroyableComponent->SetIsImmune(true); destroyableComponent->SetIsImmune(true);
} }
@ -1019,9 +1016,9 @@ void InventoryComponent::HandlePossession(Item* item) {
GameMessages::SendSetJetPackMode(m_Parent, false); GameMessages::SendSetJetPackMode(m_Parent, false);
// Make it go to the client // Make it go to the client
EntityManager::Instance()->ConstructEntity(mount); Game::entityManager->ConstructEntity(mount);
// Update the possessor // Update the possessor
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
// have to unlock the input so it vehicle can be driven // have to unlock the input so it vehicle can be driven
if (vehicleComponent) GameMessages::SendVehicleUnlockInput(mount->GetObjectID(), false, m_Parent->GetSystemAddress()); if (vehicleComponent) GameMessages::SendVehicleUnlockInput(mount->GetObjectID(), false, m_Parent->GetSystemAddress());
@ -1083,7 +1080,7 @@ void InventoryComponent::PopEquippedItems() {
destroyableComponent->SetHealth(static_cast<int32_t>(destroyableComponent->GetMaxHealth())); destroyableComponent->SetHealth(static_cast<int32_t>(destroyableComponent->GetMaxHealth()));
destroyableComponent->SetArmor(static_cast<int32_t>(destroyableComponent->GetMaxArmor())); destroyableComponent->SetArmor(static_cast<int32_t>(destroyableComponent->GetMaxArmor()));
destroyableComponent->SetImagination(static_cast<int32_t>(destroyableComponent->GetMaxImagination())); destroyableComponent->SetImagination(static_cast<int32_t>(destroyableComponent->GetMaxImagination()));
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
m_Dirty = true; m_Dirty = true;
@ -1259,7 +1256,7 @@ void InventoryComponent::SpawnPet(Item* item) {
info.rot = NiQuaternion::IDENTITY; info.rot = NiQuaternion::IDENTITY;
info.spawnerID = m_Parent->GetObjectID(); info.spawnerID = m_Parent->GetObjectID();
auto* pet = EntityManager::Instance()->CreateEntity(info); auto* pet = Game::entityManager->CreateEntity(info);
auto* petComponent = pet->GetComponent<PetComponent>(); auto* petComponent = pet->GetComponent<PetComponent>();
@ -1267,7 +1264,7 @@ void InventoryComponent::SpawnPet(Item* item) {
petComponent->Activate(item); petComponent->Activate(item);
} }
EntityManager::Instance()->ConstructEntity(pet); Game::entityManager->ConstructEntity(pet);
} }
void InventoryComponent::SetDatabasePet(LWOOBJID id, const DatabasePet& data) { void InventoryComponent::SetDatabasePet(LWOOBJID id, const DatabasePet& data) {
@ -1376,7 +1373,7 @@ void InventoryComponent::SetNPCItems(const std::vector<LOT>& items) {
UpdateSlot(info.equipLocation, { id, static_cast<LOT>(item), 1, slot++ }, true); UpdateSlot(info.equipLocation, { id, static_cast<LOT>(item), 1, slot++ }, true);
} }
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
InventoryComponent::~InventoryComponent() { InventoryComponent::~InventoryComponent() {

View File

@ -35,7 +35,7 @@ void LUPExhibitComponent::NextExhibit() {
m_Exhibit = m_Exhibits[m_ExhibitIndex]; m_Exhibit = m_Exhibits[m_ExhibitIndex];
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void LUPExhibitComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags) { void LUPExhibitComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags) {

View File

@ -13,7 +13,7 @@
#include "InventoryComponent.h" #include "InventoryComponent.h"
#include "GameMessages.h" #include "GameMessages.h"
#include "Game.h" #include "Game.h"
#include "AMFFormat.h" #include "Amf3.h"
#include "dZoneManager.h" #include "dZoneManager.h"
#include "Mail.h" #include "Mail.h"
#include "MissionPrerequisites.h" #include "MissionPrerequisites.h"
@ -26,7 +26,7 @@ std::unordered_map<AchievementCacheKey, std::vector<uint32_t>> MissionComponent:
//! Initializer //! Initializer
MissionComponent::MissionComponent(Entity* parent) : Component(parent) { MissionComponent::MissionComponent(Entity* parent) : Component(parent) {
m_LastUsedMissionOrderUID = dZoneManager::Instance()->GetUniqueMissionIdStartingValue(); m_LastUsedMissionOrderUID = Game::zoneManager->GetUniqueMissionIdStartingValue();
} }
//! Destructor //! Destructor

View File

@ -377,7 +377,7 @@ bool MovementAIComponent::Warp(const NiPoint3& point) {
SetPosition(destination); SetPosition(destination);
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
return true; return true;
} }
@ -406,7 +406,7 @@ void MovementAIComponent::Stop() {
m_CurrentSpeed = 0; m_CurrentSpeed = 0;
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void MovementAIComponent::PullToPoint(const NiPoint3& point) { void MovementAIComponent::PullToPoint(const NiPoint3& point) {
@ -448,13 +448,14 @@ float MovementAIComponent::GetBaseSpeed(LOT lot) {
foundComponent: foundComponent:
float speed; // Client defaults speed to 10 and if the speed is also null in the table, it defaults to 10.
float speed = 10.0f;
if (physicsComponent == nullptr) { if (physicsComponent) speed = physicsComponent->speed;
speed = 8;
} else { float delta = fabs(speed) - 1.0f;
speed = physicsComponent->speed;
} if (delta <= std::numeric_limits<float>::epsilon()) speed = 10.0f;
m_PhysicsSpeedCache[lot] = speed; m_PhysicsSpeedCache[lot] = speed;

View File

@ -59,7 +59,7 @@ MovingPlatformComponent::MovingPlatformComponent(Entity* parent, const std::stri
m_MoverSubComponentType = eMoverSubComponentType::mover; m_MoverSubComponentType = eMoverSubComponentType::mover;
m_MoverSubComponent = new MoverSubComponent(m_Parent->GetDefaultPosition()); m_MoverSubComponent = new MoverSubComponent(m_Parent->GetDefaultPosition());
m_PathName = GeneralUtils::ASCIIToUTF16(pathName); m_PathName = GeneralUtils::ASCIIToUTF16(pathName);
m_Path = dZoneManager::Instance()->GetZone()->GetPath(pathName); m_Path = Game::zoneManager->GetZone()->GetPath(pathName);
m_NoAutoStart = false; m_NoAutoStart = false;
if (m_Path == nullptr) { if (m_Path == nullptr) {
@ -133,7 +133,7 @@ void MovingPlatformComponent::SetMovementState(eMovementPlatformState value) {
subComponent->mState = value; subComponent->mState = value;
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void MovingPlatformComponent::GotoWaypoint(uint32_t index, bool stopAtWaypoint) { void MovingPlatformComponent::GotoWaypoint(uint32_t index, bool stopAtWaypoint) {
@ -194,7 +194,7 @@ void MovingPlatformComponent::StartPathing() {
//GameMessages::SendPlatformResync(m_Parent, UNASSIGNED_SYSTEM_ADDRESS); //GameMessages::SendPlatformResync(m_Parent, UNASSIGNED_SYSTEM_ADDRESS);
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void MovingPlatformComponent::ContinuePathing() { void MovingPlatformComponent::ContinuePathing() {
@ -242,7 +242,7 @@ void MovingPlatformComponent::ContinuePathing() {
subComponent->mCurrentWaypointIndex = pathSize; subComponent->mCurrentWaypointIndex = pathSize;
switch (behavior) { switch (behavior) {
case PathBehavior::Once: case PathBehavior::Once:
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
return; return;
case PathBehavior::Bounce: case PathBehavior::Bounce:
@ -304,7 +304,7 @@ void MovingPlatformComponent::ContinuePathing() {
ContinuePathing(); ContinuePathing();
}); });
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void MovingPlatformComponent::StopPathing() { void MovingPlatformComponent::StopPathing() {
@ -318,7 +318,7 @@ void MovingPlatformComponent::StopPathing() {
subComponent->mDesiredWaypointIndex = -1; subComponent->mDesiredWaypointIndex = -1;
subComponent->mShouldStopAtDesiredWaypoint = false; subComponent->mShouldStopAtDesiredWaypoint = false;
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
//GameMessages::SendPlatformResync(m_Parent, UNASSIGNED_SYSTEM_ADDRESS); //GameMessages::SendPlatformResync(m_Parent, UNASSIGNED_SYSTEM_ADDRESS);
} }
@ -341,7 +341,7 @@ void MovingPlatformComponent::WarpToWaypoint(size_t index) {
m_Parent->SetPosition(waypoint.position); m_Parent->SetPosition(waypoint.position);
m_Parent->SetRotation(waypoint.rotation); m_Parent->SetRotation(waypoint.rotation);
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
size_t MovingPlatformComponent::GetLastWaypointIndex() const { size_t MovingPlatformComponent::GetLastWaypointIndex() const {

View File

@ -26,6 +26,7 @@
#include "Database.h" #include "Database.h"
#include "EntityInfo.h" #include "EntityInfo.h"
#include "eMissionTaskType.h" #include "eMissionTaskType.h"
#include "RenderComponent.h"
#include "eObjectBits.h" #include "eObjectBits.h"
#include "eGameMasterLevel.h" #include "eGameMasterLevel.h"
@ -153,7 +154,7 @@ void PetComponent::OnUse(Entity* originator) {
} }
if (m_Tamer != LWOOBJID_EMPTY) { if (m_Tamer != LWOOBJID_EMPTY) {
auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); auto* tamer = Game::entityManager->GetEntity(m_Tamer);
if (tamer != nullptr) { if (tamer != nullptr) {
return; return;
@ -235,7 +236,7 @@ void PetComponent::OnUse(Entity* originator) {
return; return;
} }
auto& bricks = BrickDatabase::Instance()->GetBricks(buildFile); const auto& bricks = BrickDatabase::GetBricks(buildFile);
if (bricks.empty()) { if (bricks.empty()) {
ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to load the puzzle minigame for this pet."); ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to load the puzzle minigame for this pet.");
@ -343,7 +344,7 @@ void PetComponent::Update(float deltaTime) {
if (m_Timer <= 0) { if (m_Timer <= 0) {
Wander(); Wander();
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
} else { } else {
m_Timer = 5; m_Timer = 5;
@ -368,7 +369,7 @@ void PetComponent::Update(float deltaTime) {
} }
if (m_TresureTime > 0) { if (m_TresureTime > 0) {
auto* tresure = EntityManager::Instance()->GetEntity(m_Interaction); auto* tresure = Game::entityManager->GetEntity(m_Interaction);
if (tresure == nullptr) { if (tresure == nullptr) {
m_TresureTime = 0; m_TresureTime = 0;
@ -448,7 +449,7 @@ void PetComponent::Update(float deltaTime) {
NiPoint3 tresurePosition = closestTresure->GetPosition(); NiPoint3 tresurePosition = closestTresure->GetPosition();
float distance = Vector3::DistanceSquared(position, tresurePosition); float distance = Vector3::DistanceSquared(position, tresurePosition);
if (distance < 3 * 3) { if (distance < 5 * 5) {
m_Interaction = closestTresure->GetObjectID(); m_Interaction = closestTresure->GetObjectID();
Command(NiPoint3::ZERO, LWOOBJID_EMPTY, 1, 202, true); Command(NiPoint3::ZERO, LWOOBJID_EMPTY, 1, 202, true);
@ -475,7 +476,7 @@ skipTresure:
void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) { void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) {
if (m_Tamer == LWOOBJID_EMPTY) return; if (m_Tamer == LWOOBJID_EMPTY) return;
auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); auto* tamer = Game::entityManager->GetEntity(m_Tamer);
if (tamer == nullptr) { if (tamer == nullptr) {
m_Tamer = LWOOBJID_EMPTY; m_Tamer = LWOOBJID_EMPTY;
@ -497,7 +498,7 @@ void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) {
destroyableComponent->SetImagination(imagination); destroyableComponent->SetImagination(imagination);
EntityManager::Instance()->SerializeEntity(tamer); Game::entityManager->SerializeEntity(tamer);
if (clientFailed) { if (clientFailed) {
if (imagination < cached->second.imaginationCost) { if (imagination < cached->second.imaginationCost) {
@ -515,7 +516,7 @@ void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) {
void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) { void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) {
if (m_Tamer == LWOOBJID_EMPTY) return; if (m_Tamer == LWOOBJID_EMPTY) return;
auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); auto* tamer = Game::entityManager->GetEntity(m_Tamer);
if (tamer == nullptr) { if (tamer == nullptr) {
m_Tamer = LWOOBJID_EMPTY; m_Tamer = LWOOBJID_EMPTY;
@ -530,7 +531,7 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) {
} }
GameMessages::SendPlayFXEffect(tamer, -1, u"petceleb", "", LWOOBJID_EMPTY, 1, 1, true); GameMessages::SendPlayFXEffect(tamer, -1, u"petceleb", "", LWOOBJID_EMPTY, 1, 1, true);
GameMessages::SendPlayAnimation(tamer, u"rebuild-celebrate"); RenderComponent::PlayAnimation(tamer, u"rebuild-celebrate");
EntityInfo info{}; EntityInfo info{};
info.lot = cached->second.puzzleModelLot; info.lot = cached->second.puzzleModelLot;
@ -538,11 +539,11 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) {
info.rot = NiQuaternion::IDENTITY; info.rot = NiQuaternion::IDENTITY;
info.spawnerID = tamer->GetObjectID(); info.spawnerID = tamer->GetObjectID();
auto* modelEntity = EntityManager::Instance()->CreateEntity(info); auto* modelEntity = Game::entityManager->CreateEntity(info);
m_ModelId = modelEntity->GetObjectID(); m_ModelId = modelEntity->GetObjectID();
EntityManager::Instance()->ConstructEntity(modelEntity); Game::entityManager->ConstructEntity(modelEntity);
GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress()); GameMessages::SendNotifyTamingModelLoadedOnServer(m_Tamer, tamer->GetSystemAddress());
@ -638,7 +639,7 @@ void PetComponent::RequestSetPetName(std::u16string name) {
return; return;
} }
auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); auto* tamer = Game::entityManager->GetEntity(m_Tamer);
if (tamer == nullptr) { if (tamer == nullptr) {
m_Tamer = LWOOBJID_EMPTY; m_Tamer = LWOOBJID_EMPTY;
@ -660,7 +661,7 @@ void PetComponent::RequestSetPetName(std::u16string name) {
//Save our pet's new name to the db: //Save our pet's new name to the db:
SetPetNameForModeration(GeneralUtils::UTF16ToWTF8(name)); SetPetNameForModeration(GeneralUtils::UTF16ToWTF8(name));
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
std::u16string u16name = GeneralUtils::UTF8ToUTF16(m_Name); std::u16string u16name = GeneralUtils::UTF8ToUTF16(m_Name);
std::u16string u16ownerName = GeneralUtils::UTF8ToUTF16(m_OwnerName); std::u16string u16ownerName = GeneralUtils::UTF8ToUTF16(m_OwnerName);
@ -683,7 +684,7 @@ void PetComponent::RequestSetPetName(std::u16string name) {
GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID()); GameMessages::SendTerminateInteraction(m_Tamer, eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID());
auto* modelEntity = EntityManager::Instance()->GetEntity(m_ModelId); auto* modelEntity = Game::entityManager->GetEntity(m_ModelId);
if (modelEntity != nullptr) { if (modelEntity != nullptr) {
modelEntity->Smash(m_Tamer); modelEntity->Smash(m_Tamer);
@ -702,7 +703,7 @@ void PetComponent::RequestSetPetName(std::u16string name) {
void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) { void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) {
if (m_Tamer == LWOOBJID_EMPTY) return; if (m_Tamer == LWOOBJID_EMPTY) return;
auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); auto* tamer = Game::entityManager->GetEntity(m_Tamer);
if (tamer == nullptr) { if (tamer == nullptr) {
m_Tamer = LWOOBJID_EMPTY; m_Tamer = LWOOBJID_EMPTY;
@ -732,7 +733,7 @@ void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) {
m_Tamer = LWOOBJID_EMPTY; m_Tamer = LWOOBJID_EMPTY;
m_Timer = 0; m_Timer = 0;
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
// Notify the end of a pet taming minigame // Notify the end of a pet taming minigame
for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) {
@ -753,7 +754,7 @@ void PetComponent::StartTimer() {
void PetComponent::ClientFailTamingMinigame() { void PetComponent::ClientFailTamingMinigame() {
if (m_Tamer == LWOOBJID_EMPTY) return; if (m_Tamer == LWOOBJID_EMPTY) return;
auto* tamer = EntityManager::Instance()->GetEntity(m_Tamer); auto* tamer = Game::entityManager->GetEntity(m_Tamer);
if (tamer == nullptr) { if (tamer == nullptr) {
m_Tamer = LWOOBJID_EMPTY; m_Tamer = LWOOBJID_EMPTY;
@ -783,7 +784,7 @@ void PetComponent::ClientFailTamingMinigame() {
m_Tamer = LWOOBJID_EMPTY; m_Tamer = LWOOBJID_EMPTY;
m_Timer = 0; m_Timer = 0;
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
// Notify the end of a pet taming minigame // Notify the end of a pet taming minigame
for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(m_Parent)) {
@ -886,7 +887,7 @@ void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) {
m_Timer = 3; m_Timer = 3;
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
owner->GetCharacter()->SetPlayerFlag(ePlayerFlag::FIRST_MANUAL_PET_HIBERNATE, true); owner->GetCharacter()->SetPlayerFlag(ePlayerFlag::FIRST_MANUAL_PET_HIBERNATE, true);
@ -1003,7 +1004,7 @@ LWOOBJID PetComponent::GetOwnerId() const {
} }
Entity* PetComponent::GetOwner() const { Entity* PetComponent::GetOwner() const {
return EntityManager::Instance()->GetEntity(m_Owner); return Game::entityManager->GetEntity(m_Owner);
} }
LWOOBJID PetComponent::GetDatabaseId() const { LWOOBJID PetComponent::GetDatabaseId() const {
@ -1045,7 +1046,7 @@ PetComponent* PetComponent::GetTamingPet(LWOOBJID tamer) {
return nullptr; return nullptr;
} }
auto* entity = EntityManager::Instance()->GetEntity(pair->second); auto* entity = Game::entityManager->GetEntity(pair->second);
if (entity == nullptr) { if (entity == nullptr) {
currentActivities.erase(tamer); currentActivities.erase(tamer);
@ -1063,7 +1064,7 @@ PetComponent* PetComponent::GetActivePet(LWOOBJID owner) {
return nullptr; return nullptr;
} }
auto* entity = EntityManager::Instance()->GetEntity(pair->second); auto* entity = Game::entityManager->GetEntity(pair->second);
if (entity == nullptr) { if (entity == nullptr) {
activePets.erase(owner); activePets.erase(owner);

View File

@ -362,7 +362,7 @@ void PhantomPhysicsComponent::Update(float deltaTime) {
//If we are a respawn volume, inform the client: //If we are a respawn volume, inform the client:
if (m_IsRespawnVolume) { if (m_IsRespawnVolume) {
auto entity = EntityManager::Instance()->GetEntity(en->GetObjectID()); auto entity = Game::entityManager->GetEntity(en->GetObjectID());
if (entity) { if (entity) {
GameMessages::SendPlayerReachedRespawnCheckpoint(entity, m_RespawnPos, m_RespawnRot); GameMessages::SendPlayerReachedRespawnCheckpoint(entity, m_RespawnPos, m_RespawnRot);
@ -403,8 +403,8 @@ void PhantomPhysicsComponent::SpawnVertices() {
info.spawnerID = m_Parent->GetObjectID(); info.spawnerID = m_Parent->GetObjectID();
info.spawnerNodeID = 0; info.spawnerNodeID = 0;
Entity* newEntity = EntityManager::Instance()->CreateEntity(info, nullptr); Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr);
EntityManager::Instance()->ConstructEntity(newEntity); Game::entityManager->ConstructEntity(newEntity);
} }
} }

View File

@ -13,7 +13,7 @@ PossessorComponent::PossessorComponent(Entity* parent) : Component(parent) {
PossessorComponent::~PossessorComponent() { PossessorComponent::~PossessorComponent() {
if (m_Possessable != LWOOBJID_EMPTY) { if (m_Possessable != LWOOBJID_EMPTY) {
auto* mount = EntityManager::Instance()->GetEntity(m_Possessable); auto* mount = Game::entityManager->GetEntity(m_Possessable);
if (mount) { if (mount) {
auto* possessable = mount->GetComponent<PossessableComponent>(); auto* possessable = mount->GetComponent<PossessableComponent>();
if (possessable) { if (possessable) {
@ -58,8 +58,8 @@ void PossessorComponent::Mount(Entity* mount) {
GameMessages::SendVehicleUnlockInput(mount->GetObjectID(), false, m_Parent->GetSystemAddress()); GameMessages::SendVehicleUnlockInput(mount->GetObjectID(), false, m_Parent->GetSystemAddress());
GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStateChangeType::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true); GameMessages::SendSetStunned(m_Parent->GetObjectID(), eStateChangeType::PUSH, m_Parent->GetSystemAddress(), LWOOBJID_EMPTY, true, false, true, false, false, false, false, true, true, true, true, true, true, true, true, true);
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
EntityManager::Instance()->SerializeEntity(mount); Game::entityManager->SerializeEntity(mount);
} }
void PossessorComponent::Dismount(Entity* mount, bool forceDismount) { void PossessorComponent::Dismount(Entity* mount, bool forceDismount) {
@ -73,8 +73,8 @@ void PossessorComponent::Dismount(Entity* mount, bool forceDismount) {
possessableComponent->SetPossessor(LWOOBJID_EMPTY); possessableComponent->SetPossessor(LWOOBJID_EMPTY);
if (forceDismount) possessableComponent->ForceDepossess(); if (forceDismount) possessableComponent->ForceDepossess();
} }
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
EntityManager::Instance()->SerializeEntity(mount); Game::entityManager->SerializeEntity(mount);
auto characterComponent = m_Parent->GetComponent<CharacterComponent>(); auto characterComponent = m_Parent->GetComponent<CharacterComponent>();
if (characterComponent) characterComponent->SetIsRacing(false); if (characterComponent) characterComponent->SetIsRacing(false);

View File

@ -11,7 +11,7 @@
#include "CharacterComponent.h" #include "CharacterComponent.h"
#include "UserManager.h" #include "UserManager.h"
#include "dLogger.h" #include "dLogger.h"
#include "AMFFormat.h" #include "Amf3.h"
#include "eObjectBits.h" #include "eObjectBits.h"
#include "eGameMasterLevel.h" #include "eGameMasterLevel.h"
@ -36,12 +36,9 @@ void PropertyEntranceComponent::OnUse(Entity* entity) {
AMFArrayValue args; AMFArrayValue args;
auto* state = new AMFStringValue(); args.Insert("state", "property_menu");
state->SetStringValue("property_menu");
args.InsertValue("state", state); GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", args);
GameMessages::SendUIMessageServerToSingleClient(entity, entity->GetSystemAddress(), "pushGameState", &args);
} }
void PropertyEntranceComponent::OnEnterProperty(Entity* entity, uint32_t index, bool returnToZone, const SystemAddress& sysAddr) { void PropertyEntranceComponent::OnEnterProperty(Entity* entity, uint32_t index, bool returnToZone, const SystemAddress& sysAddr) {

View File

@ -38,7 +38,7 @@ PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Compo
instance = this; instance = this;
const auto& worldId = dZoneManager::Instance()->GetZone()->GetZoneID(); const auto& worldId = Game::zoneManager->GetZone()->GetZoneID();
const auto zoneId = worldId.GetMapID(); const auto zoneId = worldId.GetMapID();
const auto cloneId = worldId.GetCloneID(); const auto cloneId = worldId.GetCloneID();
@ -90,7 +90,7 @@ LWOOBJID PropertyManagementComponent::GetOwnerId() const {
} }
Entity* PropertyManagementComponent::GetOwner() const { Entity* PropertyManagementComponent::GetOwner() const {
return EntityManager::Instance()->GetEntity(owner); return Game::entityManager->GetEntity(owner);
} }
void PropertyManagementComponent::SetOwner(Entity* value) { void PropertyManagementComponent::SetOwner(Entity* value) {
@ -98,7 +98,7 @@ void PropertyManagementComponent::SetOwner(Entity* value) {
} }
std::vector<NiPoint3> PropertyManagementComponent::GetPaths() const { std::vector<NiPoint3> PropertyManagementComponent::GetPaths() const {
const auto zoneId = dZoneManager::Instance()->GetZone()->GetWorldID(); const auto zoneId = Game::zoneManager->GetZone()->GetWorldID();
auto query = CDClientDatabase::CreatePreppedStmt( auto query = CDClientDatabase::CreatePreppedStmt(
"SELECT path FROM PropertyTemplate WHERE mapID = ?;"); "SELECT path FROM PropertyTemplate WHERE mapID = ?;");
@ -185,14 +185,14 @@ bool PropertyManagementComponent::Claim(const LWOOBJID playerId) {
return false; return false;
} }
auto* entity = EntityManager::Instance()->GetEntity(playerId); auto* entity = Game::entityManager->GetEntity(playerId);
auto* user = entity->GetParentUser(); auto* user = entity->GetParentUser();
auto character = entity->GetCharacter(); auto character = entity->GetCharacter();
if (!character) return false; if (!character) return false;
auto* zone = dZoneManager::Instance()->GetZone(); auto* zone = Game::zoneManager->GetZone();
const auto& worldId = zone->GetZoneID(); const auto& worldId = zone->GetZoneID();
const auto propertyZoneId = worldId.GetMapID(); const auto propertyZoneId = worldId.GetMapID();
@ -240,7 +240,7 @@ bool PropertyManagementComponent::Claim(const LWOOBJID playerId) {
return false; return false;
} }
auto* zoneControlObject = dZoneManager::Instance()->GetZoneControlObject(); auto* zoneControlObject = Game::zoneManager->GetZoneControlObject();
for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControlObject)) { for (CppScripts::Script* script : CppScripts::GetEntityScripts(zoneControlObject)) {
script->OnZonePropertyRented(zoneControlObject, entity); script->OnZonePropertyRented(zoneControlObject, entity);
} }
@ -256,7 +256,7 @@ void PropertyManagementComponent::OnStartBuilding() {
LWOMAPID zoneId = 1100; LWOMAPID zoneId = 1100;
const auto entrance = EntityManager::Instance()->GetEntitiesByComponent(eReplicaComponentType::PROPERTY_ENTRANCE); const auto entrance = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::PROPERTY_ENTRANCE);
originalPrivacyOption = privacyOption; originalPrivacyOption = privacyOption;
@ -339,9 +339,9 @@ void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const N
info.settings.push_back(setting->Copy()); info.settings.push_back(setting->Copy());
} }
Entity* newEntity = EntityManager::Instance()->CreateEntity(info); Entity* newEntity = Game::entityManager->CreateEntity(info);
if (newEntity != nullptr) { if (newEntity != nullptr) {
EntityManager::Instance()->ConstructEntity(newEntity); Game::entityManager->ConstructEntity(newEntity);
// Make sure the propMgmt doesn't delete our model after the server dies // Make sure the propMgmt doesn't delete our model after the server dies
// Trying to do this after the entity is constructed. Shouldn't really change anything but // Trying to do this after the entity is constructed. Shouldn't really change anything but
@ -371,14 +371,14 @@ void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const N
info.respawnTime = 10; info.respawnTime = 10;
info.emulated = true; info.emulated = true;
info.emulator = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(); info.emulator = Game::entityManager->GetZoneControlEntity()->GetObjectID();
info.spawnerID = persistentId; info.spawnerID = persistentId;
GeneralUtils::SetBit(info.spawnerID, eObjectBits::CLIENT); GeneralUtils::SetBit(info.spawnerID, eObjectBits::CLIENT);
const auto spawnerId = dZoneManager::Instance()->MakeSpawner(info); const auto spawnerId = Game::zoneManager->MakeSpawner(info);
auto* spawner = dZoneManager::Instance()->GetSpawner(spawnerId); auto* spawner = Game::zoneManager->GetSpawner(spawnerId);
auto ldfModelBehavior = new LDFData<LWOOBJID>(u"modelBehaviors", 0); auto ldfModelBehavior = new LDFData<LWOOBJID>(u"modelBehaviors", 0);
auto userModelID = new LDFData<LWOOBJID>(u"userModelID", info.spawnerID); auto userModelID = new LDFData<LWOOBJID>(u"userModelID", info.spawnerID);
@ -401,7 +401,7 @@ void PropertyManagementComponent::UpdateModelPosition(const LWOOBJID id, const N
GameMessages::SendGetModelsOnProperty(entity->GetObjectID(), GetModels(), UNASSIGNED_SYSTEM_ADDRESS); GameMessages::SendGetModelsOnProperty(entity->GetObjectID(), GetModels(), UNASSIGNED_SYSTEM_ADDRESS);
EntityManager::Instance()->GetZoneControlEntity()->OnZonePropertyModelPlaced(entity); Game::entityManager->GetZoneControlEntity()->OnZonePropertyModelPlaced(entity);
}); });
// Progress place model missions // Progress place model missions
auto missionComponent = entity->GetComponent<MissionComponent>(); auto missionComponent = entity->GetComponent<MissionComponent>();
@ -433,7 +433,7 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet
const auto spawnerId = index->second; const auto spawnerId = index->second;
auto* spawner = dZoneManager::Instance()->GetSpawner(spawnerId); auto* spawner = Game::zoneManager->GetSpawner(spawnerId);
models.erase(id); models.erase(id);
@ -441,7 +441,7 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet
Game::logger->Log("PropertyManagementComponent", "Failed to find spawner"); Game::logger->Log("PropertyManagementComponent", "Failed to find spawner");
} }
auto* model = EntityManager::Instance()->GetEntity(id); auto* model = Game::entityManager->GetEntity(id);
if (model == nullptr) { if (model == nullptr) {
Game::logger->Log("PropertyManagementComponent", "Failed to find model entity"); Game::logger->Log("PropertyManagementComponent", "Failed to find model entity");
@ -449,7 +449,7 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet
return; return;
} }
EntityManager::Instance()->DestructEntity(model); Game::entityManager->DestructEntity(model);
Game::logger->Log("PropertyManagementComponent", "Deleting model LOT %i", model->GetLOT()); Game::logger->Log("PropertyManagementComponent", "Deleting model LOT %i", model->GetLOT());
@ -496,7 +496,7 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet
GameMessages::SendPlaceModelResponse(entity->GetObjectID(), entity->GetSystemAddress(), NiPoint3::ZERO, LWOOBJID_EMPTY, 16, NiQuaternion::IDENTITY); GameMessages::SendPlaceModelResponse(entity->GetObjectID(), entity->GetSystemAddress(), NiPoint3::ZERO, LWOOBJID_EMPTY, 16, NiQuaternion::IDENTITY);
if (spawner != nullptr) { if (spawner != nullptr) {
dZoneManager::Instance()->RemoveSpawner(spawner->m_Info.spawnerID); Game::zoneManager->RemoveSpawner(spawner->m_Info.spawnerID);
} else { } else {
model->Smash(LWOOBJID_EMPTY, eKillType::SILENT); model->Smash(LWOOBJID_EMPTY, eKillType::SILENT);
} }
@ -520,13 +520,13 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet
item->Equip(); item->Equip();
GameMessages::SendUGCEquipPostDeleteBasedOnEditMode(entity->GetObjectID(), entity->GetSystemAddress(), item->GetId(), item->GetCount()); GameMessages::SendUGCEquipPostDeleteBasedOnEditMode(entity->GetObjectID(), entity->GetSystemAddress(), item->GetId(), item->GetCount());
EntityManager::Instance()->GetZoneControlEntity()->OnZonePropertyModelPickedUp(entity); Game::entityManager->GetZoneControlEntity()->OnZonePropertyModelPickedUp(entity);
break; break;
} }
case 1: // Return to inv case 1: // Return to inv
{ {
EntityManager::Instance()->GetZoneControlEntity()->OnZonePropertyModelRemoved(entity); Game::entityManager->GetZoneControlEntity()->OnZonePropertyModelRemoved(entity);
break; break;
} }
@ -549,7 +549,7 @@ void PropertyManagementComponent::DeleteModel(const LWOOBJID id, const int delet
GameMessages::SendPlaceModelResponse(entity->GetObjectID(), entity->GetSystemAddress(), NiPoint3::ZERO, LWOOBJID_EMPTY, 16, NiQuaternion::IDENTITY); GameMessages::SendPlaceModelResponse(entity->GetObjectID(), entity->GetSystemAddress(), NiPoint3::ZERO, LWOOBJID_EMPTY, 16, NiQuaternion::IDENTITY);
if (spawner != nullptr) { if (spawner != nullptr) {
dZoneManager::Instance()->RemoveSpawner(spawner->m_Info.spawnerID); Game::zoneManager->RemoveSpawner(spawner->m_Info.spawnerID);
} else { } else {
model->Smash(LWOOBJID_EMPTY, eKillType::SILENT); model->Smash(LWOOBJID_EMPTY, eKillType::SILENT);
} }
@ -613,7 +613,7 @@ void PropertyManagementComponent::Load() {
info.respawnTime = 10; info.respawnTime = 10;
//info.emulated = true; //info.emulated = true;
//info.emulator = EntityManager::Instance()->GetZoneControlEntity()->GetObjectID(); //info.emulator = Game::entityManager->GetZoneControlEntity()->GetObjectID();
info.spawnerID = id; info.spawnerID = id;
@ -652,9 +652,9 @@ void PropertyManagementComponent::Load() {
node->config = settings; node->config = settings;
const auto spawnerId = dZoneManager::Instance()->MakeSpawner(info); const auto spawnerId = Game::zoneManager->MakeSpawner(info);
auto* spawner = dZoneManager::Instance()->GetSpawner(spawnerId); auto* spawner = Game::zoneManager->GetSpawner(spawnerId);
auto* model = spawner->Spawn(); auto* model = spawner->Spawn();
@ -698,7 +698,7 @@ void PropertyManagementComponent::Save() {
modelIds.push_back(id); modelIds.push_back(id);
auto* entity = EntityManager::Instance()->GetEntity(pair.first); auto* entity = Game::entityManager->GetEntity(pair.first);
if (entity == nullptr) { if (entity == nullptr) {
continue; continue;
@ -786,7 +786,7 @@ void PropertyManagementComponent::OnQueryPropertyData(Entity* originator, const
author = m_Parent->GetObjectID(); author = m_Parent->GetObjectID();
} }
const auto& worldId = dZoneManager::Instance()->GetZone()->GetZoneID(); const auto& worldId = Game::zoneManager->GetZone()->GetZoneID();
const auto zoneId = worldId.GetMapID(); const auto zoneId = worldId.GetMapID();
Game::logger->Log("Properties", "Getting property info for %d", zoneId); Game::logger->Log("Properties", "Getting property info for %d", zoneId);

View File

@ -43,7 +43,7 @@ void PropertyVendorComponent::OnBuyFromVendor(Entity* originator, const bool con
GameMessages::SendPropertyRentalResponse(m_Parent->GetObjectID(), 0, 0, 0, 0, originator->GetSystemAddress()); GameMessages::SendPropertyRentalResponse(m_Parent->GetObjectID(), 0, 0, 0, 0, originator->GetSystemAddress());
auto* controller = dZoneManager::Instance()->GetZoneControlObject(); auto* controller = Game::zoneManager->GetZoneControlObject();
controller->OnFireEventServerSide(m_Parent, "propertyRented"); controller->OnFireEventServerSide(m_Parent, "propertyRented");

View File

@ -23,6 +23,9 @@
#include "dConfig.h" #include "dConfig.h"
#include "Loot.h" #include "Loot.h"
#include "eMissionTaskType.h" #include "eMissionTaskType.h"
#include "LeaderboardManager.h"
#include "dZoneManager.h"
#include "CDActivitiesTable.h"
#ifndef M_PI #ifndef M_PI
#define M_PI 3.14159265358979323846264338327950288 #define M_PI 3.14159265358979323846264338327950288
@ -45,36 +48,14 @@ RacingControlComponent::RacingControlComponent(Entity* parent)
m_EmptyTimer = 0; m_EmptyTimer = 0;
m_SoloRacing = Game::config->GetValue("solo_racing") == "1"; m_SoloRacing = Game::config->GetValue("solo_racing") == "1";
// Select the main world ID as fallback when a player fails to load. m_MainWorld = 1200;
const auto worldID = Game::server->GetZoneID(); const auto worldID = Game::server->GetZoneID();
if (Game::zoneManager->CheckIfAccessibleZone((worldID/10)*10)) m_MainWorld = (worldID/10)*10;
switch (worldID) {
case 1203:
m_ActivityID = 42; m_ActivityID = 42;
m_MainWorld = 1200; CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
break; std::vector<CDActivities> activities = activitiesTable->Query([=](CDActivities entry) {return (entry.instanceMapID == worldID); });
for (CDActivities activity : activities) m_ActivityID = activity.ActivityID;
case 1261:
m_ActivityID = 60;
m_MainWorld = 1260;
break;
case 1303:
m_ActivityID = 39;
m_MainWorld = 1300;
break;
case 1403:
m_ActivityID = 54;
m_MainWorld = 1400;
break;
default:
m_ActivityID = 42;
m_MainWorld = 1200;
break;
}
} }
RacingControlComponent::~RacingControlComponent() {} RacingControlComponent::~RacingControlComponent() {}
@ -125,10 +106,10 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
// Calculate the vehicle's starting position. // Calculate the vehicle's starting position.
auto* path = dZoneManager::Instance()->GetZone()->GetPath( auto* path = Game::zoneManager->GetZone()->GetPath(
GeneralUtils::UTF16ToWTF8(m_PathName)); GeneralUtils::UTF16ToWTF8(m_PathName));
auto spawnPointEntities = EntityManager::Instance()->GetEntitiesByLOT(4843); auto spawnPointEntities = Game::entityManager->GetEntitiesByLOT(4843);
auto startPosition = NiPoint3::ZERO; auto startPosition = NiPoint3::ZERO;
auto startRotation = NiQuaternion::IDENTITY; auto startRotation = NiQuaternion::IDENTITY;
const std::string placementAsString = std::to_string(positionNumber); const std::string placementAsString = std::to_string(positionNumber);
@ -144,8 +125,7 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
// Make sure the player is at the correct position. // Make sure the player is at the correct position.
GameMessages::SendTeleport(player->GetObjectID(), startPosition, GameMessages::SendTeleport(player->GetObjectID(), startPosition,
startRotation, player->GetSystemAddress(), true, startRotation, player->GetSystemAddress(), true);
true);
// Spawn the vehicle entity. // Spawn the vehicle entity.
@ -156,7 +136,7 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
info.spawnerID = m_Parent->GetObjectID(); info.spawnerID = m_Parent->GetObjectID();
auto* carEntity = auto* carEntity =
EntityManager::Instance()->CreateEntity(info, nullptr, m_Parent); Game::entityManager->CreateEntity(info, nullptr, m_Parent);
// Make the vehicle a child of the racing controller. // Make the vehicle a child of the racing controller.
m_Parent->AddChild(carEntity); m_Parent->AddChild(carEntity);
@ -227,9 +207,9 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
// Construct and serialize everything when done. // Construct and serialize everything when done.
EntityManager::Instance()->ConstructEntity(carEntity); Game::entityManager->ConstructEntity(carEntity);
EntityManager::Instance()->SerializeEntity(player); Game::entityManager->SerializeEntity(player);
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
GameMessages::SendRacingSetPlayerResetInfo( GameMessages::SendRacingSetPlayerResetInfo(
m_Parent->GetObjectID(), 0, 0, player->GetObjectID(), startPosition, 1, m_Parent->GetObjectID(), 0, 0, player->GetObjectID(), startPosition, 1,
@ -240,7 +220,7 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
// Reset the player to the start position during downtime, in case something // Reset the player to the start position during downtime, in case something
// went wrong. // went wrong.
m_Parent->AddCallbackTimer(1, [this, playerID]() { m_Parent->AddCallbackTimer(1, [this, playerID]() {
auto* player = EntityManager::Instance()->GetEntity(playerID); auto* player = Game::entityManager->GetEntity(playerID);
if (player == nullptr) { if (player == nullptr) {
return; return;
@ -263,11 +243,9 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
// Make sure everything has the correct position. // Make sure everything has the correct position.
GameMessages::SendTeleport(player->GetObjectID(), startPosition, GameMessages::SendTeleport(player->GetObjectID(), startPosition,
startRotation, player->GetSystemAddress(), true, startRotation, player->GetSystemAddress(), true);
true);
GameMessages::SendTeleport(carEntity->GetObjectID(), startPosition, GameMessages::SendTeleport(carEntity->GetObjectID(), startPosition,
startRotation, player->GetSystemAddress(), true, startRotation, player->GetSystemAddress(), true);
true);
} }
void RacingControlComponent::OnRacingClientReady(Entity* player) { void RacingControlComponent::OnRacingClientReady(Entity* player) {
@ -291,7 +269,7 @@ void RacingControlComponent::OnRacingClientReady(Entity* player) {
racingPlayer.vehicleID, UNASSIGNED_SYSTEM_ADDRESS); racingPlayer.vehicleID, UNASSIGNED_SYSTEM_ADDRESS);
} }
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
} }
void RacingControlComponent::OnRequestDie(Entity* player) { void RacingControlComponent::OnRequestDie(Entity* player) {
@ -304,7 +282,7 @@ void RacingControlComponent::OnRequestDie(Entity* player) {
} }
auto* vehicle = auto* vehicle =
EntityManager::Instance()->GetEntity(racingPlayer.vehicleID); Game::entityManager->GetEntity(racingPlayer.vehicleID);
if (!vehicle) return; if (!vehicle) return;
@ -341,7 +319,7 @@ void RacingControlComponent::OnRequestDie(Entity* player) {
auto* destroyableComponent = vehicle->GetComponent<DestroyableComponent>(); auto* destroyableComponent = vehicle->GetComponent<DestroyableComponent>();
// Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live. // Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live.
if (destroyableComponent) destroyableComponent->SetImagination(respawnImagination); if (destroyableComponent) destroyableComponent->SetImagination(respawnImagination);
EntityManager::Instance()->SerializeEntity(vehicle); Game::entityManager->SerializeEntity(vehicle);
}); });
auto* characterComponent = player->GetComponent<CharacterComponent>(); auto* characterComponent = player->GetComponent<CharacterComponent>();
@ -370,7 +348,7 @@ void RacingControlComponent::OnRacingPlayerInfoResetFinished(Entity* player) {
} }
auto* vehicle = auto* vehicle =
EntityManager::Instance()->GetEntity(racingPlayer.vehicleID); Game::entityManager->GetEntity(racingPlayer.vehicleID);
if (vehicle == nullptr) { if (vehicle == nullptr) {
return; return;
@ -382,8 +360,7 @@ void RacingControlComponent::OnRacingPlayerInfoResetFinished(Entity* player) {
} }
} }
void RacingControlComponent::HandleMessageBoxResponse(Entity* player, void RacingControlComponent::HandleMessageBoxResponse(Entity* player, int32_t button, const std::string& id) {
const std::string& id) {
auto* data = GetPlayerData(player->GetObjectID()); auto* data = GetPlayerData(player->GetObjectID());
if (data == nullptr) { if (data == nullptr) {
@ -391,15 +368,17 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player,
} }
if (id == "rewardButton") { if (id == "rewardButton") {
if (data->collectedRewards) { if (data->collectedRewards) return;
return;
}
data->collectedRewards = true; data->collectedRewards = true;
// Calculate the score, different loot depending on player count // Calculate the score, different loot depending on player count
const auto score = m_LoadedPlayers * 10 + data->finished; auto playersRating = m_LoadedPlayers;
if(m_LoadedPlayers == 1 && m_SoloRacing) {
playersRating *= 2;
}
const auto score = playersRating * 10 + data->finished;
LootGenerator::Instance().GiveActivityLoot(player, m_Parent, m_ActivityID, score); LootGenerator::Instance().GiveActivityLoot(player, m_Parent, m_ActivityID, score);
// Giving rewards // Giving rewards
@ -418,15 +397,15 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player,
if (m_SoloRacing || m_LoadedPlayers > 2) { if (m_SoloRacing || m_LoadedPlayers > 2) {
missionComponent->Progress(eMissionTaskType::RACING, data->finished, (LWOOBJID)eRacingTaskParam::FINISH_WITH_PLACEMENT); // Finish in 1st place on a race missionComponent->Progress(eMissionTaskType::RACING, data->finished, (LWOOBJID)eRacingTaskParam::FINISH_WITH_PLACEMENT); // Finish in 1st place on a race
if (data->finished == 1) { if (data->finished == 1) {
missionComponent->Progress(eMissionTaskType::RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::FIRST_PLACE_MULTIPLE_TRACKS); // Finish in 1st place on multiple tracks. missionComponent->Progress(eMissionTaskType::RACING, Game::zoneManager->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::FIRST_PLACE_MULTIPLE_TRACKS); // Finish in 1st place on multiple tracks.
missionComponent->Progress(eMissionTaskType::RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::WIN_RACE_IN_WORLD); // Finished first place in specific world. missionComponent->Progress(eMissionTaskType::RACING, Game::zoneManager->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::WIN_RACE_IN_WORLD); // Finished first place in specific world.
} }
if (data->finished == m_LoadedPlayers) { if (data->finished == m_LoadedPlayers) {
missionComponent->Progress(eMissionTaskType::RACING, dZoneManager::Instance()->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::LAST_PLACE_FINISH); // Finished first place in specific world. missionComponent->Progress(eMissionTaskType::RACING, Game::zoneManager->GetZone()->GetWorldID(), (LWOOBJID)eRacingTaskParam::LAST_PLACE_FINISH); // Finished first place in specific world.
} }
} }
} else if (id == "ACT_RACE_EXIT_THE_RACE?" || id == "Exit") { } else if ((id == "ACT_RACE_EXIT_THE_RACE?" || id == "Exit") && button == m_ActivityExitConfirm) {
auto* vehicle = EntityManager::Instance()->GetEntity(data->vehicleID); auto* vehicle = Game::entityManager->GetEntity(data->vehicleID);
if (vehicle == nullptr) { if (vehicle == nullptr) {
return; return;
@ -527,7 +506,7 @@ void RacingControlComponent::Update(float deltaTime) {
// Check if any players has disconnected before loading in // Check if any players has disconnected before loading in
for (size_t i = 0; i < m_LobbyPlayers.size(); i++) { for (size_t i = 0; i < m_LobbyPlayers.size(); i++) {
auto* playerEntity = auto* playerEntity =
EntityManager::Instance()->GetEntity(m_LobbyPlayers[i]); Game::entityManager->GetEntity(m_LobbyPlayers[i]);
if (playerEntity == nullptr) { if (playerEntity == nullptr) {
--m_LoadedPlayers; --m_LoadedPlayers;
@ -549,7 +528,7 @@ void RacingControlComponent::Update(float deltaTime) {
if (m_EmptyTimer >= 30) { if (m_EmptyTimer >= 30) {
for (const auto player : m_LobbyPlayers) { for (const auto player : m_LobbyPlayers) {
auto* playerEntity = auto* playerEntity =
EntityManager::Instance()->GetEntity(player); Game::entityManager->GetEntity(player);
if (playerEntity == nullptr) { if (playerEntity == nullptr) {
continue; continue;
@ -574,7 +553,7 @@ void RacingControlComponent::Update(float deltaTime) {
"Loading player now!"); "Loading player now!");
auto* player = auto* player =
EntityManager::Instance()->GetEntity(m_LobbyPlayers[positionNumber]); Game::entityManager->GetEntity(m_LobbyPlayers[positionNumber]);
if (player == nullptr) { if (player == nullptr) {
return; return;
@ -598,7 +577,7 @@ void RacingControlComponent::Update(float deltaTime) {
if (!m_Started) { if (!m_Started) {
// Check if anyone has disconnected during this period // Check if anyone has disconnected during this period
for (size_t i = 0; i < m_RacingPlayers.size(); i++) { for (size_t i = 0; i < m_RacingPlayers.size(); i++) {
auto* playerEntity = EntityManager::Instance()->GetEntity( auto* playerEntity = Game::entityManager->GetEntity(
m_RacingPlayers[i].playerID); m_RacingPlayers[i].playerID);
if (playerEntity == nullptr) { if (playerEntity == nullptr) {
@ -614,7 +593,7 @@ void RacingControlComponent::Update(float deltaTime) {
if (m_LoadedPlayers < 2 && !(m_LoadedPlayers == 1 && m_SoloRacing)) { if (m_LoadedPlayers < 2 && !(m_LoadedPlayers == 1 && m_SoloRacing)) {
for (const auto player : m_LobbyPlayers) { for (const auto player : m_LobbyPlayers) {
auto* playerEntity = auto* playerEntity =
EntityManager::Instance()->GetEntity(player); Game::entityManager->GetEntity(player);
if (playerEntity == nullptr) { if (playerEntity == nullptr) {
continue; continue;
@ -647,15 +626,15 @@ void RacingControlComponent::Update(float deltaTime) {
for (const auto& player : m_RacingPlayers) { for (const auto& player : m_RacingPlayers) {
auto* vehicle = auto* vehicle =
EntityManager::Instance()->GetEntity(player.vehicleID); Game::entityManager->GetEntity(player.vehicleID);
auto* playerEntity = auto* playerEntity =
EntityManager::Instance()->GetEntity(player.playerID); Game::entityManager->GetEntity(player.playerID);
if (vehicle != nullptr && playerEntity != nullptr) { if (vehicle != nullptr && playerEntity != nullptr) {
GameMessages::SendTeleport( GameMessages::SendTeleport(
player.playerID, player.respawnPosition, player.playerID, player.respawnPosition,
player.respawnRotation, player.respawnRotation,
playerEntity->GetSystemAddress(), true, true); playerEntity->GetSystemAddress(), true);
vehicle->SetPosition(player.respawnPosition); vehicle->SetPosition(player.respawnPosition);
vehicle->SetRotation(player.respawnRotation); vehicle->SetRotation(player.respawnRotation);
@ -667,18 +646,18 @@ void RacingControlComponent::Update(float deltaTime) {
destroyableComponent->SetImagination(0); destroyableComponent->SetImagination(0);
} }
EntityManager::Instance()->SerializeEntity(vehicle); Game::entityManager->SerializeEntity(vehicle);
EntityManager::Instance()->SerializeEntity( Game::entityManager->SerializeEntity(
playerEntity); playerEntity);
} }
} }
// Spawn imagination pickups // Spawn imagination pickups
auto* minSpawner = dZoneManager::Instance()->GetSpawnersByName( auto* minSpawner = Game::zoneManager->GetSpawnersByName(
"ImaginationSpawn_Min")[0]; "ImaginationSpawn_Min")[0];
auto* medSpawner = dZoneManager::Instance()->GetSpawnersByName( auto* medSpawner = Game::zoneManager->GetSpawnersByName(
"ImaginationSpawn_Med")[0]; "ImaginationSpawn_Med")[0];
auto* maxSpawner = dZoneManager::Instance()->GetSpawnersByName( auto* maxSpawner = Game::zoneManager->GetSpawnersByName(
"ImaginationSpawn_Max")[0]; "ImaginationSpawn_Max")[0];
minSpawner->Activate(); minSpawner->Activate();
@ -694,9 +673,9 @@ void RacingControlComponent::Update(float deltaTime) {
// Reset players to their start location, without smashing them // Reset players to their start location, without smashing them
for (auto& player : m_RacingPlayers) { for (auto& player : m_RacingPlayers) {
auto* vehicleEntity = auto* vehicleEntity =
EntityManager::Instance()->GetEntity(player.vehicleID); Game::entityManager->GetEntity(player.vehicleID);
auto* playerEntity = auto* playerEntity =
EntityManager::Instance()->GetEntity(player.playerID); Game::entityManager->GetEntity(player.playerID);
if (vehicleEntity == nullptr || playerEntity == nullptr) { if (vehicleEntity == nullptr || playerEntity == nullptr) {
continue; continue;
@ -713,9 +692,9 @@ void RacingControlComponent::Update(float deltaTime) {
// Activate the players movement // Activate the players movement
for (auto& player : m_RacingPlayers) { for (auto& player : m_RacingPlayers) {
auto* vehicleEntity = auto* vehicleEntity =
EntityManager::Instance()->GetEntity(player.vehicleID); Game::entityManager->GetEntity(player.vehicleID);
auto* playerEntity = auto* playerEntity =
EntityManager::Instance()->GetEntity(player.playerID); Game::entityManager->GetEntity(player.playerID);
if (vehicleEntity == nullptr || playerEntity == nullptr) { if (vehicleEntity == nullptr || playerEntity == nullptr) {
continue; continue;
@ -733,7 +712,7 @@ void RacingControlComponent::Update(float deltaTime) {
Game::logger->Log("RacingControlComponent", "Starting race"); Game::logger->Log("RacingControlComponent", "Starting race");
EntityManager::Instance()->SerializeEntity(m_Parent); Game::entityManager->SerializeEntity(m_Parent);
m_StartTime = std::time(nullptr); m_StartTime = std::time(nullptr);
} }
@ -747,13 +726,13 @@ void RacingControlComponent::Update(float deltaTime) {
} }
// Race routines // Race routines
auto* path = dZoneManager::Instance()->GetZone()->GetPath( auto* path = Game::zoneManager->GetZone()->GetPath(
GeneralUtils::UTF16ToWTF8(m_PathName)); GeneralUtils::UTF16ToWTF8(m_PathName));
for (auto& player : m_RacingPlayers) { for (auto& player : m_RacingPlayers) {
auto* vehicle = EntityManager::Instance()->GetEntity(player.vehicleID); auto* vehicle = Game::entityManager->GetEntity(player.vehicleID);
auto* playerEntity = auto* playerEntity =
EntityManager::Instance()->GetEntity(player.playerID); Game::entityManager->GetEntity(player.playerID);
if (vehicle == nullptr || playerEntity == nullptr) { if (vehicle == nullptr || playerEntity == nullptr) {
continue; continue;
@ -859,6 +838,7 @@ void RacingControlComponent::Update(float deltaTime) {
"Completed time %llu, %llu", "Completed time %llu, %llu",
raceTime, raceTime * 1000); raceTime, raceTime * 1000);
LeaderboardManager::SaveScore(playerEntity->GetObjectID(), m_ActivityID, static_cast<float>(player.raceTime), static_cast<float>(player.bestLapTime), static_cast<float>(player.finished == 1));
// Entire race time // Entire race time
missionComponent->Progress(eMissionTaskType::RACING, (raceTime) * 1000, (LWOOBJID)eRacingTaskParam::TOTAL_TRACK_TIME); missionComponent->Progress(eMissionTaskType::RACING, (raceTime) * 1000, (LWOOBJID)eRacingTaskParam::TOTAL_TRACK_TIME);

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