mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-12-29 08:49:49 -06:00
Compare commits
9 Commits
fix_gravit
...
cdcinstanc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
23676cf17b | ||
|
|
0642b4ac55 | ||
|
|
6f2d583ca2 | ||
|
|
4a189edf43 | ||
|
|
84708b860a | ||
|
|
eebf484c4e | ||
|
|
771eb65b92 | ||
|
|
ff173dffce | ||
|
|
dc526aeec1 |
@@ -14,4 +14,4 @@ EXTERNAL_IP=localhost
|
||||
MARIADB_USER=darkflame
|
||||
MARIADB_PASSWORD=SECRET_VALUE_CHANGE_ME
|
||||
MARIADB_ROOT_PASSWORD=SECRET_VALUE_CHANGE_ME
|
||||
MARIADB_DATABASE=darkflame
|
||||
MARIADB_DATABASE=darkflame
|
||||
@@ -1,8 +1,12 @@
|
||||
PROJECT_VERSION_MAJOR=1
|
||||
PROJECT_VERSION_MINOR=1
|
||||
PROJECT_VERSION_PATCH=1
|
||||
PROJECT_VERSION_PATCH=0
|
||||
# LICENSE
|
||||
LICENSE=AGPL-3.0
|
||||
# The network version.
|
||||
# 171023 - Darkflame Universe client
|
||||
# 171022 - Unmodded client
|
||||
NET_VERSION=171022
|
||||
# Debugging
|
||||
# Set __dynamic to 1 to enable the -rdynamic flag for the linker, yielding some symbols in crashlogs.
|
||||
__dynamic=1
|
||||
@@ -18,5 +22,3 @@ __maria_db_connector_compile_jobs__=1
|
||||
__enable_testing__=1
|
||||
# The path to OpenSSL. Change this if your OpenSSL install path is different than the default.
|
||||
OPENSSL_ROOT_DIR=/usr/local/opt/openssl@3/
|
||||
# Uncomment the below line to cache the entire CDClient into memory
|
||||
# CDCLIENT_CACHE_ALL=1
|
||||
|
||||
@@ -179,7 +179,7 @@ If you would like to build the server faster, append `-j<number>` where number i
|
||||
### Notes
|
||||
Depending on your operating system, you may need to adjust some pre-processor defines in [CMakeVariables.txt](./CMakeVariables.txt) before building:
|
||||
* If you are on MacOS, ensure OPENSSL_ROOT_DIR is pointing to the openssl root directory.
|
||||
* If you are using a Darkflame Universe client, ensure `client_net_version` in `build/sharedconfig.ini` is changed to 171023.
|
||||
* If you are using a Darkflame Universe client, ensure NET_VERSION is changed to 171023.
|
||||
|
||||
## Configuring your server
|
||||
This server has a few steps that need to be taken to configure the server for your use case.
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "Database.h"
|
||||
#include <vector>
|
||||
#include "PacketUtils.h"
|
||||
#include "BitStreamUtils.h"
|
||||
#include "Game.h"
|
||||
#include "dServer.h"
|
||||
#include "GeneralUtils.h"
|
||||
@@ -76,11 +75,11 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
|
||||
//Now, we need to send the friendlist to the server they came from:
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GET_FRIENDS_LIST_RESPONSE);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GET_FRIENDS_LIST_RESPONSE);
|
||||
bitStream.Write<uint8_t>(0);
|
||||
bitStream.Write<uint16_t>(1); //Length of packet -- just writing one as it doesn't matter, client skips it.
|
||||
bitStream.Write((uint16_t)friends.size());
|
||||
@@ -413,21 +412,21 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
||||
const auto otherName = std::string(otherMember->playerName.c_str());
|
||||
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(otherMember->playerID);
|
||||
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
|
||||
bitStream.Write(otherMember->playerID);
|
||||
bitStream.Write<uint8_t>(8);
|
||||
bitStream.Write<unsigned int>(69);
|
||||
bitStream.Write(LUWString(senderName));
|
||||
PacketUtils::WritePacketWString(senderName, 33, &bitStream);
|
||||
bitStream.Write(sender->playerID);
|
||||
bitStream.Write<uint16_t>(0);
|
||||
bitStream.Write<uint8_t>(0); //not mythran nametag
|
||||
bitStream.Write(LUWString(otherName));
|
||||
PacketUtils::WritePacketWString(otherName, 33, &bitStream);
|
||||
bitStream.Write<uint8_t>(0); //not mythran for receiver
|
||||
bitStream.Write<uint8_t>(0); //teams?
|
||||
bitStream.Write(LUWString(message, 512));
|
||||
PacketUtils::WritePacketWString(message, 512, &bitStream);
|
||||
|
||||
SystemAddress sysAddr = otherMember->sysAddr;
|
||||
SEND_PACKET;
|
||||
@@ -435,7 +434,7 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
||||
}
|
||||
|
||||
void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
|
||||
LWOOBJID senderID = PacketUtils::ReadS64(0x08, packet);
|
||||
LWOOBJID senderID = PacketUtils::ReadPacketS64(0x08, packet);
|
||||
std::string receiverName = PacketUtils::ReadString(0x66, packet, true);
|
||||
std::string message = PacketUtils::ReadString(0xAA, packet, true, 512);
|
||||
|
||||
@@ -452,21 +451,21 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
|
||||
//To the sender:
|
||||
{
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(goonA->playerID);
|
||||
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
|
||||
bitStream.Write(goonA->playerID);
|
||||
bitStream.Write<uint8_t>(7);
|
||||
bitStream.Write<unsigned int>(69);
|
||||
bitStream.Write(LUWString(goonAName));
|
||||
PacketUtils::WritePacketWString(goonAName, 33, &bitStream);
|
||||
bitStream.Write(goonA->playerID);
|
||||
bitStream.Write<uint16_t>(0);
|
||||
bitStream.Write<uint8_t>(0); //not mythran nametag
|
||||
bitStream.Write(LUWString(goonBName));
|
||||
PacketUtils::WritePacketWString(goonBName, 33, &bitStream);
|
||||
bitStream.Write<uint8_t>(0); //not mythran for receiver
|
||||
bitStream.Write<uint8_t>(0); //success
|
||||
bitStream.Write(LUWString(message, 512));
|
||||
PacketUtils::WritePacketWString(message, 512, &bitStream);
|
||||
|
||||
SystemAddress sysAddr = goonA->sysAddr;
|
||||
SEND_PACKET;
|
||||
@@ -475,21 +474,21 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
|
||||
//To the receiver:
|
||||
{
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(goonB->playerID);
|
||||
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::PRIVATE_CHAT_MESSAGE);
|
||||
bitStream.Write(goonA->playerID);
|
||||
bitStream.Write<uint8_t>(7);
|
||||
bitStream.Write<unsigned int>(69);
|
||||
bitStream.Write(LUWString(goonAName));
|
||||
PacketUtils::WritePacketWString(goonAName, 33, &bitStream);
|
||||
bitStream.Write(goonA->playerID);
|
||||
bitStream.Write<uint16_t>(0);
|
||||
bitStream.Write<uint8_t>(0); //not mythran nametag
|
||||
bitStream.Write(LUWString(goonBName));
|
||||
PacketUtils::WritePacketWString(goonBName, 33, &bitStream);
|
||||
bitStream.Write<uint8_t>(0); //not mythran for receiver
|
||||
bitStream.Write<uint8_t>(3); //new whisper
|
||||
bitStream.Write(LUWString(message, 512));
|
||||
PacketUtils::WritePacketWString(message, 512, &bitStream);
|
||||
|
||||
SystemAddress sysAddr = goonB->sysAddr;
|
||||
SEND_PACKET;
|
||||
@@ -710,13 +709,13 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
|
||||
|
||||
void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::TEAM_INVITE);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::TEAM_INVITE);
|
||||
|
||||
bitStream.Write(LUWString(sender->playerName.c_str()));
|
||||
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
|
||||
bitStream.Write(sender->playerID);
|
||||
|
||||
SystemAddress sysAddr = receiver->sysAddr;
|
||||
@@ -725,7 +724,7 @@ void ChatPacketHandler::SendTeamInvite(PlayerData* receiver, PlayerData* sender)
|
||||
|
||||
void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeaderIsFreeTrial, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, uint8_t ucResponseCode, std::u16string wsLeaderName) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -752,7 +751,7 @@ void ChatPacketHandler::SendTeamInviteConfirm(PlayerData* receiver, bool bLeader
|
||||
|
||||
void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderID, LWOZONEID i64LeaderZoneID, uint8_t ucLootFlag, uint8_t ucNumOfOtherPlayers, std::u16string wsLeaderName) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -777,7 +776,7 @@ void ChatPacketHandler::SendTeamStatus(PlayerData* receiver, LWOOBJID i64LeaderI
|
||||
|
||||
void ChatPacketHandler::SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64PlayerID) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -794,7 +793,7 @@ void ChatPacketHandler::SendTeamSetLeader(PlayerData* receiver, LWOOBJID i64Play
|
||||
|
||||
void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTrial, bool bLocal, bool bNoLootOnDeath, LWOOBJID i64PlayerID, std::u16string wsPlayerName, LWOZONEID zoneID) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -823,7 +822,7 @@ void ChatPacketHandler::SendTeamAddPlayer(PlayerData* receiver, bool bIsFreeTria
|
||||
|
||||
void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband, bool bIsKicked, bool bIsLeaving, bool bLocal, LWOOBJID i64LeaderID, LWOOBJID i64PlayerID, std::u16string wsPlayerName) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -849,7 +848,7 @@ void ChatPacketHandler::SendTeamRemovePlayer(PlayerData* receiver, bool bDisband
|
||||
|
||||
void ChatPacketHandler::SendTeamSetOffWorldFlag(PlayerData* receiver, LWOOBJID i64PlayerID, LWOZONEID zoneID) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
@@ -883,16 +882,16 @@ void ChatPacketHandler::SendFriendUpdate(PlayerData* friendData, PlayerData* pla
|
||||
[bool] - is FTP*/
|
||||
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(friendData->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::UPDATE_FRIEND_NOTIFY);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::UPDATE_FRIEND_NOTIFY);
|
||||
bitStream.Write<uint8_t>(notifyType);
|
||||
|
||||
std::string playerName = playerData->playerName.c_str();
|
||||
|
||||
bitStream.Write(LUWString(playerName));
|
||||
PacketUtils::WritePacketWString(playerName, 33, &bitStream);
|
||||
|
||||
bitStream.Write(playerData->zoneID.GetMapID());
|
||||
bitStream.Write(playerData->zoneID.GetInstanceID());
|
||||
@@ -922,12 +921,12 @@ void ChatPacketHandler::SendFriendRequest(PlayerData* receiver, PlayerData* send
|
||||
}
|
||||
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_REQUEST);
|
||||
bitStream.Write(LUWString(sender->playerName.c_str()));
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_REQUEST);
|
||||
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
|
||||
bitStream.Write<uint8_t>(0); // This is a BFF flag however this is unused in live and does not have an implementation client side.
|
||||
|
||||
SystemAddress sysAddr = receiver->sysAddr;
|
||||
@@ -938,16 +937,16 @@ void ChatPacketHandler::SendFriendResponse(PlayerData* receiver, PlayerData* sen
|
||||
if (!receiver || !sender) return;
|
||||
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
// Portion that will get routed:
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_RESPONSE);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::ADD_FRIEND_RESPONSE);
|
||||
bitStream.Write(responseCode);
|
||||
// For all requests besides accepted, write a flag that says whether or not we are already best friends with the receiver.
|
||||
bitStream.Write<uint8_t>(responseCode != eAddFriendResponseType::ACCEPTED ? isBestFriendsAlready : sender->sysAddr != UNASSIGNED_SYSTEM_ADDRESS);
|
||||
// Then write the player name
|
||||
bitStream.Write(LUWString(sender->playerName.c_str()));
|
||||
PacketUtils::WritePacketWString(sender->playerName.c_str(), 33, &bitStream);
|
||||
// Then if this is an acceptance code, write the following extra info.
|
||||
if (responseCode == eAddFriendResponseType::ACCEPTED) {
|
||||
bitStream.Write(sender->playerID);
|
||||
@@ -963,13 +962,13 @@ void ChatPacketHandler::SendRemoveFriend(PlayerData* receiver, std::string& pers
|
||||
if (!receiver) return;
|
||||
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||
bitStream.Write(receiver->playerID);
|
||||
|
||||
//portion that will get routed:
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::REMOVE_FRIEND_RESPONSE);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::REMOVE_FRIEND_RESPONSE);
|
||||
bitStream.Write<uint8_t>(isSuccessful); //isOnline
|
||||
bitStream.Write(LUWString(personToRemove));
|
||||
PacketUtils::WritePacketWString(personToRemove, 33, &bitStream);
|
||||
|
||||
SystemAddress sysAddr = receiver->sysAddr;
|
||||
SEND_PACKET;
|
||||
|
||||
@@ -33,7 +33,6 @@ namespace Game {
|
||||
dChatFilter* chatFilter = nullptr;
|
||||
AssetManager* assetManager = nullptr;
|
||||
bool shouldShutdown = false;
|
||||
std::mt19937 randomEngine;
|
||||
}
|
||||
|
||||
|
||||
@@ -115,8 +114,6 @@ int main(int argc, char** argv) {
|
||||
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::shouldShutdown);
|
||||
|
||||
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf"))));
|
||||
|
||||
Game::randomEngine = std::mt19937(time(0));
|
||||
|
||||
//Run it until server gets a kill message from Master:
|
||||
auto t = std::chrono::high_resolution_clock::now();
|
||||
|
||||
@@ -6,11 +6,10 @@
|
||||
#include "dLogger.h"
|
||||
#include "ChatPacketHandler.h"
|
||||
#include "GeneralUtils.h"
|
||||
#include "BitStreamUtils.h"
|
||||
#include "PacketUtils.h"
|
||||
#include "Database.h"
|
||||
#include "eConnectionType.h"
|
||||
#include "eChatInternalMessageType.h"
|
||||
#include "ChatPackets.h"
|
||||
|
||||
PlayerContainer::PlayerContainer() {
|
||||
}
|
||||
@@ -147,7 +146,7 @@ void PlayerContainer::CreateTeamServer(Packet* packet) {
|
||||
|
||||
void PlayerContainer::BroadcastMuteUpdate(LWOOBJID player, time_t time) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::MUTE_UPDATE);
|
||||
|
||||
bitStream.Write(player);
|
||||
bitStream.Write(time);
|
||||
@@ -208,14 +207,6 @@ TeamData* PlayerContainer::GetTeam(LWOOBJID playerID) {
|
||||
}
|
||||
|
||||
void PlayerContainer::AddMember(TeamData* team, LWOOBJID playerID) {
|
||||
if (team->memberIDs.size() >= 4){
|
||||
Game::logger->Log("PlayerContainer", "Tried to add player to team that already had 4 players");
|
||||
auto* player = GetPlayerData(playerID);
|
||||
if (!player) return;
|
||||
ChatPackets::SendSystemMessage(player->sysAddr, u"The teams is full! You have not been added to a team!");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto index = std::find(team->memberIDs.begin(), team->memberIDs.end(), playerID);
|
||||
|
||||
if (index != team->memberIDs.end()) return;
|
||||
@@ -354,7 +345,7 @@ void PlayerContainer::TeamStatusUpdate(TeamData* team) {
|
||||
|
||||
void PlayerContainer::UpdateTeamsOnWorld(TeamData* team, bool deleteTeam) {
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::TEAM_UPDATE);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::TEAM_UPDATE);
|
||||
|
||||
bitStream.Write(team->teamID);
|
||||
bitStream.Write(deleteTeam);
|
||||
|
||||
@@ -12,7 +12,7 @@ set(DCOMMON_SOURCES
|
||||
"NiPoint3.cpp"
|
||||
"NiQuaternion.cpp"
|
||||
"SHA512.cpp"
|
||||
"Demangler.cpp"
|
||||
"Type.cpp"
|
||||
"ZCompression.cpp"
|
||||
"BrickByBrickFix.cpp"
|
||||
"BinaryPathFinder.cpp"
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#include "Demangler.h"
|
||||
#ifdef __GNUG__
|
||||
#include <cstdlib>
|
||||
#include <cxxabi.h>
|
||||
#include <memory>
|
||||
#include <typeinfo>
|
||||
|
||||
std::string Demangler::Demangle(const char* name) {
|
||||
// some arbitrary value to eliminate the compiler warning
|
||||
// -4 is not a valid return value for __cxa_demangle so we'll use that.
|
||||
int status = -4;
|
||||
|
||||
// __cxa_demangle requires that we free the returned char*
|
||||
std::unique_ptr<char, void (*)(void*)> res{
|
||||
abi::__cxa_demangle(name, NULL, NULL, &status),
|
||||
std::free
|
||||
};
|
||||
|
||||
return (status == 0) ? res.get() : "";
|
||||
}
|
||||
|
||||
#else // __GNUG__
|
||||
|
||||
// does nothing if not g++
|
||||
std::string Demangler::Demangle(const char* name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
#endif // __GNUG__
|
||||
@@ -1,9 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Demangler {
|
||||
// Given a char* containing a mangled name, return a std::string containing the demangled name.
|
||||
// If the function fails for any reason, it returns an empty string.
|
||||
std::string Demangle(const char* name);
|
||||
}
|
||||
@@ -107,7 +107,7 @@ static void ErrorCallback(void* data, const char* msg, int errnum) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "Demangler.h"
|
||||
#include "Type.h"
|
||||
|
||||
void GenerateDump() {
|
||||
std::string cmd = "sudo gcore " + std::to_string(getpid());
|
||||
@@ -122,43 +122,41 @@ void CatchUnhandled(int sig) {
|
||||
if (Diagnostics::GetProduceMemoryDump()) {
|
||||
GenerateDump();
|
||||
}
|
||||
constexpr uint8_t MaxStackTrace = 32;
|
||||
void* array[MaxStackTrace];
|
||||
|
||||
void* array[10];
|
||||
size_t size;
|
||||
|
||||
// get void*'s for all entries on the stack
|
||||
size = backtrace(array, MaxStackTrace);
|
||||
size = backtrace(array, 10);
|
||||
|
||||
# if defined(__GNUG__)
|
||||
#if defined(__GNUG__) and defined(__dynamic)
|
||||
|
||||
// Loop through the returned addresses, and get the symbols to be demangled
|
||||
char** strings = backtrace_symbols(array, size);
|
||||
|
||||
// Print the stack trace
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
// Take a string like './WorldServer(_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress+0x6187) [0x55869c44ecf7]'
|
||||
// and extract '_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress' from it to be demangled into a proper name
|
||||
// Take a string like './WorldServer(_ZN19SlashCommandHandler17HandleChatCommandERKSbIDsSt11char_traitsIDsESaIDsEEP6EntityRK13SystemAddress+0x6187) [0x55869c44ecf7]' and extract the function name
|
||||
std::string functionName = strings[i];
|
||||
std::string::size_type start = functionName.find('(');
|
||||
std::string::size_type end = functionName.find('+');
|
||||
if (start != std::string::npos && end != std::string::npos) {
|
||||
std::string demangled = functionName.substr(start + 1, end - start - 1);
|
||||
|
||||
demangled = Demangler::Demangle(demangled.c_str());
|
||||
demangled = demangle(functionName.c_str());
|
||||
|
||||
// If the demangled string is not empty, then we can replace the mangled string with the demangled one
|
||||
if (!demangled.empty()) {
|
||||
demangled.push_back('(');
|
||||
demangled += functionName.substr(end);
|
||||
functionName = demangled;
|
||||
if (demangled.empty()) {
|
||||
Game::logger->Log("Diagnostics", "[%02zu] %s", i, demangled.c_str());
|
||||
} else {
|
||||
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
|
||||
}
|
||||
} else {
|
||||
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
|
||||
}
|
||||
|
||||
Game::logger->Log("Diagnostics", "[%02zu] %s", i, functionName.c_str());
|
||||
}
|
||||
# else // defined(__GNUG__)
|
||||
#else
|
||||
backtrace_symbols_fd(array, size, STDOUT_FILENO);
|
||||
# endif // defined(__GNUG__)
|
||||
#endif
|
||||
|
||||
FILE* file = fopen(fileName.c_str(), "w+");
|
||||
if (file != NULL) {
|
||||
@@ -168,7 +166,7 @@ void CatchUnhandled(int sig) {
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
#else // __include_backtrace__
|
||||
#else
|
||||
|
||||
struct backtrace_state* state = backtrace_create_state(
|
||||
Diagnostics::GetProcessFileName().c_str(),
|
||||
@@ -179,7 +177,7 @@ void CatchUnhandled(int sig) {
|
||||
struct bt_ctx ctx = { state, 0 };
|
||||
Bt(state);
|
||||
|
||||
#endif // __include_backtrace__
|
||||
#endif
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -126,11 +126,6 @@ namespace GeneralUtils {
|
||||
template <typename T>
|
||||
T Parse(const char* value);
|
||||
|
||||
template <>
|
||||
inline bool Parse(const char* value) {
|
||||
return std::stoi(value);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline int32_t Parse(const char* value) {
|
||||
return std::stoi(value);
|
||||
|
||||
@@ -61,33 +61,35 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
|
||||
}
|
||||
|
||||
case LDF_TYPE_S32: {
|
||||
int32_t data;
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
try {
|
||||
int32_t data = static_cast<int32_t>(strtoul(ldfTypeAndValue.second.data(), &storage, 10));
|
||||
returnValue = new LDFData<int32_t>(key, data);
|
||||
} catch (std::exception) {
|
||||
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid int32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
returnValue = new LDFData<int32_t>(key, data);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case LDF_TYPE_FLOAT: {
|
||||
float data;
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
try {
|
||||
float data = strtof(ldfTypeAndValue.second.data(), &storage);
|
||||
returnValue = new LDFData<float>(key, data);
|
||||
} catch (std::exception) {
|
||||
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid float value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
returnValue = new LDFData<float>(key, data);
|
||||
break;
|
||||
}
|
||||
|
||||
case LDF_TYPE_DOUBLE: {
|
||||
double data;
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
try {
|
||||
double data = strtod(ldfTypeAndValue.second.data(), &storage);
|
||||
returnValue = new LDFData<double>(key, data);
|
||||
} catch (std::exception) {
|
||||
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid double value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
returnValue = new LDFData<double>(key, data);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -100,7 +102,9 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
|
||||
} else if (ldfTypeAndValue.second == "false") {
|
||||
data = 0;
|
||||
} else {
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
try {
|
||||
data = static_cast<uint32_t>(strtoul(ldfTypeAndValue.second.data(), &storage, 10));
|
||||
} catch (std::exception) {
|
||||
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid uint32 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
@@ -118,7 +122,9 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
|
||||
} else if (ldfTypeAndValue.second == "false") {
|
||||
data = false;
|
||||
} else {
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
try {
|
||||
data = static_cast<bool>(strtol(ldfTypeAndValue.second.data(), &storage, 10));
|
||||
} catch (std::exception) {
|
||||
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid bool value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
@@ -129,22 +135,24 @@ LDFBaseData* LDFBaseData::DataFromString(const std::string_view& format) {
|
||||
}
|
||||
|
||||
case LDF_TYPE_U64: {
|
||||
uint64_t data;
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
try {
|
||||
uint64_t data = static_cast<uint64_t>(strtoull(ldfTypeAndValue.second.data(), &storage, 10));
|
||||
returnValue = new LDFData<uint64_t>(key, data);
|
||||
} catch (std::exception) {
|
||||
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid uint64 value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
returnValue = new LDFData<uint64_t>(key, data);
|
||||
break;
|
||||
}
|
||||
|
||||
case LDF_TYPE_OBJID: {
|
||||
LWOOBJID data;
|
||||
if (!GeneralUtils::TryParse(ldfTypeAndValue.second.data(), data)) {
|
||||
try {
|
||||
LWOOBJID data = static_cast<LWOOBJID>(strtoll(ldfTypeAndValue.second.data(), &storage, 10));
|
||||
returnValue = new LDFData<LWOOBJID>(key, data);
|
||||
} catch (std::exception) {
|
||||
Game::logger->Log("LDFFormat", "Warning: Attempted to process invalid LWOOBJID value (%s) from string (%s)", ldfTypeAndValue.second.data(), format.data());
|
||||
return nullptr;
|
||||
}
|
||||
returnValue = new LDFData<LWOOBJID>(key, data);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -129,19 +129,10 @@ NiPoint3 NiPoint3::operator+(const NiPoint3& point) const {
|
||||
}
|
||||
|
||||
//! Operator for addition of vectors
|
||||
NiPoint3& NiPoint3::operator+=(const NiPoint3& point) {
|
||||
this->x += point.x;
|
||||
this->y += point.y;
|
||||
this->z += point.z;
|
||||
return *this;
|
||||
NiPoint3 NiPoint3::operator+=(const NiPoint3& point) const {
|
||||
return NiPoint3(this->x + point.x, this->y + point.y, this->z + point.z);
|
||||
}
|
||||
|
||||
NiPoint3& NiPoint3::operator*=(const float scalar) {
|
||||
this->x *= scalar;
|
||||
this->y *= scalar;
|
||||
this->z *= scalar;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Operator for subtraction of vectors
|
||||
NiPoint3 NiPoint3::operator-(const NiPoint3& point) const {
|
||||
|
||||
@@ -136,9 +136,7 @@ public:
|
||||
NiPoint3 operator+(const NiPoint3& point) const;
|
||||
|
||||
//! Operator for addition of vectors
|
||||
NiPoint3& operator+=(const NiPoint3& point);
|
||||
|
||||
NiPoint3& operator*=(const float scalar);
|
||||
NiPoint3 operator+=(const NiPoint3& point) const;
|
||||
|
||||
//! Operator for subtraction of vectors
|
||||
NiPoint3 operator-(const NiPoint3& point) const;
|
||||
|
||||
27
dCommon/Type.cpp
Normal file
27
dCommon/Type.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "Type.h"
|
||||
#ifdef __GNUG__
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <cxxabi.h>
|
||||
|
||||
std::string demangle(const char* name) {
|
||||
|
||||
int status = -4; // some arbitrary value to eliminate the compiler warning
|
||||
|
||||
// enable c++11 by passing the flag -std=c++11 to g++
|
||||
std::unique_ptr<char, void(*)(void*)> res{
|
||||
abi::__cxa_demangle(name, NULL, NULL, &status),
|
||||
std::free
|
||||
};
|
||||
|
||||
return (status == 0) ? res.get() : name;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// does nothing if not g++
|
||||
std::string demangle(const char* name) {
|
||||
return name;
|
||||
}
|
||||
|
||||
#endif
|
||||
12
dCommon/Type.h
Normal file
12
dCommon/Type.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
std::string demangle(const char* name);
|
||||
|
||||
template <class T>
|
||||
std::string type(const T& t) {
|
||||
|
||||
return demangle(typeid(t).name());
|
||||
}
|
||||
@@ -42,7 +42,7 @@ struct AssetMemoryBuffer : std::streambuf {
|
||||
}
|
||||
|
||||
void close() {
|
||||
free(m_Base);
|
||||
delete m_Base;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "BitStream.h"
|
||||
#include "eConnectionType.h"
|
||||
#include "eClientMessageType.h"
|
||||
#include "BitStreamUtils.h"
|
||||
|
||||
#pragma warning (disable:4251) //Disables SQL warnings
|
||||
|
||||
@@ -33,7 +32,7 @@ constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate);
|
||||
#define CBITSTREAM RakNet::BitStream bitStream;
|
||||
#define CINSTREAM RakNet::BitStream inStream(packet->data, packet->length, false);
|
||||
#define CINSTREAM_SKIP_HEADER CINSTREAM if (inStream.GetNumberOfUnreadBits() >= BYTES_TO_BITS(HEADER_SIZE)) inStream.IgnoreBytes(HEADER_SIZE); else inStream.IgnoreBits(inStream.GetNumberOfUnreadBits());
|
||||
#define CMSGHEADER BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
|
||||
#define CMSGHEADER PacketUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
|
||||
#define SEND_PACKET Game::server->Send(&bitStream, sysAddr, false);
|
||||
#define SEND_PACKET_BROADCAST Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -101,7 +101,7 @@ enum class eReplicaComponentType : uint32_t {
|
||||
TRADE,
|
||||
USER_CONTROL,
|
||||
IGNORE_LIST,
|
||||
MULTI_ZONE_ENTRANCE,
|
||||
ROCKET_LAUNCH_LUP,
|
||||
BUFF_REAL, // the real buff component, should just be name BUFF
|
||||
INTERACTION_MANAGER,
|
||||
DONATION_VENDOR,
|
||||
|
||||
@@ -55,7 +55,7 @@ CDClientManager::CDClientManager() {
|
||||
CDBehaviorParameterTable::Instance().LoadValuesFromDatabase();
|
||||
CDBehaviorTemplateTable::Instance().LoadValuesFromDatabase();
|
||||
CDBrickIDTableTable::Instance().LoadValuesFromDatabase();
|
||||
CDCLIENT_DONT_CACHE_TABLE(CDComponentsRegistryTable::Instance().LoadValuesFromDatabase());
|
||||
CDComponentsRegistryTable::Instance().LoadValuesFromDatabase();
|
||||
CDCurrencyTableTable::Instance().LoadValuesFromDatabase();
|
||||
CDDestructibleComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDEmoteTableTable::Instance().LoadValuesFromDatabase();
|
||||
@@ -65,8 +65,8 @@ CDClientManager::CDClientManager() {
|
||||
CDItemSetSkillsTable::Instance().LoadValuesFromDatabase();
|
||||
CDItemSetsTable::Instance().LoadValuesFromDatabase();
|
||||
CDLevelProgressionLookupTable::Instance().LoadValuesFromDatabase();
|
||||
CDCLIENT_DONT_CACHE_TABLE(CDLootMatrixTable::Instance().LoadValuesFromDatabase());
|
||||
CDCLIENT_DONT_CACHE_TABLE(CDLootTableTable::Instance().LoadValuesFromDatabase());
|
||||
CDLootMatrixTable::Instance().LoadValuesFromDatabase();
|
||||
CDLootTableTable::Instance().LoadValuesFromDatabase();
|
||||
CDMissionEmailTable::Instance().LoadValuesFromDatabase();
|
||||
CDMissionNPCComponentTable::Instance().LoadValuesFromDatabase();
|
||||
CDMissionTasksTable::Instance().LoadValuesFromDatabase();
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
#include "CDBehaviorParameterTable.h"
|
||||
#include "GeneralUtils.h"
|
||||
|
||||
uint64_t GetKey(const uint32_t behaviorID, const uint32_t parameterID) {
|
||||
uint64_t key = behaviorID;
|
||||
key <<= 31U;
|
||||
key |= parameterID;
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
void CDBehaviorParameterTable::LoadValuesFromDatabase() {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM BehaviorParameter");
|
||||
uint32_t uniqueParameterId = 0;
|
||||
uint64_t hash = 0;
|
||||
while (!tableData.eof()) {
|
||||
uint32_t behaviorID = tableData.getIntField("behaviorID", -1);
|
||||
CDBehaviorParameter entry;
|
||||
entry.behaviorID = tableData.getIntField("behaviorID", -1);
|
||||
auto candidateStringToAdd = std::string(tableData.getStringField("parameterID", ""));
|
||||
auto parameter = m_ParametersList.find(candidateStringToAdd);
|
||||
uint32_t parameterId;
|
||||
if (parameter != m_ParametersList.end()) {
|
||||
parameterId = parameter->second;
|
||||
entry.parameterID = parameter;
|
||||
} else {
|
||||
parameterId = m_ParametersList.insert(std::make_pair(candidateStringToAdd, m_ParametersList.size())).first->second;
|
||||
entry.parameterID = m_ParametersList.insert(std::make_pair(candidateStringToAdd, uniqueParameterId)).first;
|
||||
uniqueParameterId++;
|
||||
}
|
||||
uint64_t hash = GetKey(behaviorID, parameterId);
|
||||
float value = tableData.getFloatField("value", -1.0f);
|
||||
hash = entry.behaviorID;
|
||||
hash = (hash << 31U) | entry.parameterID->second;
|
||||
entry.value = tableData.getFloatField("value", -1.0f);
|
||||
|
||||
m_Entries.insert(std::make_pair(hash, value));
|
||||
m_Entries.insert(std::make_pair(hash, entry));
|
||||
|
||||
tableData.nextRow();
|
||||
}
|
||||
@@ -34,21 +30,25 @@ void CDBehaviorParameterTable::LoadValuesFromDatabase() {
|
||||
float CDBehaviorParameterTable::GetValue(const uint32_t behaviorID, const std::string& name, const float defaultValue) {
|
||||
auto parameterID = this->m_ParametersList.find(name);
|
||||
if (parameterID == this->m_ParametersList.end()) return defaultValue;
|
||||
auto hash = GetKey(behaviorID, parameterID->second);
|
||||
|
||||
uint64_t hash = behaviorID;
|
||||
|
||||
hash = (hash << 31U) | parameterID->second;
|
||||
|
||||
// Search for specific parameter
|
||||
auto it = m_Entries.find(hash);
|
||||
return it != m_Entries.end() ? it->second : defaultValue;
|
||||
const auto& it = m_Entries.find(hash);
|
||||
return it != m_Entries.end() ? it->second.value : defaultValue;
|
||||
}
|
||||
|
||||
std::map<std::string, float> CDBehaviorParameterTable::GetParametersByBehaviorID(uint32_t behaviorID) {
|
||||
uint64_t hashBase = behaviorID;
|
||||
std::map<std::string, float> returnInfo;
|
||||
for (auto& [parameterString, parameterId] : m_ParametersList) {
|
||||
uint64_t hash = GetKey(hashBase, parameterId);
|
||||
uint64_t hash;
|
||||
for (auto& parameterCandidate : m_ParametersList) {
|
||||
hash = (hashBase << 31U) | parameterCandidate.second;
|
||||
auto infoCandidate = m_Entries.find(hash);
|
||||
if (infoCandidate != m_Entries.end()) {
|
||||
returnInfo.insert(std::make_pair(parameterString, infoCandidate->second));
|
||||
returnInfo.insert(std::make_pair(infoCandidate->second.parameterID->first, infoCandidate->second.value));
|
||||
}
|
||||
}
|
||||
return returnInfo;
|
||||
|
||||
@@ -5,11 +5,15 @@
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
struct CDBehaviorParameter {
|
||||
unsigned int behaviorID; //!< The Behavior ID
|
||||
std::unordered_map<std::string, uint32_t>::iterator parameterID; //!< The Parameter ID
|
||||
float value; //!< The value of the behavior template
|
||||
};
|
||||
|
||||
class CDBehaviorParameterTable : public CDTable<CDBehaviorParameterTable> {
|
||||
private:
|
||||
typedef uint64_t BehaviorParameterHash;
|
||||
typedef float BehaviorParameterValue;
|
||||
std::unordered_map<BehaviorParameterHash, BehaviorParameterValue> m_Entries;
|
||||
std::unordered_map<uint64_t, CDBehaviorParameter> m_Entries;
|
||||
std::unordered_map<std::string, uint32_t> m_ParametersList;
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
|
||||
@@ -11,7 +11,6 @@ void CDComponentsRegistryTable::LoadValuesFromDatabase() {
|
||||
entry.component_id = tableData.getIntField("component_id", -1);
|
||||
|
||||
this->mappedEntries.insert_or_assign(((uint64_t)entry.component_type) << 32 | ((uint64_t)entry.id), entry.component_id);
|
||||
this->mappedEntries.insert_or_assign(entry.id, 0);
|
||||
|
||||
tableData.nextRow();
|
||||
}
|
||||
@@ -20,18 +19,19 @@ void CDComponentsRegistryTable::LoadValuesFromDatabase() {
|
||||
}
|
||||
|
||||
int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponentType componentType, int32_t defaultValue) {
|
||||
auto exists = mappedEntries.find(id);
|
||||
if (exists != mappedEntries.end()) {
|
||||
auto iter = mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
|
||||
return iter == mappedEntries.end() ? defaultValue : iter->second;
|
||||
auto iter = mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
|
||||
|
||||
if (iter == this->mappedEntries.end()) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
// Now get the data. Get all components of this entity so we dont do a query for each component
|
||||
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM ComponentsRegistry WHERE id = ?;");
|
||||
return iter->second;
|
||||
// Now get the data
|
||||
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM ComponentsRegistry WHERE id = ? AND component_type = ?;");
|
||||
query.bind(1, static_cast<int32_t>(id));
|
||||
query.bind(2, static_cast<int32_t>(componentType));
|
||||
|
||||
auto tableData = query.execQuery();
|
||||
|
||||
while (!tableData.eof()) {
|
||||
CDComponentsRegistry entry;
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
@@ -43,9 +43,7 @@ int32_t CDComponentsRegistryTable::GetByIDAndType(uint32_t id, eReplicaComponent
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
mappedEntries.insert_or_assign(id, 0);
|
||||
|
||||
auto iter = this->mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
|
||||
iter = this->mappedEntries.find(((uint64_t)componentType) << 32 | ((uint64_t)id));
|
||||
|
||||
return iter == this->mappedEntries.end() ? defaultValue : iter->second;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ struct CDComponentsRegistry {
|
||||
|
||||
class CDComponentsRegistryTable : public CDTable<CDComponentsRegistryTable> {
|
||||
private:
|
||||
std::unordered_map<uint64_t, uint32_t> mappedEntries; //id, component_type, component_id
|
||||
std::map<uint64_t, uint32_t> mappedEntries; //id, component_type, component_id
|
||||
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
|
||||
@@ -1,18 +1,5 @@
|
||||
#include "CDLootMatrixTable.h"
|
||||
|
||||
CDLootMatrix CDLootMatrixTable::ReadRow(CppSQLite3Query& tableData) const {
|
||||
CDLootMatrix entry{};
|
||||
if (tableData.eof()) return entry;
|
||||
entry.LootTableIndex = tableData.getIntField("LootTableIndex", -1);
|
||||
entry.RarityTableIndex = tableData.getIntField("RarityTableIndex", -1);
|
||||
entry.percent = tableData.getFloatField("percent", -1.0f);
|
||||
entry.minToDrop = tableData.getIntField("minToDrop", -1);
|
||||
entry.maxToDrop = tableData.getIntField("maxToDrop", -1);
|
||||
entry.flagID = tableData.getIntField("flagID", -1);
|
||||
UNUSED(entry.gate_version = tableData.getStringField("gate_version", ""));
|
||||
return entry;
|
||||
}
|
||||
|
||||
void CDLootMatrixTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
@@ -24,6 +11,8 @@ void CDLootMatrixTable::LoadValuesFromDatabase() {
|
||||
tableSize.nextRow();
|
||||
}
|
||||
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
|
||||
@@ -31,28 +20,33 @@ void CDLootMatrixTable::LoadValuesFromDatabase() {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootMatrix");
|
||||
while (!tableData.eof()) {
|
||||
CDLootMatrix entry;
|
||||
uint32_t lootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1);
|
||||
entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1);
|
||||
entry.LootTableIndex = tableData.getIntField("LootTableIndex", -1);
|
||||
entry.RarityTableIndex = tableData.getIntField("RarityTableIndex", -1);
|
||||
entry.percent = tableData.getFloatField("percent", -1.0f);
|
||||
entry.minToDrop = tableData.getIntField("minToDrop", -1);
|
||||
entry.maxToDrop = tableData.getIntField("maxToDrop", -1);
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
entry.flagID = tableData.getIntField("flagID", -1);
|
||||
UNUSED(entry.gate_version = tableData.getStringField("gate_version", ""));
|
||||
|
||||
this->entries[lootMatrixIndex].push_back(ReadRow(tableData));
|
||||
tableData.nextRow();
|
||||
}
|
||||
}
|
||||
|
||||
const LootMatrixEntries& CDLootMatrixTable::GetMatrix(uint32_t matrixId) {
|
||||
auto itr = this->entries.find(matrixId);
|
||||
if (itr != this->entries.end()) {
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM LootMatrix where LootMatrixIndex = ?;");
|
||||
query.bind(1, static_cast<int32_t>(matrixId));
|
||||
|
||||
auto tableData = query.execQuery();
|
||||
while (!tableData.eof()) {
|
||||
this->entries[matrixId].push_back(ReadRow(tableData));
|
||||
this->entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
return this->entries[matrixId];
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
std::vector<CDLootMatrix> CDLootMatrixTable::Query(std::function<bool(CDLootMatrix)> predicate) {
|
||||
|
||||
std::vector<CDLootMatrix> data = cpplinq::from(this->entries)
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
const std::vector<CDLootMatrix>& CDLootMatrixTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,26 +4,26 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDLootMatrix {
|
||||
unsigned int LootMatrixIndex; //!< The Loot Matrix Index
|
||||
unsigned int LootTableIndex; //!< The Loot Table Index
|
||||
unsigned int RarityTableIndex; //!< The Rarity Table Index
|
||||
float percent; //!< The percent that this matrix is used?
|
||||
unsigned int minToDrop; //!< The minimum amount of loot from this matrix to drop
|
||||
unsigned int maxToDrop; //!< The maximum amount of loot from this matrix to drop
|
||||
unsigned int id; //!< The ID of the Loot Matrix
|
||||
unsigned int flagID; //!< ???
|
||||
UNUSED(std::string gate_version); //!< The Gate Version
|
||||
};
|
||||
|
||||
typedef uint32_t LootMatrixIndex;
|
||||
typedef std::vector<CDLootMatrix> LootMatrixEntries;
|
||||
|
||||
class CDLootMatrixTable : public CDTable<CDLootMatrixTable> {
|
||||
private:
|
||||
std::vector<CDLootMatrix> entries;
|
||||
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDLootMatrix> Query(std::function<bool(CDLootMatrix)> predicate);
|
||||
|
||||
// Gets a matrix by ID or inserts a blank one if none existed.
|
||||
const LootMatrixEntries& GetMatrix(uint32_t matrixId);
|
||||
private:
|
||||
CDLootMatrix ReadRow(CppSQLite3Query& tableData) const;
|
||||
std::unordered_map<LootMatrixIndex, LootMatrixEntries> entries;
|
||||
const std::vector<CDLootMatrix>& GetEntries() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,14 +1,5 @@
|
||||
#include "CDLootTableTable.h"
|
||||
|
||||
CDLootTable CDLootTableTable::ReadRow(CppSQLite3Query& tableData) const {
|
||||
CDLootTable entry{};
|
||||
if (tableData.eof()) return entry;
|
||||
entry.itemid = tableData.getIntField("itemid", -1);
|
||||
entry.MissionDrop = tableData.getIntField("MissionDrop", -1) == 1 ? true : false;
|
||||
entry.sortPriority = tableData.getIntField("sortPriority", -1);
|
||||
return entry;
|
||||
}
|
||||
|
||||
void CDLootTableTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
@@ -20,6 +11,8 @@ void CDLootTableTable::LoadValuesFromDatabase() {
|
||||
tableSize.nextRow();
|
||||
}
|
||||
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
|
||||
@@ -27,28 +20,32 @@ void CDLootTableTable::LoadValuesFromDatabase() {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM LootTable");
|
||||
while (!tableData.eof()) {
|
||||
CDLootTable entry;
|
||||
uint32_t lootTableIndex = tableData.getIntField("LootTableIndex", -1);
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
entry.itemid = tableData.getIntField("itemid", -1);
|
||||
entry.LootTableIndex = tableData.getIntField("LootTableIndex", -1);
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
entry.MissionDrop = tableData.getIntField("MissionDrop", -1) == 1 ? true : false;
|
||||
entry.sortPriority = tableData.getIntField("sortPriority", -1);
|
||||
|
||||
this->entries[lootTableIndex].push_back(ReadRow(tableData));
|
||||
tableData.nextRow();
|
||||
}
|
||||
}
|
||||
|
||||
const LootTableEntries& CDLootTableTable::GetTable(uint32_t tableId) {
|
||||
auto itr = this->entries.find(tableId);
|
||||
if (itr != this->entries.end()) {
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
auto query = CDClientDatabase::CreatePreppedStmt("SELECT * FROM LootTable WHERE LootTableIndex = ?;");
|
||||
query.bind(1, static_cast<int32_t>(tableId));
|
||||
auto tableData = query.execQuery();
|
||||
|
||||
while (!tableData.eof()) {
|
||||
CDLootTable entry;
|
||||
this->entries[tableId].push_back(ReadRow(tableData));
|
||||
this->entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
return this->entries[tableId];
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
std::vector<CDLootTable> CDLootTableTable::Query(std::function<bool(CDLootTable)> predicate) {
|
||||
|
||||
std::vector<CDLootTable> data = cpplinq::from(this->entries)
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
//! Gets all the entries in the table
|
||||
const std::vector<CDLootTable>& CDLootTableTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,21 +6,20 @@
|
||||
struct CDLootTable {
|
||||
unsigned int itemid; //!< The LOT of the item
|
||||
unsigned int LootTableIndex; //!< The Loot Table Index
|
||||
unsigned int id; //!< The ID
|
||||
bool MissionDrop; //!< Whether or not this loot table is a mission drop
|
||||
unsigned int sortPriority; //!< The sorting priority
|
||||
};
|
||||
|
||||
typedef uint32_t LootTableIndex;
|
||||
typedef std::vector<CDLootTable> LootTableEntries;
|
||||
|
||||
class CDLootTableTable : public CDTable<CDLootTableTable> {
|
||||
private:
|
||||
CDLootTable ReadRow(CppSQLite3Query& tableData) const;
|
||||
std::unordered_map<LootTableIndex, LootTableEntries> entries;
|
||||
std::vector<CDLootTable> entries;
|
||||
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
const LootTableEntries& GetTable(uint32_t tableId);
|
||||
std::vector<CDLootTable> Query(std::function<bool(CDLootTable)> predicate);
|
||||
|
||||
const std::vector<CDLootTable>& GetEntries() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,34 +1,24 @@
|
||||
#include "CDRarityTableTable.h"
|
||||
|
||||
void CDRarityTableTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM RarityTable");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
|
||||
tableSize.nextRow();
|
||||
}
|
||||
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RarityTable order by randmax desc;");
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RarityTable");
|
||||
while (!tableData.eof()) {
|
||||
uint32_t rarityTableIndex = tableData.getIntField("RarityTableIndex", -1);
|
||||
|
||||
CDRarityTable entry;
|
||||
uint32_t id = tableData.getIntField("id", -1);
|
||||
entry.randmax = tableData.getFloatField("randmax", -1);
|
||||
entry.rarity = tableData.getIntField("rarity", -1);
|
||||
entries[rarityTableIndex].push_back(entry);
|
||||
entry.RarityTableIndex = tableData.getIntField("RarityTableIndex", -1);
|
||||
|
||||
this->entries.insert_or_assign(id, entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
const std::vector<CDRarityTable>& CDRarityTableTable::GetRarityTable(uint32_t id) {
|
||||
return entries[id];
|
||||
//! Queries the table with a custom "where" clause
|
||||
const std::optional<CDRarityTable> CDRarityTableTable::Get(uint32_t id) {
|
||||
auto it = this->entries.find(id);
|
||||
return it != this->entries.end() ? std::make_optional(it->second) : std::nullopt;
|
||||
}
|
||||
|
||||
@@ -4,20 +4,35 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDRarityTable {
|
||||
unsigned int id;
|
||||
float randmax;
|
||||
unsigned int rarity;
|
||||
};
|
||||
unsigned int RarityTableIndex;
|
||||
|
||||
typedef std::vector<CDRarityTable> RarityTable;
|
||||
friend bool operator> (const CDRarityTable& c1, const CDRarityTable& c2) {
|
||||
return c1.rarity > c2.rarity;
|
||||
}
|
||||
|
||||
friend bool operator>= (const CDRarityTable& c1, const CDRarityTable& c2) {
|
||||
return c1.rarity >= c2.rarity;
|
||||
}
|
||||
|
||||
friend bool operator< (const CDRarityTable& c1, const CDRarityTable& c2) {
|
||||
return c1.rarity < c2.rarity;
|
||||
}
|
||||
|
||||
friend bool operator<= (const CDRarityTable& c1, const CDRarityTable& c2) {
|
||||
return c1.rarity <= c2.rarity;
|
||||
}
|
||||
};
|
||||
|
||||
class CDRarityTableTable : public CDTable<CDRarityTableTable> {
|
||||
private:
|
||||
typedef uint32_t RarityTableIndex;
|
||||
std::unordered_map<RarityTableIndex, std::vector<CDRarityTable>> entries;
|
||||
std::unordered_map<uint32_t, CDRarityTable> entries;
|
||||
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
|
||||
const std::vector<CDRarityTable>& GetRarityTable(uint32_t predicate);
|
||||
// Queries the table with a custom "where" clause
|
||||
const std::optional<CDRarityTable> Get(uint32_t predicate);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,26 +1,11 @@
|
||||
#include "CDRebuildComponentTable.h"
|
||||
|
||||
void CDRebuildComponentTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM RebuildComponent");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
|
||||
tableSize.nextRow();
|
||||
}
|
||||
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RebuildComponent");
|
||||
while (!tableData.eof()) {
|
||||
CDRebuildComponent entry;
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
uint32_t id = tableData.getIntField("id", -1);
|
||||
entry.reset_time = tableData.getFloatField("reset_time", -1.0f);
|
||||
entry.complete_time = tableData.getFloatField("complete_time", -1.0f);
|
||||
entry.take_imagination = tableData.getIntField("take_imagination", -1);
|
||||
@@ -31,23 +16,12 @@ void CDRebuildComponentTable::LoadValuesFromDatabase() {
|
||||
entry.post_imagination_cost = tableData.getIntField("post_imagination_cost", -1);
|
||||
entry.time_before_smash = tableData.getFloatField("time_before_smash", -1.0f);
|
||||
|
||||
this->entries.push_back(entry);
|
||||
this->entries.insert_or_assign(id, entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
std::vector<CDRebuildComponent> CDRebuildComponentTable::Query(std::function<bool(CDRebuildComponent)> predicate) {
|
||||
|
||||
std::vector<CDRebuildComponent> data = cpplinq::from(this->entries)
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
const std::optional<CDRebuildComponent> CDRebuildComponentTable::Get(uint32_t componentId) {
|
||||
auto it = this->entries.find(componentId);
|
||||
return it != this->entries.end() ? std::make_optional(it->second) : std::nullopt;
|
||||
}
|
||||
|
||||
const std::vector<CDRebuildComponent>& CDRebuildComponentTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDRebuildComponent {
|
||||
unsigned int id; //!< The component Id
|
||||
float reset_time; //!< The reset time
|
||||
float complete_time; //!< The complete time
|
||||
unsigned int take_imagination; //!< The amount of imagination it costs
|
||||
@@ -18,13 +17,11 @@ struct CDRebuildComponent {
|
||||
|
||||
class CDRebuildComponentTable : public CDTable<CDRebuildComponentTable> {
|
||||
private:
|
||||
std::vector<CDRebuildComponent> entries;
|
||||
std::unordered_map<uint32_t, CDRebuildComponent> entries;
|
||||
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDRebuildComponent> Query(std::function<bool(CDRebuildComponent)> predicate);
|
||||
|
||||
const std::vector<CDRebuildComponent>& GetEntries() const;
|
||||
const std::optional<CDRebuildComponent> Get(uint32_t componentId);
|
||||
};
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@ void CDRewardsTable::LoadValuesFromDatabase() {
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM Rewards");
|
||||
while (!tableData.eof()) {
|
||||
CDRewards entry;
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
uint32_t id = tableData.getIntField("id", -1);
|
||||
entry.levelID = tableData.getIntField("LevelID", -1);
|
||||
entry.missionID = tableData.getIntField("MissionID", -1);
|
||||
entry.rewardType = tableData.getIntField("RewardType", -1);
|
||||
entry.value = tableData.getIntField("value", -1);
|
||||
entry.count = tableData.getIntField("count", -1);
|
||||
|
||||
m_entries.insert(std::make_pair(entry.id, entry));
|
||||
m_entries.push_back(entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
@@ -19,9 +19,9 @@ void CDRewardsTable::LoadValuesFromDatabase() {
|
||||
}
|
||||
|
||||
std::vector<CDRewards> CDRewardsTable::GetByLevelID(uint32_t levelID) {
|
||||
std::vector<CDRewards> result{};
|
||||
for (const auto& e : m_entries) {
|
||||
if (e.second.levelID == levelID) result.push_back(e.second);
|
||||
std::vector<CDRewards> result;
|
||||
for (const auto& levelData : m_entries) {
|
||||
if (levelData.levelID == levelID) result.push_back(levelData);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <string>
|
||||
|
||||
struct CDRewards {
|
||||
int32_t id;
|
||||
int32_t levelID;
|
||||
int32_t missionID;
|
||||
int32_t rewardType;
|
||||
@@ -14,10 +13,7 @@ struct CDRewards {
|
||||
class CDRewardsTable : public CDTable<CDRewardsTable> {
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
|
||||
static const std::string GetTableName() { return "Rewards"; };
|
||||
std::vector<CDRewards> GetByLevelID(uint32_t levelID);
|
||||
|
||||
private:
|
||||
std::map<uint32_t, CDRewards> m_entries;
|
||||
std::vector<CDRewards> m_entries;
|
||||
};
|
||||
|
||||
@@ -1,39 +1,21 @@
|
||||
#include "CDScriptComponentTable.h"
|
||||
|
||||
void CDScriptComponentTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ScriptComponent");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
|
||||
tableSize.nextRow();
|
||||
}
|
||||
|
||||
tableSize.finalize();
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ScriptComponent");
|
||||
while (!tableData.eof()) {
|
||||
CDScriptComponent entry;
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
uint32_t id = tableData.getIntField("id", -1);
|
||||
entry.script_name = tableData.getStringField("script_name", "");
|
||||
entry.client_script_name = tableData.getStringField("client_script_name", "");
|
||||
|
||||
this->entries.insert(std::make_pair(entry.id, entry));
|
||||
this->entries.insert_or_assign(id, entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
const CDScriptComponent& CDScriptComponentTable::GetByID(unsigned int id) {
|
||||
std::map<unsigned int, CDScriptComponent>::iterator it = this->entries.find(id);
|
||||
if (it != this->entries.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return m_ToReturnWhenNoneFound;
|
||||
const std::optional<CDScriptComponent> CDScriptComponentTable::GetByID(unsigned int id) {
|
||||
auto it = this->entries.find(id);
|
||||
return (it != this->entries.end()) ? std::make_optional<CDScriptComponent>(it->second) : std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,19 +4,16 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDScriptComponent {
|
||||
unsigned int id; //!< The component ID
|
||||
std::string script_name; //!< The script name
|
||||
std::string client_script_name; //!< The client script name
|
||||
std::string script_name; //!< The script name
|
||||
std::string client_script_name; //!< The client script name
|
||||
};
|
||||
|
||||
class CDScriptComponentTable : public CDTable<CDScriptComponentTable> {
|
||||
private:
|
||||
std::map<unsigned int, CDScriptComponent> entries;
|
||||
CDScriptComponent m_ToReturnWhenNoneFound;
|
||||
|
||||
std::unordered_map<unsigned int, CDScriptComponent> entries;
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Gets an entry by scriptID
|
||||
const CDScriptComponent& GetByID(unsigned int id);
|
||||
const std::optional<CDScriptComponent> GetByID(unsigned int id);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,27 +1,10 @@
|
||||
#include "CDSkillBehaviorTable.h"
|
||||
|
||||
void CDSkillBehaviorTable::LoadValuesFromDatabase() {
|
||||
m_empty = CDSkillBehavior();
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM SkillBehavior");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
|
||||
tableSize.nextRow();
|
||||
}
|
||||
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
//this->entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM SkillBehavior");
|
||||
while (!tableData.eof()) {
|
||||
CDSkillBehavior entry;
|
||||
entry.skillID = tableData.getIntField("skillID", -1);
|
||||
uint32_t skillID = tableData.getIntField("skillID", -1);
|
||||
UNUSED(entry.locStatus = tableData.getIntField("locStatus", -1));
|
||||
entry.behaviorID = tableData.getIntField("behaviorID", -1);
|
||||
entry.imaginationcost = tableData.getIntField("imaginationcost", -1);
|
||||
@@ -41,20 +24,13 @@ void CDSkillBehaviorTable::LoadValuesFromDatabase() {
|
||||
UNUSED(entry.gate_version = tableData.getStringField("gate_version", ""));
|
||||
UNUSED(entry.cancelType = tableData.getIntField("cancelType", -1));
|
||||
|
||||
this->entries.insert(std::make_pair(entry.skillID, entry));
|
||||
//this->entries.push_back(entry);
|
||||
this->entries.insert_or_assign(skillID, entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
const CDSkillBehavior& CDSkillBehaviorTable::GetSkillByID(unsigned int skillID) {
|
||||
std::map<unsigned int, CDSkillBehavior>::iterator it = this->entries.find(skillID);
|
||||
if (it != this->entries.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return m_empty;
|
||||
const std::optional<CDSkillBehavior> CDSkillBehaviorTable::GetSkillByID(unsigned int skillID) {
|
||||
auto it = this->entries.find(skillID);
|
||||
return it != this->entries.end() ? std::make_optional(it->second) : std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDSkillBehavior {
|
||||
unsigned int skillID; //!< The Skill ID of the skill
|
||||
UNUSED(unsigned int locStatus); //!< ??
|
||||
unsigned int behaviorID; //!< The Behavior ID of the skill
|
||||
unsigned int imaginationcost; //!< The imagination cost of the skill
|
||||
@@ -27,13 +26,11 @@ struct CDSkillBehavior {
|
||||
|
||||
class CDSkillBehaviorTable : public CDTable<CDSkillBehaviorTable> {
|
||||
private:
|
||||
std::map<unsigned int, CDSkillBehavior> entries;
|
||||
CDSkillBehavior m_empty;
|
||||
|
||||
std::unordered_map<uint32_t, CDSkillBehavior> entries;
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
|
||||
// Gets an entry by skillID
|
||||
const CDSkillBehavior& GetSkillByID(unsigned int skillID);
|
||||
const std::optional<CDSkillBehavior> GetSkillByID(unsigned int skillID);
|
||||
};
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "DluAssert.h"
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
@@ -1,50 +1,22 @@
|
||||
#include "CDVendorComponentTable.h"
|
||||
|
||||
void CDVendorComponentTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM VendorComponent");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
|
||||
tableSize.nextRow();
|
||||
}
|
||||
|
||||
tableSize.finalize();
|
||||
|
||||
// Reserve the size
|
||||
this->entries.reserve(size);
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM VendorComponent");
|
||||
while (!tableData.eof()) {
|
||||
CDVendorComponent entry;
|
||||
entry.id = tableData.getIntField("id", -1);
|
||||
entry.buyScalar = tableData.getFloatField("buyScalar", 0.0f);
|
||||
uint32_t id = tableData.getIntField("id", -1);
|
||||
entry.buyScalar = tableData.getFloatField("buyScalar", -1.0f);
|
||||
entry.sellScalar = tableData.getFloatField("sellScalar", -1.0f);
|
||||
entry.refreshTimeSeconds = tableData.getFloatField("refreshTimeSeconds", -1.0f);
|
||||
entry.LootMatrixIndex = tableData.getIntField("LootMatrixIndex", -1);
|
||||
|
||||
this->entries.push_back(entry);
|
||||
this->entries.insert_or_assign(id, entry);
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
//! Queries the table with a custom "where" clause
|
||||
std::vector<CDVendorComponent> CDVendorComponentTable::Query(std::function<bool(CDVendorComponent)> predicate) {
|
||||
|
||||
std::vector<CDVendorComponent> data = cpplinq::from(this->entries)
|
||||
>> cpplinq::where(predicate)
|
||||
>> cpplinq::to_vector();
|
||||
|
||||
return data;
|
||||
const std::optional<CDVendorComponent> CDVendorComponentTable::Query(uint32_t id) {
|
||||
const auto& iter = entries.find(id);
|
||||
return iter != entries.end() ? std::make_optional(iter->second) : std::nullopt;
|
||||
}
|
||||
|
||||
//! Gets all the entries in the table
|
||||
const std::vector<CDVendorComponent>& CDVendorComponentTable::GetEntries() const {
|
||||
return this->entries;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDVendorComponent {
|
||||
unsigned int id; //!< The Component ID
|
||||
float buyScalar; //!< Buy Scalar (what does that mean?)
|
||||
float sellScalar; //!< Sell Scalar (what does that mean?)
|
||||
float refreshTimeSeconds; //!< The refresh time
|
||||
@@ -13,13 +12,11 @@ struct CDVendorComponent {
|
||||
|
||||
class CDVendorComponentTable : public CDTable<CDVendorComponentTable> {
|
||||
private:
|
||||
std::vector<CDVendorComponent> entries;
|
||||
std::unordered_map<uint32_t, CDVendorComponent> entries;
|
||||
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
// Queries the table with a custom "where" clause
|
||||
std::vector<CDVendorComponent> Query(std::function<bool(CDVendorComponent)> predicate);
|
||||
|
||||
const std::vector<CDVendorComponent>& GetEntries(void) const;
|
||||
const std::optional<CDVendorComponent> Query(uint32_t id);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,18 +1,6 @@
|
||||
#include "CDZoneTableTable.h"
|
||||
|
||||
void CDZoneTableTable::LoadValuesFromDatabase() {
|
||||
|
||||
// First, get the size of the table
|
||||
unsigned int size = 0;
|
||||
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM ZoneTable");
|
||||
while (!tableSize.eof()) {
|
||||
size = tableSize.getIntField(0, 0);
|
||||
|
||||
tableSize.nextRow();
|
||||
}
|
||||
|
||||
tableSize.finalize();
|
||||
|
||||
// Now get the data
|
||||
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM ZoneTable");
|
||||
while (!tableData.eof()) {
|
||||
@@ -48,18 +36,11 @@ void CDZoneTableTable::LoadValuesFromDatabase() {
|
||||
this->m_Entries.insert(std::make_pair(entry.zoneID, entry));
|
||||
tableData.nextRow();
|
||||
}
|
||||
|
||||
tableData.finalize();
|
||||
}
|
||||
|
||||
//! Queries the table with a zoneID to find.
|
||||
const CDZoneTable* CDZoneTableTable::Query(unsigned int zoneID) {
|
||||
const std::optional<CDZoneTable> CDZoneTableTable::Query(unsigned int zoneID) {
|
||||
const auto& iter = m_Entries.find(zoneID);
|
||||
|
||||
if (iter != m_Entries.end()) {
|
||||
return &iter->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return iter != m_Entries.end() ? std::make_optional(iter->second) : std::nullopt;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
// Custom Classes
|
||||
#include "CDTable.h"
|
||||
|
||||
struct CDZoneTable {
|
||||
@@ -35,11 +34,11 @@ struct CDZoneTable {
|
||||
|
||||
class CDZoneTableTable : public CDTable<CDZoneTableTable> {
|
||||
private:
|
||||
std::map<unsigned int, CDZoneTable> m_Entries;
|
||||
std::unordered_map<uint32_t, CDZoneTable> m_Entries;
|
||||
|
||||
public:
|
||||
void LoadValuesFromDatabase();
|
||||
|
||||
// Queries the table with a zoneID to find.
|
||||
const CDZoneTable* Query(unsigned int zoneID);
|
||||
const std::optional<CDZoneTable> Query(unsigned int zoneID);
|
||||
};
|
||||
|
||||
151
dGame/Entity.cpp
151
dGame/Entity.cpp
@@ -30,7 +30,7 @@
|
||||
#include "Component.h"
|
||||
#include "ControllablePhysicsComponent.h"
|
||||
#include "RenderComponent.h"
|
||||
#include "MultiZoneEntranceComponent.h"
|
||||
#include "RocketLaunchLupComponent.h"
|
||||
#include "CharacterComponent.h"
|
||||
#include "DestroyableComponent.h"
|
||||
#include "BuffComponent.h"
|
||||
@@ -51,7 +51,6 @@
|
||||
#include "BuildBorderComponent.h"
|
||||
#include "MovementAIComponent.h"
|
||||
#include "VendorComponent.h"
|
||||
#include "DonationVendorComponent.h"
|
||||
#include "RocketLaunchpadControlComponent.h"
|
||||
#include "PropertyComponent.h"
|
||||
#include "BaseCombatAIComponent.h"
|
||||
@@ -71,7 +70,6 @@
|
||||
#include "ShootingGalleryComponent.h"
|
||||
#include "RailActivatorComponent.h"
|
||||
#include "LUPExhibitComponent.h"
|
||||
#include "RacingSoundTriggerComponent.h"
|
||||
#include "TriggerComponent.h"
|
||||
#include "eGameMasterLevel.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
@@ -319,9 +317,6 @@ void Entity::Initialize() {
|
||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SOUND_TRIGGER, -1) != -1) {
|
||||
auto* comp = new SoundTriggerComponent(this);
|
||||
m_Components.insert(std::make_pair(eReplicaComponentType::SOUND_TRIGGER, comp));
|
||||
} else if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::RACING_SOUND_TRIGGER, -1) != -1) {
|
||||
auto* comp = new RacingSoundTriggerComponent(this);
|
||||
m_Components.insert(std::make_pair(eReplicaComponentType::RACING_SOUND_TRIGGER, comp));
|
||||
}
|
||||
|
||||
//Also check for the collectible id:
|
||||
@@ -377,7 +372,6 @@ void Entity::Initialize() {
|
||||
comp->SetIsSmashable(destCompData[0].isSmashable);
|
||||
|
||||
comp->SetLootMatrixID(destCompData[0].LootMatrixIndex);
|
||||
Loot::CacheMatrix(destCompData[0].LootMatrixIndex);
|
||||
|
||||
// Now get currency information
|
||||
uint32_t npcMinLevel = destCompData[0].level;
|
||||
@@ -452,9 +446,9 @@ void Entity::Initialize() {
|
||||
m_Components.insert(std::make_pair(eReplicaComponentType::INVENTORY, comp));
|
||||
}
|
||||
// if this component exists, then we initialize it. it's value is always 0
|
||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MULTI_ZONE_ENTRANCE, -1) != -1) {
|
||||
auto comp = new MultiZoneEntranceComponent(this);
|
||||
m_Components.insert(std::make_pair(eReplicaComponentType::MULTI_ZONE_ENTRANCE, comp));
|
||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::ROCKET_LAUNCH_LUP, -1) != -1) {
|
||||
auto comp = new RocketLaunchLupComponent(this);
|
||||
m_Components.insert(std::make_pair(eReplicaComponentType::ROCKET_LAUNCH_LUP, comp));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -469,9 +463,11 @@ void Entity::Initialize() {
|
||||
if (scriptComponentID > 0 || m_Character) {
|
||||
std::string clientScriptName;
|
||||
if (!m_Character) {
|
||||
CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID);
|
||||
scriptName = scriptCompData.script_name;
|
||||
clientScriptName = scriptCompData.client_script_name;
|
||||
auto scriptCompData = scriptCompTable->GetByID(scriptComponentID);
|
||||
if (scriptCompData) {
|
||||
scriptName = scriptCompData->script_name;
|
||||
clientScriptName = scriptCompData->client_script_name;
|
||||
}
|
||||
} else {
|
||||
scriptName = "";
|
||||
}
|
||||
@@ -510,16 +506,17 @@ void Entity::Initialize() {
|
||||
|
||||
// ZoneControl script
|
||||
if (m_TemplateID == 2365) {
|
||||
CDZoneTableTable* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>();
|
||||
auto* zoneTable = CDClientManager::Instance().GetTable<CDZoneTableTable>();
|
||||
const auto zoneID = Game::zoneManager->GetZoneID();
|
||||
const CDZoneTable* zoneData = zoneTable->Query(zoneID.GetMapID());
|
||||
auto zoneData = zoneTable->Query(zoneID.GetMapID());
|
||||
|
||||
if (zoneData != nullptr) {
|
||||
if (zoneData) {
|
||||
int zoneScriptID = zoneData->scriptID;
|
||||
CDScriptComponent zoneScriptData = scriptCompTable->GetByID(zoneScriptID);
|
||||
|
||||
ScriptComponent* comp = new ScriptComponent(this, zoneScriptData.script_name, true);
|
||||
m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPT, comp));
|
||||
auto zoneScriptData = scriptCompTable->GetByID(zoneScriptID);
|
||||
if (zoneScriptData) {
|
||||
ScriptComponent* comp = new ScriptComponent(this, zoneScriptData->script_name, true);
|
||||
m_Components.insert(std::make_pair(eReplicaComponentType::SCRIPT, comp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,17 +536,17 @@ void Entity::Initialize() {
|
||||
m_Components.insert(std::make_pair(eReplicaComponentType::QUICK_BUILD, comp));
|
||||
|
||||
CDRebuildComponentTable* rebCompTable = CDClientManager::Instance().GetTable<CDRebuildComponentTable>();
|
||||
std::vector<CDRebuildComponent> rebCompData = rebCompTable->Query([=](CDRebuildComponent entry) { return (entry.id == rebuildComponentID); });
|
||||
auto rebCompData = rebCompTable->Get(rebuildComponentID);
|
||||
|
||||
if (rebCompData.size() > 0) {
|
||||
comp->SetResetTime(rebCompData[0].reset_time);
|
||||
comp->SetCompleteTime(rebCompData[0].complete_time);
|
||||
comp->SetTakeImagination(rebCompData[0].take_imagination);
|
||||
comp->SetInterruptible(rebCompData[0].interruptible);
|
||||
comp->SetSelfActivator(rebCompData[0].self_activator);
|
||||
comp->SetActivityId(rebCompData[0].activityID);
|
||||
comp->SetPostImaginationCost(rebCompData[0].post_imagination_cost);
|
||||
comp->SetTimeBeforeSmash(rebCompData[0].time_before_smash);
|
||||
if (rebCompData) {
|
||||
comp->SetResetTime(rebCompData->reset_time);
|
||||
comp->SetCompleteTime(rebCompData->complete_time);
|
||||
comp->SetTakeImagination(rebCompData->take_imagination);
|
||||
comp->SetInterruptible(rebCompData->interruptible);
|
||||
comp->SetSelfActivator(rebCompData->self_activator);
|
||||
comp->SetActivityId(rebCompData->activityID);
|
||||
comp->SetPostImaginationCost(rebCompData->post_imagination_cost);
|
||||
comp->SetTimeBeforeSmash(rebCompData->time_before_smash);
|
||||
|
||||
const auto rebuildResetTime = GetVar<float>(u"rebuild_reset_time");
|
||||
|
||||
@@ -566,7 +563,6 @@ void Entity::Initialize() {
|
||||
|
||||
if (activityID > 0) {
|
||||
comp->SetActivityId(activityID);
|
||||
Loot::CacheMatrix(activityID);
|
||||
}
|
||||
|
||||
const auto compTime = GetVar<float>(u"compTime");
|
||||
@@ -585,9 +581,6 @@ void Entity::Initialize() {
|
||||
if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::VENDOR) > 0)) {
|
||||
VendorComponent* comp = new VendorComponent(this);
|
||||
m_Components.insert(std::make_pair(eReplicaComponentType::VENDOR, comp));
|
||||
} else if ((compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::DONATION_VENDOR, -1) != -1)) {
|
||||
DonationVendorComponent* comp = new DonationVendorComponent(this);
|
||||
m_Components.insert(std::make_pair(eReplicaComponentType::DONATION_VENDOR, comp));
|
||||
}
|
||||
|
||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY_VENDOR, -1) != -1) {
|
||||
@@ -1022,60 +1015,57 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
||||
*/
|
||||
|
||||
bool destroyableSerialized = false;
|
||||
bool bIsInitialUpdate = packetType == eReplicaPacketType::CONSTRUCTION;
|
||||
bool bIsInitialUpdate = false;
|
||||
if (packetType == eReplicaPacketType::CONSTRUCTION) bIsInitialUpdate = true;
|
||||
unsigned int flags = 0;
|
||||
|
||||
PossessableComponent* possessableComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::POSSESSABLE, possessableComponent)) {
|
||||
possessableComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
possessableComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
ModuleAssemblyComponent* moduleAssemblyComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::MODULE_ASSEMBLY, moduleAssemblyComponent)) {
|
||||
moduleAssemblyComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
moduleAssemblyComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
ControllablePhysicsComponent* controllablePhysicsComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS, controllablePhysicsComponent)) {
|
||||
controllablePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
controllablePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
SimplePhysicsComponent* simplePhysicsComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::SIMPLE_PHYSICS, simplePhysicsComponent)) {
|
||||
simplePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
simplePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
RigidbodyPhantomPhysicsComponent* rigidbodyPhantomPhysics;
|
||||
if (TryGetComponent(eReplicaComponentType::RIGID_BODY_PHANTOM_PHYSICS, rigidbodyPhantomPhysics)) {
|
||||
rigidbodyPhantomPhysics->Serialize(outBitStream, bIsInitialUpdate);
|
||||
rigidbodyPhantomPhysics->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
VehiclePhysicsComponent* vehiclePhysicsComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::VEHICLE_PHYSICS, vehiclePhysicsComponent)) {
|
||||
vehiclePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
vehiclePhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
PhantomPhysicsComponent* phantomPhysicsComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::PHANTOM_PHYSICS, phantomPhysicsComponent)) {
|
||||
phantomPhysicsComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
phantomPhysicsComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
SoundTriggerComponent* soundTriggerComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::SOUND_TRIGGER, soundTriggerComponent)) {
|
||||
soundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
}
|
||||
|
||||
RacingSoundTriggerComponent* racingSoundTriggerComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::RACING_SOUND_TRIGGER, racingSoundTriggerComponent)) {
|
||||
racingSoundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
soundTriggerComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
BuffComponent* buffComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::BUFF, buffComponent)) {
|
||||
buffComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
buffComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
|
||||
DestroyableComponent* destroyableComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent)) {
|
||||
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
destroyableSerialized = true;
|
||||
}
|
||||
@@ -1083,7 +1073,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
||||
if (HasComponent(eReplicaComponentType::COLLECTIBLE)) {
|
||||
DestroyableComponent* destroyableComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) {
|
||||
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
destroyableSerialized = true;
|
||||
outBitStream->Write(m_CollectibleID); // Collectable component
|
||||
@@ -1091,7 +1081,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
||||
|
||||
PetComponent* petComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::PET, petComponent)) {
|
||||
petComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
petComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
CharacterComponent* characterComponent;
|
||||
@@ -1099,7 +1089,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
||||
|
||||
PossessorComponent* possessorComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::POSSESSOR, possessorComponent)) {
|
||||
possessorComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
possessorComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
} else {
|
||||
// Should never happen, but just to be safe
|
||||
outBitStream->Write0();
|
||||
@@ -1107,7 +1097,7 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
||||
|
||||
LevelProgressionComponent* levelProgressionComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::LEVEL_PROGRESSION, levelProgressionComponent)) {
|
||||
levelProgressionComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
levelProgressionComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
} else {
|
||||
// Should never happen, but just to be safe
|
||||
outBitStream->Write0();
|
||||
@@ -1115,13 +1105,13 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
||||
|
||||
PlayerForcedMovementComponent* playerForcedMovementComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::PLAYER_FORCED_MOVEMENT, playerForcedMovementComponent)) {
|
||||
playerForcedMovementComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
playerForcedMovementComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
} else {
|
||||
// Should never happen, but just to be safe
|
||||
outBitStream->Write0();
|
||||
}
|
||||
|
||||
characterComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
characterComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
if (HasComponent(eReplicaComponentType::ITEM)) {
|
||||
@@ -1130,93 +1120,88 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
||||
|
||||
InventoryComponent* inventoryComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::INVENTORY, inventoryComponent)) {
|
||||
inventoryComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
inventoryComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
ScriptComponent* scriptComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::SCRIPT, scriptComponent)) {
|
||||
scriptComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
scriptComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
SkillComponent* skillComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::SKILL, skillComponent)) {
|
||||
skillComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
skillComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
BaseCombatAIComponent* baseCombatAiComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::BASE_COMBAT_AI, baseCombatAiComponent)) {
|
||||
baseCombatAiComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
baseCombatAiComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
RebuildComponent* rebuildComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::QUICK_BUILD, rebuildComponent)) {
|
||||
DestroyableComponent* destroyableComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) {
|
||||
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
destroyableSerialized = true;
|
||||
rebuildComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
rebuildComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
MovingPlatformComponent* movingPlatformComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::MOVING_PLATFORM, movingPlatformComponent)) {
|
||||
movingPlatformComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
movingPlatformComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
SwitchComponent* switchComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::SWITCH, switchComponent)) {
|
||||
switchComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
switchComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
VendorComponent* vendorComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::VENDOR, vendorComponent)) {
|
||||
vendorComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
}
|
||||
|
||||
DonationVendorComponent* donationVendorComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::DONATION_VENDOR, donationVendorComponent)) {
|
||||
donationVendorComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
vendorComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
BouncerComponent* bouncerComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::BOUNCER, bouncerComponent)) {
|
||||
bouncerComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
bouncerComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
ScriptedActivityComponent* scriptedActivityComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::SCRIPTED_ACTIVITY, scriptedActivityComponent)) {
|
||||
scriptedActivityComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
scriptedActivityComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
ShootingGalleryComponent* shootingGalleryComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::SHOOTING_GALLERY, shootingGalleryComponent)) {
|
||||
shootingGalleryComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
shootingGalleryComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
RacingControlComponent* racingControlComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::RACING_CONTROL, racingControlComponent)) {
|
||||
racingControlComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
racingControlComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
LUPExhibitComponent* lupExhibitComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::LUP_EXHIBIT, lupExhibitComponent)) {
|
||||
lupExhibitComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
lupExhibitComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
ModelComponent* modelComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::MODEL, modelComponent)) {
|
||||
modelComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
modelComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
RenderComponent* renderComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::RENDER, renderComponent)) {
|
||||
renderComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
renderComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
|
||||
if (modelComponent) {
|
||||
DestroyableComponent* destroyableComponent;
|
||||
if (TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent) && !destroyableSerialized) {
|
||||
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate);
|
||||
destroyableComponent->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
destroyableSerialized = true;
|
||||
}
|
||||
}
|
||||
@@ -1231,6 +1216,10 @@ void Entity::WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType
|
||||
outBitStream->Write0();
|
||||
}
|
||||
|
||||
void Entity::ResetFlags() {
|
||||
// Unused
|
||||
}
|
||||
|
||||
void Entity::UpdateXMLDoc(tinyxml2::XMLDocument* doc) {
|
||||
//This function should only ever be called from within Character, meaning doc should always exist when this is called.
|
||||
//Naturally, we don't include any non-player components in this update function.
|
||||
@@ -1642,9 +1631,9 @@ void Entity::PickupItem(const LWOOBJID& objectID) {
|
||||
std::vector<CDObjectSkills> skills = skillsTable->Query([=](CDObjectSkills entry) {return (entry.objectTemplate == p.second.lot); });
|
||||
for (CDObjectSkills skill : skills) {
|
||||
CDSkillBehaviorTable* skillBehTable = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>();
|
||||
CDSkillBehavior behaviorData = skillBehTable->GetSkillByID(skill.skillID);
|
||||
|
||||
SkillComponent::HandleUnmanaged(behaviorData.behaviorID, GetObjectID());
|
||||
auto behaviorData = skillBehTable->GetSkillByID(skill.skillID);
|
||||
if (!behaviorData) continue;
|
||||
SkillComponent::HandleUnmanaged(behaviorData->behaviorID, GetObjectID());
|
||||
|
||||
auto* missionComponent = GetComponent<MissionComponent>();
|
||||
|
||||
|
||||
@@ -85,7 +85,6 @@ public:
|
||||
bool GetPlayerReadyForUpdates() const { return m_PlayerIsReadyForUpdates; }
|
||||
|
||||
bool GetIsGhostingCandidate() const;
|
||||
void SetIsGhostingCandidate(bool value) { m_IsGhostingCandidate = value; };
|
||||
|
||||
int8_t GetObservers() const;
|
||||
|
||||
@@ -174,6 +173,7 @@ public:
|
||||
|
||||
void WriteBaseReplicaData(RakNet::BitStream* outBitStream, eReplicaPacketType packetType);
|
||||
void WriteComponents(RakNet::BitStream* outBitStream, eReplicaPacketType packetType);
|
||||
void ResetFlags();
|
||||
void UpdateXMLDoc(tinyxml2::XMLDocument* doc);
|
||||
void Update(float deltaTime);
|
||||
|
||||
|
||||
@@ -298,16 +298,6 @@ std::vector<Entity*> EntityManager::GetEntitiesByLOT(const LOT& lot) const {
|
||||
return entities;
|
||||
}
|
||||
|
||||
std::vector<Entity*> EntityManager::GetEntitiesByProximity(NiPoint3 reference, float radius) const{
|
||||
std::vector<Entity*> entities = {};
|
||||
if (radius > 1000.0f) return entities;
|
||||
for (const auto& entity : m_Entities) {
|
||||
if (NiPoint3::Distance(reference, entity.second->GetPosition()) <= radius) entities.push_back(entity.second);
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
|
||||
|
||||
Entity* EntityManager::GetZoneControlEntity() const {
|
||||
return m_ZoneControlEntity;
|
||||
}
|
||||
@@ -593,6 +583,12 @@ bool EntityManager::GetGhostingEnabled() const {
|
||||
return m_GhostingEnabled;
|
||||
}
|
||||
|
||||
void EntityManager::ResetFlags() {
|
||||
for (const auto& e : m_Entities) {
|
||||
e.second->ResetFlags();
|
||||
}
|
||||
}
|
||||
|
||||
void EntityManager::ScheduleForKill(Entity* entity) {
|
||||
// Deactivate switches if they die
|
||||
if (!entity)
|
||||
|
||||
@@ -28,7 +28,6 @@ public:
|
||||
std::vector<Entity*> GetEntitiesInGroup(const std::string& group);
|
||||
std::vector<Entity*> GetEntitiesByComponent(eReplicaComponentType componentType) const;
|
||||
std::vector<Entity*> GetEntitiesByLOT(const LOT& lot) const;
|
||||
std::vector<Entity*> GetEntitiesByProximity(NiPoint3 reference, float radius) const;
|
||||
Entity* GetZoneControlEntity() const;
|
||||
|
||||
// Get spawn point entity by spawn name
|
||||
@@ -60,6 +59,8 @@ public:
|
||||
Entity* GetGhostCandidate(int32_t id);
|
||||
bool GetGhostingEnabled() const;
|
||||
|
||||
void ResetFlags();
|
||||
|
||||
void ScheduleForKill(Entity* entity);
|
||||
|
||||
void ScheduleForDeletion(LWOOBJID entity);
|
||||
|
||||
@@ -131,8 +131,8 @@ void Leaderboard::QueryToLdf(std::unique_ptr<sql::ResultSet>& rows) {
|
||||
// Time:1
|
||||
break;
|
||||
case Type::Donations:
|
||||
entry.push_back(new LDFData<int32_t>(u"Score", rows->getInt("primaryScore")));
|
||||
// Score:1
|
||||
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
|
||||
@@ -170,32 +170,32 @@ void Leaderboard::SetupLeaderboard(bool weekly, uint32_t resultStart, uint32_t r
|
||||
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
|
||||
(
|
||||
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)
|
||||
) 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";
|
||||
|
||||
@@ -277,15 +277,15 @@ std::string FormatInsert(const Leaderboard::Type& type, const Score& score, cons
|
||||
if (useUpdate) {
|
||||
insertStatement =
|
||||
R"QUERY(
|
||||
UPDATE leaderboard
|
||||
SET primaryScore = %f, secondaryScore = %f, tertiaryScore = %f,
|
||||
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,
|
||||
INSERT leaderboard SET
|
||||
primaryScore = %f, secondaryScore = %f, tertiaryScore = %f,
|
||||
character_id = ?, game_id = ?;
|
||||
)QUERY";
|
||||
}
|
||||
@@ -300,8 +300,9 @@ std::string FormatInsert(const Leaderboard::Type& type, const Score& score, cons
|
||||
|
||||
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 = ?;";
|
||||
|
||||
std::unique_ptr<sql::PreparedStatement> query(Database::CreatePreppedStmt("SELECT * FROM leaderboard WHERE character_id = ? AND game_id = ?;"));
|
||||
std::unique_ptr<sql::PreparedStatement> query(Database::CreatePreppedStmt(lookup));
|
||||
query->setInt(1, playerID);
|
||||
query->setInt(2, activityId);
|
||||
std::unique_ptr<sql::ResultSet> myScoreResult(query->executeQuery());
|
||||
@@ -336,7 +337,6 @@ void LeaderboardManager::SaveScore(const LWOOBJID& playerID, const GameID activi
|
||||
case Leaderboard::Type::UnusedLeaderboard4:
|
||||
case Leaderboard::Type::Donations: {
|
||||
oldScore.SetPrimaryScore(myScoreResult->getInt("primaryScore"));
|
||||
newScore.SetPrimaryScore(oldScore.GetPrimaryScore() + newScore.GetPrimaryScore());
|
||||
break;
|
||||
}
|
||||
case Leaderboard::Type::Racing: {
|
||||
@@ -382,7 +382,7 @@ void LeaderboardManager::SaveScore(const LWOOBJID& playerID, const GameID activi
|
||||
saveStatement->setInt(1, playerID);
|
||||
saveStatement->setInt(2, activityId);
|
||||
saveStatement->execute();
|
||||
|
||||
|
||||
// track wins separately
|
||||
if (leaderboardType == Leaderboard::Type::Racing && tertiaryScore != 0.0f) {
|
||||
std::unique_ptr<sql::PreparedStatement> winUpdate(Database::CreatePreppedStmt("UPDATE leaderboard SET numWins = numWins + 1 WHERE character_id = ? AND game_id = ?;"));
|
||||
|
||||
@@ -28,8 +28,6 @@
|
||||
#include "eRenameResponse.h"
|
||||
#include "eConnectionType.h"
|
||||
#include "eChatInternalMessageType.h"
|
||||
#include "BitStreamUtils.h"
|
||||
#include "CheatDetection.h"
|
||||
|
||||
UserManager* UserManager::m_Address = nullptr;
|
||||
|
||||
@@ -205,38 +203,40 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
|
||||
stmt->setUInt(1, u->GetAccountID());
|
||||
|
||||
sql::ResultSet* res = stmt->executeQuery();
|
||||
std::vector<Character*>& chars = u->GetCharacters();
|
||||
if (res->rowsCount() > 0) {
|
||||
std::vector<Character*>& chars = u->GetCharacters();
|
||||
|
||||
for (size_t i = 0; i < chars.size(); ++i) {
|
||||
if (chars[i]->GetEntity() == nullptr) // We don't have entity data to save
|
||||
{
|
||||
delete chars[i];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* skillComponent = chars[i]->GetEntity()->GetComponent<SkillComponent>();
|
||||
|
||||
if (skillComponent != nullptr) {
|
||||
skillComponent->Reset();
|
||||
}
|
||||
|
||||
Game::entityManager->DestroyEntity(chars[i]->GetEntity());
|
||||
|
||||
chars[i]->SaveXMLToDatabase();
|
||||
|
||||
chars[i]->GetEntity()->SetCharacter(nullptr);
|
||||
|
||||
for (size_t i = 0; i < chars.size(); ++i) {
|
||||
if (chars[i]->GetEntity() == nullptr) // We don't have entity data to save
|
||||
{
|
||||
delete chars[i];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* skillComponent = chars[i]->GetEntity()->GetComponent<SkillComponent>();
|
||||
chars.clear();
|
||||
|
||||
if (skillComponent != nullptr) {
|
||||
skillComponent->Reset();
|
||||
while (res->next()) {
|
||||
LWOOBJID objID = res->getUInt64(1);
|
||||
Character* character = new Character(uint32_t(objID), u);
|
||||
character->SetIsNewLogin();
|
||||
chars.push_back(character);
|
||||
}
|
||||
|
||||
Game::entityManager->DestroyEntity(chars[i]->GetEntity());
|
||||
|
||||
chars[i]->SaveXMLToDatabase();
|
||||
|
||||
chars[i]->GetEntity()->SetCharacter(nullptr);
|
||||
|
||||
delete chars[i];
|
||||
}
|
||||
|
||||
chars.clear();
|
||||
|
||||
while (res->next()) {
|
||||
LWOOBJID objID = res->getUInt64(1);
|
||||
Character* character = new Character(uint32_t(objID), u);
|
||||
character->SetIsNewLogin();
|
||||
chars.push_back(character);
|
||||
}
|
||||
|
||||
delete res;
|
||||
@@ -251,21 +251,21 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
|
||||
std::string name = PacketUtils::ReadString(8, packet, true);
|
||||
|
||||
uint32_t firstNameIndex = PacketUtils::ReadU32(74, packet);
|
||||
uint32_t middleNameIndex = PacketUtils::ReadU32(78, packet);
|
||||
uint32_t lastNameIndex = PacketUtils::ReadU32(82, packet);
|
||||
uint32_t firstNameIndex = PacketUtils::ReadPacketU32(74, packet);
|
||||
uint32_t middleNameIndex = PacketUtils::ReadPacketU32(78, packet);
|
||||
uint32_t lastNameIndex = PacketUtils::ReadPacketU32(82, packet);
|
||||
std::string predefinedName = GetPredefinedName(firstNameIndex, middleNameIndex, lastNameIndex);
|
||||
|
||||
uint32_t shirtColor = PacketUtils::ReadU32(95, packet);
|
||||
uint32_t shirtStyle = PacketUtils::ReadU32(99, packet);
|
||||
uint32_t pantsColor = PacketUtils::ReadU32(103, packet);
|
||||
uint32_t hairStyle = PacketUtils::ReadU32(107, packet);
|
||||
uint32_t hairColor = PacketUtils::ReadU32(111, packet);
|
||||
uint32_t lh = PacketUtils::ReadU32(115, packet);
|
||||
uint32_t rh = PacketUtils::ReadU32(119, packet);
|
||||
uint32_t eyebrows = PacketUtils::ReadU32(123, packet);
|
||||
uint32_t eyes = PacketUtils::ReadU32(127, packet);
|
||||
uint32_t mouth = PacketUtils::ReadU32(131, packet);
|
||||
uint32_t shirtColor = PacketUtils::ReadPacketU32(95, packet);
|
||||
uint32_t shirtStyle = PacketUtils::ReadPacketU32(99, packet);
|
||||
uint32_t pantsColor = PacketUtils::ReadPacketU32(103, packet);
|
||||
uint32_t hairStyle = PacketUtils::ReadPacketU32(107, packet);
|
||||
uint32_t hairColor = PacketUtils::ReadPacketU32(111, packet);
|
||||
uint32_t lh = PacketUtils::ReadPacketU32(115, packet);
|
||||
uint32_t rh = PacketUtils::ReadPacketU32(119, packet);
|
||||
uint32_t eyebrows = PacketUtils::ReadPacketU32(123, packet);
|
||||
uint32_t eyes = PacketUtils::ReadPacketU32(127, packet);
|
||||
uint32_t mouth = PacketUtils::ReadPacketU32(131, packet);
|
||||
|
||||
LOT shirtLOT = FindCharShirtID(shirtColor, shirtStyle);
|
||||
LOT pantsLOT = FindCharPantsID(pantsColor);
|
||||
@@ -387,19 +387,20 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
return;
|
||||
}
|
||||
|
||||
LWOOBJID objectID = PacketUtils::ReadS64(8, packet);
|
||||
LWOOBJID objectID = PacketUtils::ReadPacketS64(8, packet);
|
||||
uint32_t charID = static_cast<uint32_t>(objectID);
|
||||
|
||||
Game::logger->Log("UserManager", "Received char delete req for ID: %llu (%u)", objectID, charID);
|
||||
|
||||
bool hasCharacter = CheatDetection::VerifyLwoobjidIsSender(
|
||||
objectID,
|
||||
sysAddr,
|
||||
CheckType::User,
|
||||
"User %i tried to delete a character that it does not own!",
|
||||
u->GetAccountID());
|
||||
//Check if this user has this character:
|
||||
bool hasCharacter = false;
|
||||
std::vector<Character*>& characters = u->GetCharacters();
|
||||
for (size_t i = 0; i < characters.size(); ++i) {
|
||||
if (characters[i]->GetID() == charID) { hasCharacter = true; }
|
||||
}
|
||||
|
||||
if (!hasCharacter) {
|
||||
Game::logger->Log("UserManager", "User %i tried to delete a character that it does not own!", u->GetAccountID());
|
||||
WorldPackets::SendCharacterDeleteResponse(sysAddr, false);
|
||||
} else {
|
||||
Game::logger->Log("UserManager", "Deleting character %i", charID);
|
||||
@@ -422,7 +423,7 @@ void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
stmt->execute();
|
||||
delete stmt;
|
||||
CBITSTREAM;
|
||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION);
|
||||
PacketUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION);
|
||||
bitStream.Write(objectID);
|
||||
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||
}
|
||||
@@ -482,7 +483,7 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
return;
|
||||
}
|
||||
|
||||
LWOOBJID objectID = PacketUtils::ReadS64(8, packet);
|
||||
LWOOBJID objectID = PacketUtils::ReadPacketS64(8, packet);
|
||||
GeneralUtils::ClearBit(objectID, eObjectBits::CHARACTER);
|
||||
GeneralUtils::ClearBit(objectID, eObjectBits::PERSISTENT);
|
||||
|
||||
@@ -494,24 +495,16 @@ void UserManager::RenameCharacter(const SystemAddress& sysAddr, Packet* packet)
|
||||
Character* character = nullptr;
|
||||
|
||||
//Check if this user has this character:
|
||||
bool ownsCharacter = CheatDetection::VerifyLwoobjidIsSender(
|
||||
objectID,
|
||||
sysAddr,
|
||||
CheckType::User,
|
||||
"User %i tried to rename a character that it does not own!",
|
||||
u->GetAccountID());
|
||||
bool hasCharacter = false;
|
||||
std::vector<Character*>& characters = u->GetCharacters();
|
||||
for (size_t i = 0; i < characters.size(); ++i) {
|
||||
if (characters[i]->GetID() == charID) { hasCharacter = true; character = characters[i]; }
|
||||
}
|
||||
|
||||
std::find_if(u->GetCharacters().begin(), u->GetCharacters().end(), [&](Character* c) {
|
||||
if (c->GetID() == charID) {
|
||||
character = c;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
if (!ownsCharacter || !character) {
|
||||
if (!hasCharacter || !character) {
|
||||
Game::logger->Log("UserManager", "User %i tried to rename a character that it does not own!", u->GetAccountID());
|
||||
WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::UNKNOWN_ERROR);
|
||||
} else if (ownsCharacter && character) {
|
||||
} else if (hasCharacter && character) {
|
||||
if (newName == character->GetName()) {
|
||||
WorldPackets::SendCharacterRenameResponse(sysAddr, eRenameResponse::NAME_UNAVAILABLE);
|
||||
return;
|
||||
|
||||
@@ -20,114 +20,134 @@ void AreaOfEffectBehavior::Handle(BehaviorContext* context, RakNet::BitStream* b
|
||||
return;
|
||||
}
|
||||
|
||||
if (this->m_useTargetPosition && branch.target == LWOOBJID_EMPTY) return;
|
||||
|
||||
if (targetCount == 0){
|
||||
PlayFx(u"miss", context->originator);
|
||||
return;
|
||||
}
|
||||
|
||||
if (targetCount > this->m_maxTargets) {
|
||||
Game::logger->Log("AreaOfEffectBehavior", "Serialized size is greater than max targets! Size: %i, Max: %i", targetCount, this->m_maxTargets);
|
||||
return;
|
||||
}
|
||||
|
||||
auto caster = context->caster;
|
||||
if (this->m_useTargetAsCaster) context->caster = branch.target;
|
||||
|
||||
std::vector<LWOOBJID> targets;
|
||||
|
||||
targets.reserve(targetCount);
|
||||
|
||||
for (auto i = 0u; i < targetCount; ++i) {
|
||||
LWOOBJID target{};
|
||||
|
||||
if (!bitStream->Read(target)) {
|
||||
Game::logger->Log("AreaOfEffectBehavior", "failed to read in target %i from bitStream, aborting target Handle!", i);
|
||||
return;
|
||||
};
|
||||
|
||||
targets.push_back(target);
|
||||
}
|
||||
|
||||
for (auto target : targets) {
|
||||
branch.target = target;
|
||||
|
||||
this->m_action->Handle(context, bitStream, branch);
|
||||
}
|
||||
context->caster = caster;
|
||||
PlayFx(u"cast", context->originator);
|
||||
}
|
||||
|
||||
void AreaOfEffectBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
|
||||
auto* caster = Game::entityManager->GetEntity(context->caster);
|
||||
if (!caster) return;
|
||||
auto* self = Game::entityManager->GetEntity(context->caster);
|
||||
if (self == nullptr) {
|
||||
Game::logger->Log("AreaOfEffectBehavior", "Invalid self for (%llu)!", context->originator);
|
||||
|
||||
// determine the position we are casting the AOE from
|
||||
auto reference = branch.isProjectile ? branch.referencePosition : caster->GetPosition();
|
||||
if (this->m_useTargetPosition) {
|
||||
if (branch.target == LWOOBJID_EMPTY) return;
|
||||
auto branchTarget = Game::entityManager->GetEntity(branch.target);
|
||||
if (branchTarget) reference = branchTarget->GetPosition();
|
||||
return;
|
||||
}
|
||||
|
||||
reference += this->m_offset;
|
||||
auto reference = branch.isProjectile ? branch.referencePosition : self->GetPosition();
|
||||
|
||||
std::vector<Entity*> targets {};
|
||||
targets = Game::entityManager->GetEntitiesByProximity(reference, this->m_radius);
|
||||
context->FilterTargets(targets, this->m_ignoreFactionList, this->m_includeFactionList, this->m_targetSelf, this->m_targetEnemy, this->m_targetFriend, this->m_targetTeam);
|
||||
std::vector<Entity*> targets;
|
||||
|
||||
auto* presetTarget = Game::entityManager->GetEntity(branch.target);
|
||||
|
||||
if (presetTarget != nullptr) {
|
||||
if (this->m_radius * this->m_radius >= Vector3::DistanceSquared(reference, presetTarget->GetPosition())) {
|
||||
targets.push_back(presetTarget);
|
||||
}
|
||||
}
|
||||
|
||||
int32_t includeFaction = m_includeFaction;
|
||||
|
||||
if (self->GetLOT() == 14466) // TODO: Fix edge case
|
||||
{
|
||||
includeFaction = 1;
|
||||
}
|
||||
|
||||
// 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)) {
|
||||
auto* entity = Game::entityManager->GetEntity(validTarget);
|
||||
|
||||
if (entity == nullptr) {
|
||||
Game::logger->Log("AreaOfEffectBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (std::find(targets.begin(), targets.end(), entity) != targets.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
||||
|
||||
if (destroyableComponent == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (destroyableComponent->HasFaction(m_ignoreFaction)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto distance = Vector3::DistanceSquared(reference, entity->GetPosition());
|
||||
|
||||
if (this->m_radius * this->m_radius >= distance && (this->m_maxTargets == 0 || targets.size() < this->m_maxTargets)) {
|
||||
targets.push_back(entity);
|
||||
}
|
||||
}
|
||||
|
||||
// sort by distance
|
||||
std::sort(targets.begin(), targets.end(), [reference](Entity* a, Entity* b) {
|
||||
const auto aDistance = NiPoint3::Distance(a->GetPosition(), reference);
|
||||
const auto bDistance = NiPoint3::Distance(b->GetPosition(), reference);
|
||||
return aDistance < bDistance;
|
||||
}
|
||||
);
|
||||
const auto aDistance = Vector3::DistanceSquared(a->GetPosition(), reference);
|
||||
const auto bDistance = Vector3::DistanceSquared(b->GetPosition(), reference);
|
||||
|
||||
// resize if we have more than max targets allows
|
||||
if (targets.size() > this->m_maxTargets) targets.resize(this->m_maxTargets);
|
||||
return aDistance > bDistance;
|
||||
});
|
||||
|
||||
bitStream->Write<uint32_t>(targets.size());
|
||||
const uint32_t size = targets.size();
|
||||
|
||||
if (targets.size() == 0) {
|
||||
PlayFx(u"miss", context->originator);
|
||||
bitStream->Write(size);
|
||||
|
||||
if (size == 0) {
|
||||
return;
|
||||
} else {
|
||||
context->foundTarget = true;
|
||||
// write all the targets to the bitstream
|
||||
for (auto* target : targets) {
|
||||
bitStream->Write(target->GetObjectID());
|
||||
}
|
||||
}
|
||||
|
||||
// then cast all the actions
|
||||
for (auto* target : targets) {
|
||||
branch.target = target->GetObjectID();
|
||||
this->m_action->Calculate(context, bitStream, branch);
|
||||
}
|
||||
PlayFx(u"cast", context->originator);
|
||||
context->foundTarget = true;
|
||||
|
||||
for (auto* target : targets) {
|
||||
bitStream->Write(target->GetObjectID());
|
||||
|
||||
PlayFx(u"cast", context->originator, target->GetObjectID());
|
||||
}
|
||||
|
||||
for (auto* target : targets) {
|
||||
branch.target = target->GetObjectID();
|
||||
|
||||
this->m_action->Calculate(context, bitStream, branch);
|
||||
}
|
||||
}
|
||||
|
||||
void AreaOfEffectBehavior::Load() {
|
||||
this->m_action = GetAction("action"); // required
|
||||
this->m_radius = GetFloat("radius", 0.0f); // required
|
||||
this->m_maxTargets = GetInt("max targets", 100);
|
||||
if (this->m_maxTargets == 0) this->m_maxTargets = 100;
|
||||
this->m_useTargetPosition = GetBoolean("use_target_position", false);
|
||||
this->m_useTargetAsCaster = GetBoolean("use_target_as_caster", false);
|
||||
this->m_offset = NiPoint3(
|
||||
GetFloat("offset_x", 0.0f),
|
||||
GetFloat("offset_y", 0.0f),
|
||||
GetFloat("offset_z", 0.0f)
|
||||
);
|
||||
this->m_action = GetAction("action");
|
||||
|
||||
// params after this are needed for filter targets
|
||||
const auto parameters = GetParameterNames();
|
||||
for (const auto& parameter : parameters) {
|
||||
if (parameter.first.rfind("include_faction", 0) == 0) {
|
||||
this->m_includeFactionList.push_front(parameter.second);
|
||||
} else if (parameter.first.rfind("ignore_faction", 0) == 0) {
|
||||
this->m_ignoreFactionList.push_front(parameter.second);
|
||||
}
|
||||
}
|
||||
this->m_targetSelf = GetBoolean("target_self", false);
|
||||
this->m_targetEnemy = GetBoolean("target_enemy", false);
|
||||
this->m_targetFriend = GetBoolean("target_friend", false);
|
||||
this->m_targetTeam = GetBoolean("target_team", false);
|
||||
this->m_radius = GetFloat("radius");
|
||||
|
||||
this->m_maxTargets = GetInt("max targets");
|
||||
|
||||
this->m_ignoreFaction = GetInt("ignore_faction");
|
||||
|
||||
this->m_includeFaction = GetInt("include_faction");
|
||||
|
||||
this->m_TargetSelf = GetInt("target_self");
|
||||
|
||||
this->m_targetEnemy = GetInt("target_enemy");
|
||||
|
||||
this->m_targetFriend = GetInt("target_friend");
|
||||
}
|
||||
|
||||
@@ -1,26 +1,34 @@
|
||||
#pragma once
|
||||
#include "Behavior.h"
|
||||
#include <forward_list>
|
||||
|
||||
class AreaOfEffectBehavior final : public Behavior
|
||||
{
|
||||
public:
|
||||
explicit AreaOfEffectBehavior(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 Load() override;
|
||||
private:
|
||||
Behavior* m_action;
|
||||
uint32_t m_maxTargets;
|
||||
float m_radius;
|
||||
bool m_useTargetPosition;
|
||||
bool m_useTargetAsCaster;
|
||||
NiPoint3 m_offset;
|
||||
|
||||
std::forward_list<int32_t> m_ignoreFactionList {};
|
||||
std::forward_list<int32_t> m_includeFactionList {};
|
||||
bool m_targetSelf;
|
||||
bool m_targetEnemy;
|
||||
bool m_targetFriend;
|
||||
bool m_targetTeam;
|
||||
uint32_t m_maxTargets;
|
||||
|
||||
float m_radius;
|
||||
|
||||
int32_t m_ignoreFaction;
|
||||
|
||||
int32_t m_includeFaction;
|
||||
|
||||
int32_t m_TargetSelf;
|
||||
|
||||
int32_t m_targetEnemy;
|
||||
|
||||
int32_t m_targetFriend;
|
||||
|
||||
/*
|
||||
* Inherited
|
||||
*/
|
||||
explicit AreaOfEffectBehavior(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 Load() override;
|
||||
};
|
||||
|
||||
@@ -175,7 +175,7 @@ Behavior* Behavior::CreateBehavior(const uint32_t behaviorId) {
|
||||
case BehaviorTemplates::BEHAVIOR_SPEED:
|
||||
behavior = new SpeedBehavior(behaviorId);
|
||||
break;
|
||||
case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION:
|
||||
case BehaviorTemplates::BEHAVIOR_DARK_INSPIRATION:
|
||||
behavior = new DarkInspirationBehavior(behaviorId);
|
||||
break;
|
||||
case BehaviorTemplates::BEHAVIOR_LOOT_BUFF:
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "Game.h"
|
||||
#include "dLogger.h"
|
||||
#include "dServer.h"
|
||||
#include "BitStreamUtils.h"
|
||||
#include "PacketUtils.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "PhantomPhysicsComponent.h"
|
||||
#include "RebuildComponent.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
#include "TeamManager.h"
|
||||
#include "eConnectionType.h"
|
||||
|
||||
BehaviorSyncEntry::BehaviorSyncEntry() {
|
||||
@@ -254,7 +253,7 @@ bool BehaviorContext::CalculateUpdate(const float deltaTime) {
|
||||
// Write message
|
||||
RakNet::BitStream message;
|
||||
|
||||
BitStreamUtils::WriteHeader(message, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
|
||||
PacketUtils::WriteHeader(message, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
|
||||
message.Write(this->originator);
|
||||
echo.Serialize(&message);
|
||||
|
||||
@@ -308,123 +307,46 @@ void BehaviorContext::Reset() {
|
||||
this->scheduledUpdates.clear();
|
||||
}
|
||||
|
||||
void BehaviorContext::FilterTargets(std::vector<Entity*>& targets, std::forward_list<int32_t>& ignoreFactionList, std::forward_list<int32_t>& includeFactionList, bool targetSelf, bool targetEnemy, bool targetFriend, bool targetTeam) const {
|
||||
std::vector<LWOOBJID> BehaviorContext::GetValidTargets(int32_t ignoreFaction, int32_t includeFaction, bool targetSelf, bool targetEnemy, bool targetFriend) const {
|
||||
auto* entity = Game::entityManager->GetEntity(this->caster);
|
||||
|
||||
// if we aren't targeting anything, then clear the targets vector
|
||||
if (!targetSelf && !targetEnemy && !targetFriend && !targetTeam && ignoreFactionList.empty() && includeFactionList.empty()) {
|
||||
targets.clear();
|
||||
return;
|
||||
std::vector<LWOOBJID> targets;
|
||||
|
||||
if (entity == nullptr) {
|
||||
Game::logger->Log("BehaviorContext", "Invalid entity for (%llu)!", this->originator);
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
// if the caster is not there, return empty targets list
|
||||
auto* caster = Game::entityManager->GetEntity(this->caster);
|
||||
if (!caster) {
|
||||
Game::logger->LogDebug("BehaviorContext", "Invalid caster for (%llu)!", this->originator);
|
||||
targets.clear();
|
||||
return;
|
||||
if (!ignoreFaction && !includeFaction) {
|
||||
for (auto entry : entity->GetTargetsInPhantom()) {
|
||||
auto* instance = Game::entityManager->GetEntity(entry);
|
||||
|
||||
if (instance == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
targets.push_back(entry);
|
||||
}
|
||||
}
|
||||
|
||||
auto index = targets.begin();
|
||||
while (index != targets.end()) {
|
||||
auto candidate = *index;
|
||||
|
||||
// make sure we don't have a nullptr
|
||||
if (!candidate) {
|
||||
index = targets.erase(index);
|
||||
continue;
|
||||
if (ignoreFaction || includeFaction || (!entity->HasComponent(eReplicaComponentType::PHANTOM_PHYSICS) && targets.empty())) {
|
||||
DestroyableComponent* destroyableComponent;
|
||||
if (!entity->TryGetComponent(eReplicaComponentType::DESTROYABLE, destroyableComponent)) {
|
||||
return targets;
|
||||
}
|
||||
|
||||
// handle targeting the caster
|
||||
if (candidate == caster){
|
||||
// if we aren't targeting self, erase, otherise increment and continue
|
||||
if (!targetSelf) index = targets.erase(index);
|
||||
else index++;
|
||||
continue;
|
||||
}
|
||||
auto entities = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS);
|
||||
for (auto* candidate : entities) {
|
||||
const auto id = candidate->GetObjectID();
|
||||
|
||||
// make sure that the entity is targetable
|
||||
if (!CheckTargetingRequirements(candidate)) {
|
||||
index = targets.erase(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
// get factions to check against
|
||||
// CheckTargetingRequirements checks for a destroyable component
|
||||
// but we check again because bounds check are necessary
|
||||
auto candidateDestroyableComponent = candidate->GetComponent<DestroyableComponent>();
|
||||
if (!candidateDestroyableComponent) {
|
||||
index = targets.erase(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if they are dead, then earse and continue
|
||||
if (candidateDestroyableComponent->GetIsDead()){
|
||||
index = targets.erase(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if their faction is explicitly included, increment and continue
|
||||
auto candidateFactions = candidateDestroyableComponent->GetFactionIDs();
|
||||
if (CheckFactionList(includeFactionList, candidateFactions)){
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if they are a team member
|
||||
if (targetTeam){
|
||||
auto* team = TeamManager::Instance()->GetTeam(this->caster);
|
||||
if (team){
|
||||
// if we find a team member keep it and continue to skip enemy checks
|
||||
if(std::find(team->members.begin(), team->members.end(), candidate->GetObjectID()) != team->members.end()){
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
if ((id != entity->GetObjectID() || targetSelf) && destroyableComponent->CheckValidity(id, ignoreFaction || includeFaction, targetEnemy, targetFriend)) {
|
||||
targets.push_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
// if the caster doesn't have a destroyable component, return an empty targets list
|
||||
auto* casterDestroyableComponent = caster->GetComponent<DestroyableComponent>();
|
||||
if (!casterDestroyableComponent) {
|
||||
targets.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// if we arent targeting a friend, and they are a friend OR
|
||||
// if we are not targeting enemies and they are an enemy OR.
|
||||
// if we are ignoring their faction is explicitly ignored
|
||||
// erase and continue
|
||||
auto isEnemy = casterDestroyableComponent->IsEnemy(candidate);
|
||||
if ((!targetFriend && !isEnemy) ||
|
||||
(!targetEnemy && isEnemy) ||
|
||||
CheckFactionList(ignoreFactionList, candidateFactions)) {
|
||||
index = targets.erase(index);
|
||||
continue;
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// some basic checks as well as the check that matters for this: if the quickbuild is complete
|
||||
bool BehaviorContext::CheckTargetingRequirements(const Entity* target) const {
|
||||
// if the target is a nullptr, then it's not valid
|
||||
if (!target) return false;
|
||||
|
||||
// ignore quickbuilds that aren't completed
|
||||
auto* targetQuickbuildComponent = target->GetComponent<RebuildComponent>();
|
||||
if (targetQuickbuildComponent && targetQuickbuildComponent->GetState() != eRebuildState::COMPLETED) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// returns true if any of the object factions are in the faction list
|
||||
bool BehaviorContext::CheckFactionList(std::forward_list<int32_t>& factionList, std::vector<int32_t>& objectsFactions) const {
|
||||
if (factionList.empty() || objectsFactions.empty()) return false;
|
||||
for (auto faction : factionList){
|
||||
if(std::find(objectsFactions.begin(), objectsFactions.end(), faction) != objectsFactions.end()) return true;
|
||||
}
|
||||
return false;
|
||||
return targets;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "GameMessages.h"
|
||||
|
||||
#include <vector>
|
||||
#include <forward_list>
|
||||
|
||||
class Behavior;
|
||||
|
||||
@@ -107,11 +106,7 @@ struct BehaviorContext
|
||||
|
||||
void Reset();
|
||||
|
||||
void FilterTargets(std::vector<Entity*>& targetsReference, std::forward_list<int32_t>& ignoreFaction, std::forward_list<int32_t>& includeFaction, const bool targetSelf = false, const bool targetEnemy = true, const bool targetFriend = false, const bool targetTeam = false) const;
|
||||
|
||||
bool CheckTargetingRequirements(const Entity* target) const;
|
||||
|
||||
bool CheckFactionList(std::forward_list<int32_t>& factionList, std::vector<int32_t>& objectsFactions) const;
|
||||
std::vector<LWOOBJID> GetValidTargets(int32_t ignoreFaction = 0, int32_t includeFaction = 0, const bool targetSelf = false, const bool targetEnemy = true, const bool targetFriend = false) const;
|
||||
|
||||
explicit BehaviorContext(LWOOBJID originator, bool calculation = false);
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#ifndef BEHAVIORSLOT_H
|
||||
#define BEHAVIORSLOT_H
|
||||
#include <cstdint>
|
||||
|
||||
enum class BehaviorSlot : int32_t {
|
||||
enum class BehaviorSlot
|
||||
{
|
||||
Invalid = -1,
|
||||
Primary,
|
||||
Offhand,
|
||||
|
||||
@@ -42,7 +42,8 @@ void OverTimeBehavior::Load() {
|
||||
// Since m_Action is a skillID and not a behavior, get is correlated behaviorID.
|
||||
|
||||
CDSkillBehaviorTable* skillTable = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>();
|
||||
m_ActionBehaviorId = skillTable->GetSkillByID(m_Action).behaviorID;
|
||||
auto skillData = skillTable->GetSkillByID(m_Action);
|
||||
if (skillData) m_ActionBehaviorId = skillData->behaviorID;
|
||||
|
||||
m_Delay = GetFloat("delay");
|
||||
m_NumIntervals = GetInt("num_intervals");
|
||||
|
||||
@@ -12,24 +12,16 @@
|
||||
#include <vector>
|
||||
|
||||
void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
|
||||
std::vector<Entity*> targets = {};
|
||||
if (this->m_targetEnemy && this->m_usePickedTarget && branch.target > 0) {
|
||||
this->m_action->Handle(context, bitStream, branch);
|
||||
|
||||
if (this->m_usePickedTarget && branch.target != LWOOBJID_EMPTY) {
|
||||
auto target = Game::entityManager->GetEntity(branch.target);
|
||||
if (!target) Game::logger->Log("TacArcBehavior", "target %llu is null", branch.target);
|
||||
else {
|
||||
targets.push_back(target);
|
||||
context->FilterTargets(targets, this->m_ignoreFactionList, this->m_includeFactionList, this->m_targetSelf, this->m_targetEnemy, this->m_targetFriend, this->m_targetTeam);
|
||||
if (!targets.empty()) {
|
||||
this->m_action->Handle(context, bitStream, branch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool hasTargets = false;
|
||||
if (!bitStream->Read(hasTargets)) {
|
||||
Game::logger->Log("TacArcBehavior", "Unable to read hasTargets from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
|
||||
bool hit = false;
|
||||
|
||||
if (!bitStream->Read(hit)) {
|
||||
Game::logger->Log("TacArcBehavior", "Unable to read hit from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -43,23 +35,26 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
|
||||
|
||||
if (blocked) {
|
||||
this->m_blockedAction->Handle(context, bitStream, branch);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasTargets) {
|
||||
if (hit) {
|
||||
uint32_t count = 0;
|
||||
|
||||
if (!bitStream->Read(count)) {
|
||||
Game::logger->Log("TacArcBehavior", "Unable to read count from bitStream, aborting Handle! %i", bitStream->GetNumberOfUnreadBits());
|
||||
return;
|
||||
};
|
||||
|
||||
if (count > m_maxTargets) {
|
||||
Game::logger->Log("TacArcBehavior", "Bitstream has too many targets Max:%i Recv:%i", this->m_maxTargets, count);
|
||||
return;
|
||||
if (count > m_maxTargets && m_maxTargets > 0) {
|
||||
count = m_maxTargets;
|
||||
}
|
||||
|
||||
for (auto i = 0u; i < count; i++) {
|
||||
std::vector<LWOOBJID> targets;
|
||||
|
||||
for (auto i = 0u; i < count; ++i) {
|
||||
LWOOBJID id{};
|
||||
|
||||
if (!bitStream->Read(id)) {
|
||||
@@ -67,19 +62,17 @@ void TacArcBehavior::Handle(BehaviorContext* context, RakNet::BitStream* bitStre
|
||||
return;
|
||||
};
|
||||
|
||||
if (id != LWOOBJID_EMPTY) {
|
||||
auto* canidate = Game::entityManager->GetEntity(id);
|
||||
if (canidate) targets.push_back(canidate);
|
||||
} else {
|
||||
Game::logger->Log("TacArcBehavior", "Bitstream has LWOOBJID_EMPTY as a target!");
|
||||
}
|
||||
targets.push_back(id);
|
||||
}
|
||||
|
||||
for (auto target : targets) {
|
||||
branch.target = target->GetObjectID();
|
||||
branch.target = target;
|
||||
|
||||
this->m_action->Handle(context, bitStream, branch);
|
||||
}
|
||||
} else this->m_missAction->Handle(context, bitStream, branch);
|
||||
} else {
|
||||
this->m_missAction->Handle(context, bitStream, branch);
|
||||
}
|
||||
}
|
||||
|
||||
void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) {
|
||||
@@ -89,15 +82,23 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<Entity*> targets = {};
|
||||
if (this->m_usePickedTarget && branch.target != LWOOBJID_EMPTY) {
|
||||
auto target = Game::entityManager->GetEntity(branch.target);
|
||||
targets.push_back(target);
|
||||
context->FilterTargets(targets, this->m_ignoreFactionList, this->m_includeFactionList, this->m_targetSelf, this->m_targetEnemy, this->m_targetFriend, this->m_targetTeam);
|
||||
if (!targets.empty()) {
|
||||
this->m_action->Handle(context, bitStream, branch);
|
||||
const auto* destroyableComponent = self->GetComponent<DestroyableComponent>();
|
||||
|
||||
if ((this->m_usePickedTarget || context->clientInitalized) && branch.target > 0) {
|
||||
const auto* target = Game::entityManager->GetEntity(branch.target);
|
||||
|
||||
if (target == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the game is specific about who to target, check that
|
||||
if (destroyableComponent == nullptr || ((!m_targetFriend && !m_targetEnemy
|
||||
|| m_targetFriend && destroyableComponent->IsFriend(target)
|
||||
|| m_targetEnemy && destroyableComponent->IsEnemy(target)))) {
|
||||
this->m_action->Calculate(context, bitStream, branch);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto* combatAi = self->GetComponent<BaseCombatAIComponent>();
|
||||
@@ -106,25 +107,50 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
|
||||
|
||||
auto reference = self->GetPosition(); //+ m_offset;
|
||||
|
||||
targets.clear();
|
||||
std::vector<Entity*> targets;
|
||||
|
||||
std::vector<Entity*> validTargets = Game::entityManager->GetEntitiesByProximity(reference, this->m_maxRange);
|
||||
std::vector<LWOOBJID> validTargets;
|
||||
|
||||
// filter all valid targets, based on whether we target enemies or friends
|
||||
context->FilterTargets(validTargets, this->m_ignoreFactionList, this->m_includeFactionList, this->m_targetSelf, this->m_targetEnemy, this->m_targetFriend, this->m_targetTeam);
|
||||
if (combatAi != nullptr) {
|
||||
if (combatAi->GetTarget() != LWOOBJID_EMPTY) {
|
||||
validTargets.push_back(combatAi->GetTarget());
|
||||
}
|
||||
}
|
||||
|
||||
// Find all valid targets, based on whether we target enemies or friends
|
||||
for (const auto& contextTarget : context->GetValidTargets()) {
|
||||
if (destroyableComponent != nullptr) {
|
||||
const auto* targetEntity = Game::entityManager->GetEntity(contextTarget);
|
||||
|
||||
if (m_targetEnemy && destroyableComponent->IsEnemy(targetEntity)
|
||||
|| m_targetFriend && destroyableComponent->IsFriend(targetEntity)) {
|
||||
validTargets.push_back(contextTarget);
|
||||
}
|
||||
} else {
|
||||
validTargets.push_back(contextTarget);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto validTarget : validTargets) {
|
||||
if (targets.size() >= this->m_maxTargets) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (std::find(targets.begin(), targets.end(), validTarget) != targets.end()) {
|
||||
auto* entity = Game::entityManager->GetEntity(validTarget);
|
||||
|
||||
if (entity == nullptr) {
|
||||
Game::logger->Log("TacArcBehavior", "Invalid target (%llu) for (%llu)!", validTarget, context->originator);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (validTarget->GetIsDead()) continue;
|
||||
if (std::find(targets.begin(), targets.end(), entity) != targets.end()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto otherPosition = validTarget->GetPosition();
|
||||
if (entity->GetIsDead()) continue;
|
||||
|
||||
const auto otherPosition = entity->GetPosition();
|
||||
|
||||
const auto heightDifference = std::abs(otherPosition.y - casterPosition.y);
|
||||
|
||||
@@ -154,8 +180,8 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
|
||||
|
||||
const float degreeAngle = std::abs(Vector3::Angle(forward, normalized) * (180 / 3.14) - 180);
|
||||
|
||||
if (distance >= this->m_minRange && this->m_maxRange >= distance && degreeAngle <= 2 * this->m_angle) {
|
||||
targets.push_back(validTarget);
|
||||
if (distance >= this->m_minDistance && this->m_maxDistance >= distance && degreeAngle <= 2 * this->m_angle) {
|
||||
targets.push_back(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,48 +228,43 @@ void TacArcBehavior::Calculate(BehaviorContext* context, RakNet::BitStream* bitS
|
||||
}
|
||||
|
||||
void TacArcBehavior::Load() {
|
||||
this->m_maxRange = GetFloat("max range");
|
||||
this->m_height = GetFloat("height", 2.2f);
|
||||
this->m_distanceWeight = GetFloat("distance_weight", 0.0f);
|
||||
this->m_angleWeight = GetFloat("angle_weight", 0.0f);
|
||||
this->m_angle = GetFloat("angle", 45.0f);
|
||||
this->m_minRange = GetFloat("min range", 0.0f);
|
||||
this->m_offset = NiPoint3(
|
||||
GetFloat("offset_x", 0.0f),
|
||||
GetFloat("offset_y", 0.0f),
|
||||
GetFloat("offset_z", 0.0f)
|
||||
);
|
||||
this->m_method = GetInt("method", 1);
|
||||
this->m_upperBound = GetFloat("upper_bound", 4.4f);
|
||||
this->m_lowerBound = GetFloat("lower_bound", 0.4f);
|
||||
this->m_usePickedTarget = GetBoolean("use_picked_target", false);
|
||||
this->m_useTargetPostion = GetBoolean("use_target_position", false);
|
||||
this->m_checkEnv = GetBoolean("check_env", false);
|
||||
this->m_useAttackPriority = GetBoolean("use_attack_priority", false);
|
||||
this->m_usePickedTarget = GetBoolean("use_picked_target");
|
||||
|
||||
this->m_action = GetAction("action");
|
||||
|
||||
this->m_missAction = GetAction("miss action");
|
||||
|
||||
this->m_checkEnv = GetBoolean("check_env");
|
||||
|
||||
this->m_blockedAction = GetAction("blocked action");
|
||||
|
||||
this->m_maxTargets = GetInt("max targets", 100);
|
||||
if (this->m_maxTargets == 0) this->m_maxTargets = 100;
|
||||
this->m_minDistance = GetFloat("min range");
|
||||
|
||||
this->m_farHeight = GetFloat("far_height", 5.0f);
|
||||
this->m_farWidth = GetFloat("far_width", 5.0f);
|
||||
this->m_nearHeight = GetFloat("near_height", 5.0f);
|
||||
this->m_nearWidth = GetFloat("near_width", 5.0f);
|
||||
this->m_maxDistance = GetFloat("max range");
|
||||
|
||||
// params after this are needed for filter targets
|
||||
const auto parameters = GetParameterNames();
|
||||
for (const auto& parameter : parameters) {
|
||||
if (parameter.first.rfind("include_faction", 0) == 0) {
|
||||
this->m_includeFactionList.push_front(parameter.second);
|
||||
} else if (parameter.first.rfind("ignore_faction", 0) == 0) {
|
||||
this->m_ignoreFactionList.push_front(parameter.second);
|
||||
}
|
||||
}
|
||||
this->m_targetSelf = GetBoolean("target_caster", false);
|
||||
this->m_targetEnemy = GetBoolean("target_enemy", false);
|
||||
this->m_targetFriend = GetBoolean("target_friend", false);
|
||||
this->m_targetTeam = GetBoolean("target_team", false);
|
||||
this->m_maxTargets = GetInt("max targets");
|
||||
|
||||
this->m_targetEnemy = GetBoolean("target_enemy");
|
||||
|
||||
this->m_targetFriend = GetBoolean("target_friend");
|
||||
|
||||
this->m_targetTeam = GetBoolean("target_team");
|
||||
|
||||
this->m_angle = GetFloat("angle");
|
||||
|
||||
this->m_upperBound = GetFloat("upper_bound");
|
||||
|
||||
this->m_lowerBound = GetFloat("lower_bound");
|
||||
|
||||
this->m_farHeight = GetFloat("far_height");
|
||||
|
||||
this->m_farWidth = GetFloat("far_width");
|
||||
|
||||
this->m_method = GetInt("method");
|
||||
|
||||
this->m_offset = {
|
||||
GetFloat("offset_x"),
|
||||
GetFloat("offset_y"),
|
||||
GetFloat("offset_z")
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,42 +2,56 @@
|
||||
#include "Behavior.h"
|
||||
#include "dCommonVars.h"
|
||||
#include "NiPoint3.h"
|
||||
#include <forward_list>
|
||||
|
||||
class TacArcBehavior final : public Behavior {
|
||||
class TacArcBehavior final : public Behavior
|
||||
{
|
||||
public:
|
||||
explicit TacArcBehavior(const uint32_t behavior_id) : Behavior(behavior_id) {}
|
||||
void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
|
||||
void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
|
||||
void Load() override;
|
||||
private:
|
||||
float m_maxRange;
|
||||
float m_height;
|
||||
float m_distanceWeight;
|
||||
float m_angleWeight;
|
||||
float m_angle;
|
||||
float m_minRange;
|
||||
NiPoint3 m_offset;
|
||||
uint32_t m_method;
|
||||
float m_upperBound;
|
||||
float m_lowerBound;
|
||||
bool m_usePickedTarget;
|
||||
bool m_useTargetPostion;
|
||||
bool m_checkEnv;
|
||||
bool m_useAttackPriority;
|
||||
Behavior* m_action;
|
||||
Behavior* m_missAction;
|
||||
Behavior* m_blockedAction;
|
||||
uint32_t m_maxTargets;
|
||||
float m_farHeight;
|
||||
float m_farWidth;
|
||||
float m_nearHeight;
|
||||
float m_nearWidth;
|
||||
|
||||
std::forward_list<int32_t> m_ignoreFactionList {};
|
||||
std::forward_list<int32_t> m_includeFactionList {};
|
||||
bool m_targetSelf;
|
||||
Behavior* m_action;
|
||||
|
||||
bool m_checkEnv;
|
||||
|
||||
Behavior* m_missAction;
|
||||
|
||||
Behavior* m_blockedAction;
|
||||
|
||||
float m_minDistance;
|
||||
|
||||
float m_maxDistance;
|
||||
|
||||
uint32_t m_maxTargets;
|
||||
|
||||
bool m_targetEnemy;
|
||||
|
||||
bool m_targetFriend;
|
||||
|
||||
bool m_targetTeam;
|
||||
|
||||
float m_angle;
|
||||
|
||||
float m_upperBound;
|
||||
|
||||
float m_lowerBound;
|
||||
|
||||
float m_farHeight;
|
||||
|
||||
float m_farWidth;
|
||||
|
||||
uint32_t m_method;
|
||||
|
||||
NiPoint3 m_offset;
|
||||
|
||||
/*
|
||||
* Inherited
|
||||
*/
|
||||
|
||||
explicit TacArcBehavior(const uint32_t behavior_id) : Behavior(behavior_id) {
|
||||
}
|
||||
|
||||
void Handle(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
|
||||
|
||||
void Calculate(BehaviorContext* context, RakNet::BitStream* bitStream, BehaviorBranchContext branch) override;
|
||||
|
||||
void Load() override;
|
||||
};
|
||||
|
||||
@@ -318,7 +318,7 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) {
|
||||
// Speed towards start position
|
||||
if (m_MovementAI != nullptr) {
|
||||
m_MovementAI->SetHaltDistance(0);
|
||||
m_MovementAI->SetMaxSpeed(m_PursuitSpeed);
|
||||
m_MovementAI->SetSpeed(m_PursuitSpeed);
|
||||
m_MovementAI->SetDestination(m_StartPosition);
|
||||
}
|
||||
|
||||
@@ -382,6 +382,8 @@ void BaseCombatAIComponent::CalculateCombat(const float deltaTime) {
|
||||
}
|
||||
|
||||
LWOOBJID BaseCombatAIComponent::FindTarget() {
|
||||
//const auto reference = m_MovementAI == nullptr ? m_StartPosition : m_MovementAI->ApproximateLocation();
|
||||
|
||||
NiPoint3 reference = m_StartPosition;
|
||||
|
||||
if (m_MovementAI) reference = m_MovementAI->ApproximateLocation();
|
||||
@@ -520,7 +522,7 @@ bool BaseCombatAIComponent::IsMech() {
|
||||
}
|
||||
|
||||
|
||||
void BaseCombatAIComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void BaseCombatAIComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
outBitStream->Write(m_DirtyStateOrTarget || bIsInitialUpdate);
|
||||
if (m_DirtyStateOrTarget || bIsInitialUpdate) {
|
||||
outBitStream->Write(uint32_t(m_State));
|
||||
@@ -658,17 +660,17 @@ void BaseCombatAIComponent::Wander() {
|
||||
destination.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(destination);
|
||||
}
|
||||
|
||||
if (Vector3::DistanceSquared(destination, m_MovementAI->GetParent()->GetPosition()) < 2 * 2) {
|
||||
if (Vector3::DistanceSquared(destination, m_MovementAI->GetCurrentPosition()) < 2 * 2) {
|
||||
m_MovementAI->Stop();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_MovementAI->SetMaxSpeed(m_TetherSpeed);
|
||||
m_MovementAI->SetSpeed(m_TetherSpeed);
|
||||
|
||||
m_MovementAI->SetDestination(destination);
|
||||
|
||||
m_Timer += (m_MovementAI->GetParent()->GetPosition().x - destination.x) / m_TetherSpeed;
|
||||
m_Timer += (m_MovementAI->GetCurrentPosition().x - destination.x) / m_TetherSpeed;
|
||||
}
|
||||
|
||||
void BaseCombatAIComponent::OnAggro() {
|
||||
@@ -683,21 +685,21 @@ void BaseCombatAIComponent::OnAggro() {
|
||||
m_MovementAI->SetHaltDistance(m_AttackRadius);
|
||||
|
||||
NiPoint3 targetPos = target->GetPosition();
|
||||
NiPoint3 currentPos = m_MovementAI->GetParent()->GetPosition();
|
||||
NiPoint3 currentPos = m_MovementAI->GetCurrentPosition();
|
||||
|
||||
// If the player's position is within range, attack
|
||||
if (Vector3::DistanceSquared(currentPos, targetPos) <= m_AttackRadius * m_AttackRadius) {
|
||||
m_MovementAI->Stop();
|
||||
} else if (Vector3::DistanceSquared(m_StartPosition, targetPos) > m_HardTetherRadius * m_HardTetherRadius) //Return to spawn if we're too far
|
||||
{
|
||||
m_MovementAI->SetMaxSpeed(m_PursuitSpeed);
|
||||
m_MovementAI->SetSpeed(m_PursuitSpeed);
|
||||
|
||||
m_MovementAI->SetDestination(m_StartPosition);
|
||||
} else //Chase the player's new position
|
||||
{
|
||||
if (IsMech() && Vector3::DistanceSquared(targetPos, currentPos) > m_AttackRadius * m_AttackRadius * 3 * 3) return;
|
||||
|
||||
m_MovementAI->SetMaxSpeed(m_PursuitSpeed);
|
||||
m_MovementAI->SetSpeed(m_PursuitSpeed);
|
||||
|
||||
m_MovementAI->SetDestination(targetPos);
|
||||
|
||||
@@ -723,7 +725,7 @@ void BaseCombatAIComponent::OnTether() {
|
||||
m_MovementAI->Stop();
|
||||
} else if (Vector3::DistanceSquared(m_StartPosition, targetPos) > m_HardTetherRadius * m_HardTetherRadius) //Return to spawn if we're too far
|
||||
{
|
||||
m_MovementAI->SetMaxSpeed(m_PursuitSpeed);
|
||||
m_MovementAI->SetSpeed(m_PursuitSpeed);
|
||||
|
||||
m_MovementAI->SetDestination(m_StartPosition);
|
||||
|
||||
@@ -731,7 +733,7 @@ void BaseCombatAIComponent::OnTether() {
|
||||
} else {
|
||||
if (IsMech() && Vector3::DistanceSquared(targetPos, currentPos) > m_AttackRadius * m_AttackRadius * 3 * 3) return;
|
||||
|
||||
m_MovementAI->SetMaxSpeed(m_PursuitSpeed);
|
||||
m_MovementAI->SetSpeed(m_PursuitSpeed);
|
||||
|
||||
m_MovementAI->SetDestination(targetPos);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
~BaseCombatAIComponent() override;
|
||||
|
||||
void Update(float deltaTime) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
|
||||
/**
|
||||
* Get the current behavioral state of the enemy
|
||||
|
||||
@@ -22,7 +22,7 @@ BouncerComponent::BouncerComponent(Entity* parent) : Component(parent) {
|
||||
BouncerComponent::~BouncerComponent() {
|
||||
}
|
||||
|
||||
void BouncerComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void BouncerComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
outBitStream->Write(m_PetEnabled);
|
||||
if (m_PetEnabled) {
|
||||
outBitStream->Write(m_PetBouncerEnabled);
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
BouncerComponent(Entity* parentEntity);
|
||||
~BouncerComponent() override;
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
|
||||
Entity* GetParentEntity() const;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ BuffComponent::BuffComponent(Entity* parent) : Component(parent) {
|
||||
BuffComponent::~BuffComponent() {
|
||||
}
|
||||
|
||||
void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void BuffComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
if (!bIsInitialUpdate) return;
|
||||
if (m_Buffs.empty()) {
|
||||
outBitStream->Write0();
|
||||
@@ -104,7 +104,12 @@ void BuffComponent::ApplyBuff(const int32_t id, const float duration, const LWOO
|
||||
if (parameter.name == "overtime") {
|
||||
auto* behaviorTemplateTable = CDClientManager::Instance().GetTable<CDSkillBehaviorTable>();
|
||||
|
||||
behaviorID = behaviorTemplateTable->GetSkillByID(parameter.values[0]).behaviorID;
|
||||
auto skillInfo = behaviorTemplateTable->GetSkillByID(parameter.values[0]);
|
||||
if (skillInfo) {
|
||||
behaviorID = skillInfo->behaviorID;
|
||||
} else {
|
||||
Game::logger->Log("BuffComponent", "Failed to find skill info for skill ID %d!", parameter.values[0]);
|
||||
}
|
||||
stacks = static_cast<int32_t>(parameter.values[1]);
|
||||
tick = parameter.values[2];
|
||||
const auto unknown2 = parameter.values[3]; // Always 0
|
||||
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
|
||||
void UpdateXml(tinyxml2::XMLDocument* doc) override;
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
|
||||
void Update(float deltaTime) override;
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp"
|
||||
"Component.cpp"
|
||||
"ControllablePhysicsComponent.cpp"
|
||||
"DestroyableComponent.cpp"
|
||||
"DonationVendorComponent.cpp"
|
||||
"InventoryComponent.cpp"
|
||||
"LevelProgressionComponent.cpp"
|
||||
"LUPExhibitComponent.cpp"
|
||||
@@ -18,7 +17,6 @@ set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp"
|
||||
"MovingPlatformComponent.cpp"
|
||||
"PetComponent.cpp"
|
||||
"PhantomPhysicsComponent.cpp"
|
||||
"PhysicsComponent.cpp"
|
||||
"PlayerForcedMovementComponent.cpp"
|
||||
"PossessableComponent.cpp"
|
||||
"PossessorComponent.cpp"
|
||||
@@ -32,7 +30,7 @@ set(DGAME_DCOMPONENTS_SOURCES "BaseCombatAIComponent.cpp"
|
||||
"RebuildComponent.cpp"
|
||||
"RenderComponent.cpp"
|
||||
"RigidbodyPhantomPhysicsComponent.cpp"
|
||||
"MultiZoneEntranceComponent.cpp"
|
||||
"RocketLaunchLupComponent.cpp"
|
||||
"RocketLaunchpadControlComponent.cpp"
|
||||
"ScriptedActivityComponent.cpp"
|
||||
"ShootingGalleryComponent.cpp"
|
||||
|
||||
@@ -70,7 +70,7 @@ bool CharacterComponent::LandingAnimDisabled(int zoneID) {
|
||||
CharacterComponent::~CharacterComponent() {
|
||||
}
|
||||
|
||||
void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
|
||||
if (bIsInitialUpdate) {
|
||||
outBitStream->Write0();
|
||||
|
||||
@@ -70,7 +70,7 @@ public:
|
||||
void LoadFromXml(tinyxml2::XMLDocument* doc) override;
|
||||
void UpdateXml(tinyxml2::XMLDocument* doc) override;
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
|
||||
/**
|
||||
* Updates the rocket configuration using a LOT string separated by commas
|
||||
@@ -276,10 +276,6 @@ public:
|
||||
*/
|
||||
void UpdateClientMinimap(bool showFaction, std::string ventureVisionType) const;
|
||||
|
||||
void SetCurrentInteracting(LWOOBJID objectID) {m_CurrentInteracting = objectID;};
|
||||
|
||||
LWOOBJID GetCurrentInteracting() {return m_CurrentInteracting;};
|
||||
|
||||
/**
|
||||
* Character info regarding this character, including clothing styles, etc.
|
||||
*/
|
||||
@@ -564,8 +560,6 @@ private:
|
||||
* ID of the last rocket used
|
||||
*/
|
||||
LWOOBJID m_LastRocketItemID = LWOOBJID_EMPTY;
|
||||
|
||||
LWOOBJID m_CurrentInteracting = LWOOBJID_EMPTY;
|
||||
};
|
||||
|
||||
#endif // CHARACTERCOMPONENT_H
|
||||
|
||||
@@ -28,7 +28,3 @@ void Component::UpdateXml(tinyxml2::XMLDocument* doc) {
|
||||
void Component::LoadFromXml(tinyxml2::XMLDocument* doc) {
|
||||
|
||||
}
|
||||
|
||||
void Component::Serialize(RakNet::BitStream* outBitStream, bool isConstruction) {
|
||||
|
||||
}
|
||||
|
||||
@@ -43,8 +43,6 @@ public:
|
||||
*/
|
||||
virtual void LoadFromXml(tinyxml2::XMLDocument* doc);
|
||||
|
||||
virtual void Serialize(RakNet::BitStream* outBitStream, bool isConstruction);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
|
||||
@@ -15,12 +15,15 @@
|
||||
#include "LevelProgressionComponent.h"
|
||||
#include "eStateChangeType.h"
|
||||
|
||||
ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : PhysicsComponent(entity) {
|
||||
ControllablePhysicsComponent::ControllablePhysicsComponent(Entity* entity) : Component(entity) {
|
||||
m_Position = {};
|
||||
m_Rotation = NiQuaternion::IDENTITY;
|
||||
m_Velocity = {};
|
||||
m_AngularVelocity = {};
|
||||
m_InJetpackMode = false;
|
||||
m_IsOnGround = true;
|
||||
m_IsOnRail = false;
|
||||
m_DirtyPosition = true;
|
||||
m_DirtyVelocity = true;
|
||||
m_DirtyAngularVelocity = true;
|
||||
m_dpEntity = nullptr;
|
||||
@@ -71,7 +74,7 @@ void ControllablePhysicsComponent::Update(float deltaTime) {
|
||||
|
||||
}
|
||||
|
||||
void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void ControllablePhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
//If this is a creation, then we assume the position is dirty, even when it isn't.
|
||||
//This is because new clients will still need to receive the position.
|
||||
//if (bIsInitialUpdate) m_DirtyPosition = true;
|
||||
@@ -178,6 +181,12 @@ void ControllablePhysicsComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
|
||||
m_DirtyPosition = true;
|
||||
}
|
||||
|
||||
void ControllablePhysicsComponent::ResetFlags() {
|
||||
m_DirtyAngularVelocity = false;
|
||||
m_DirtyPosition = false;
|
||||
m_DirtyVelocity = false;
|
||||
}
|
||||
|
||||
void ControllablePhysicsComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
|
||||
tinyxml2::XMLElement* character = doc->FirstChildElement("obj")->FirstChildElement("char");
|
||||
if (!character) {
|
||||
@@ -199,14 +208,26 @@ void ControllablePhysicsComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
|
||||
}
|
||||
|
||||
void ControllablePhysicsComponent::SetPosition(const NiPoint3& pos) {
|
||||
if (m_Static) return;
|
||||
PhysicsComponent::SetPosition(pos);
|
||||
if (m_Static) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Position.x = pos.x;
|
||||
m_Position.y = pos.y;
|
||||
m_Position.z = pos.z;
|
||||
m_DirtyPosition = true;
|
||||
|
||||
if (m_dpEntity) m_dpEntity->SetPosition(pos);
|
||||
}
|
||||
|
||||
void ControllablePhysicsComponent::SetRotation(const NiQuaternion& rot) {
|
||||
if (m_Static) return;
|
||||
PhysicsComponent::SetRotation(rot);
|
||||
if (m_Static) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Rotation = rot;
|
||||
m_DirtyPosition = true;
|
||||
|
||||
if (m_dpEntity) m_dpEntity->SetRotation(rot);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "NiPoint3.h"
|
||||
#include "NiQuaternion.h"
|
||||
#include "tinyxml2.h"
|
||||
#include "PhysicsComponent.h"
|
||||
#include "Component.h"
|
||||
#include "dpCollisionChecks.h"
|
||||
#include "PhantomPhysicsComponent.h"
|
||||
#include "eBubbleType.h"
|
||||
@@ -19,7 +19,7 @@ enum class eStateChangeType : uint32_t;
|
||||
/**
|
||||
* Handles the movement of controllable Entities, e.g. enemies and players
|
||||
*/
|
||||
class ControllablePhysicsComponent : public PhysicsComponent {
|
||||
class ControllablePhysicsComponent : public Component {
|
||||
public:
|
||||
static const eReplicaComponentType ComponentType = eReplicaComponentType::CONTROLLABLE_PHYSICS;
|
||||
|
||||
@@ -27,8 +27,9 @@ public:
|
||||
~ControllablePhysicsComponent() override;
|
||||
|
||||
void Update(float deltaTime) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
void LoadFromXml(tinyxml2::XMLDocument* doc) override;
|
||||
void ResetFlags();
|
||||
void UpdateXml(tinyxml2::XMLDocument* doc) override;
|
||||
|
||||
/**
|
||||
@@ -36,14 +37,26 @@ public:
|
||||
* If the entity is static, this is a no-op.
|
||||
* @param pos The position to set
|
||||
*/
|
||||
void SetPosition(const NiPoint3& pos) override;
|
||||
void SetPosition(const NiPoint3& pos);
|
||||
|
||||
/**
|
||||
* Returns the current position of the entity
|
||||
* @return The current position of the entity
|
||||
*/
|
||||
const NiPoint3& GetPosition() const { return m_Position; }
|
||||
|
||||
/**
|
||||
* Sets the rotation of this entity, ensures this change is serialized next tick. If the entity is static, this is
|
||||
* a no-op.
|
||||
* @param rot the rotation to set
|
||||
*/
|
||||
void SetRotation(const NiQuaternion& rot) override;
|
||||
void SetRotation(const NiQuaternion& rot);
|
||||
|
||||
/**
|
||||
* Returns the current rotation of this entity
|
||||
* @return the current rotation of this entity
|
||||
*/
|
||||
const NiQuaternion& GetRotation() const { return m_Rotation; }
|
||||
|
||||
/**
|
||||
* Sets the current velocity of this entity, ensures that this change is serialized next tick. If the entity is
|
||||
@@ -310,6 +323,21 @@ private:
|
||||
*/
|
||||
dpEntity* m_dpEntity;
|
||||
|
||||
/**
|
||||
* Whether or not the position is dirty, forcing a serialization update of the position
|
||||
*/
|
||||
bool m_DirtyPosition;
|
||||
|
||||
/**
|
||||
* The current position of the entity
|
||||
*/
|
||||
NiPoint3 m_Position;
|
||||
|
||||
/**
|
||||
* The current rotation of the entity
|
||||
*/
|
||||
NiQuaternion m_Rotation;
|
||||
|
||||
/**
|
||||
* Whether or not the velocity is dirty, forcing a serialization of the velocity
|
||||
*/
|
||||
|
||||
@@ -119,7 +119,7 @@ void DestroyableComponent::Reinitialize(LOT templateID) {
|
||||
}
|
||||
}
|
||||
|
||||
void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void DestroyableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags) {
|
||||
if (bIsInitialUpdate) {
|
||||
outBitStream->Write1(); // always write these on construction
|
||||
outBitStream->Write(m_ImmuneToBasicAttackCount);
|
||||
@@ -363,10 +363,9 @@ void DestroyableComponent::SetIsShielded(bool value) {
|
||||
|
||||
void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignoreChecks) {
|
||||
// Ignore factionID -1
|
||||
if (factionID == -1 && !ignoreChecks) return;
|
||||
|
||||
// if we already have that faction, don't add it again
|
||||
if (std::find(m_FactionIDs.begin(), m_FactionIDs.end(), factionID) != m_FactionIDs.end()) return;
|
||||
if (factionID == -1 && !ignoreChecks) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_FactionIDs.push_back(factionID);
|
||||
m_DirtyHealth = true;
|
||||
@@ -408,14 +407,6 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore
|
||||
}
|
||||
|
||||
bool DestroyableComponent::IsEnemy(const Entity* other) const {
|
||||
if (m_Parent->IsPlayer() && other->IsPlayer()){
|
||||
auto* thisCharacterComponent = m_Parent->GetComponent<CharacterComponent>();
|
||||
if (!thisCharacterComponent) return false;
|
||||
auto* otherCharacterComponent = other->GetComponent<CharacterComponent>();
|
||||
if (!otherCharacterComponent) return false;
|
||||
if (thisCharacterComponent->GetPvpEnabled() && otherCharacterComponent->GetPvpEnabled()) return true;
|
||||
return false;
|
||||
}
|
||||
const auto* otherDestroyableComponent = other->GetComponent<DestroyableComponent>();
|
||||
if (otherDestroyableComponent != nullptr) {
|
||||
for (const auto enemyFaction : m_EnemyFactionIDs) {
|
||||
@@ -494,6 +485,43 @@ Entity* DestroyableComponent::GetKiller() const {
|
||||
return Game::entityManager->GetEntity(m_KillerID);
|
||||
}
|
||||
|
||||
bool DestroyableComponent::CheckValidity(const LWOOBJID target, const bool ignoreFactions, const bool targetEnemy, const bool targetFriend) const {
|
||||
auto* targetEntity = Game::entityManager->GetEntity(target);
|
||||
|
||||
if (targetEntity == nullptr) {
|
||||
Game::logger->Log("DestroyableComponent", "Invalid entity for checking validity (%llu)!", target);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* targetDestroyable = targetEntity->GetComponent<DestroyableComponent>();
|
||||
|
||||
if (targetDestroyable == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto* targetQuickbuild = targetEntity->GetComponent<RebuildComponent>();
|
||||
|
||||
if (targetQuickbuild != nullptr) {
|
||||
const auto state = targetQuickbuild->GetState();
|
||||
|
||||
if (state != eRebuildState::COMPLETED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ignoreFactions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get if the target entity is an enemy and friend
|
||||
bool isEnemy = IsEnemy(targetEntity);
|
||||
bool isFriend = IsFriend(targetEntity);
|
||||
|
||||
// Return true if the target type matches what we are targeting
|
||||
return (isEnemy && targetEnemy) || (isFriend && targetFriend);
|
||||
}
|
||||
|
||||
|
||||
void DestroyableComponent::Heal(const uint32_t health) {
|
||||
auto current = static_cast<uint32_t>(GetHealth());
|
||||
const auto max = static_cast<uint32_t>(GetMaxHealth());
|
||||
@@ -735,18 +763,18 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
|
||||
|
||||
auto* member = Game::entityManager->GetEntity(specificOwner);
|
||||
|
||||
if (member) Loot::DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins());
|
||||
if (member) LootGenerator::Instance().DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins());
|
||||
} else {
|
||||
for (const auto memberId : team->members) { // Free for all
|
||||
auto* member = Game::entityManager->GetEntity(memberId);
|
||||
|
||||
if (member == nullptr) continue;
|
||||
|
||||
Loot::DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins());
|
||||
LootGenerator::Instance().DropLoot(member, m_Parent, lootMatrixId, GetMinCoins(), GetMaxCoins());
|
||||
}
|
||||
}
|
||||
} else { // drop loot for non team user
|
||||
Loot::DropLoot(owner, m_Parent, GetLootMatrixID(), GetMinCoins(), GetMaxCoins());
|
||||
LootGenerator::Instance().DropLoot(owner, m_Parent, GetLootMatrixID(), GetMinCoins(), GetMaxCoins());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -764,7 +792,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
|
||||
|
||||
coinsTotal -= coinsToLose;
|
||||
|
||||
Loot::DropLoot(m_Parent, m_Parent, -1, coinsToLose, coinsToLose);
|
||||
LootGenerator::Instance().DropLoot(m_Parent, m_Parent, -1, coinsToLose, coinsToLose);
|
||||
character->SetCoins(coinsTotal, eLootSourceType::PICKUP);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public:
|
||||
DestroyableComponent(Entity* parentEntity);
|
||||
~DestroyableComponent() override;
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags);
|
||||
void LoadFromXml(tinyxml2::XMLDocument* doc) override;
|
||||
void UpdateXml(tinyxml2::XMLDocument* doc) override;
|
||||
|
||||
@@ -371,6 +371,14 @@ public:
|
||||
*/
|
||||
Entity* GetKiller() const;
|
||||
|
||||
/**
|
||||
* Checks if the target ID is a valid enemy of this entity
|
||||
* @param target the target ID to check for
|
||||
* @param ignoreFactions whether or not check for the factions, e.g. just return true if the entity cannot be smashed
|
||||
* @return if the target ID is a valid enemy
|
||||
*/
|
||||
bool CheckValidity(LWOOBJID target, bool ignoreFactions = false, bool targetEnemy = true, bool targetFriend = false) const;
|
||||
|
||||
/**
|
||||
* Attempt to damage this entity, handles everything from health and armor to absorption, immunity and callbacks.
|
||||
* @param damage the damage to attempt to apply
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
#include "DonationVendorComponent.h"
|
||||
#include "Database.h"
|
||||
|
||||
DonationVendorComponent::DonationVendorComponent(Entity* parent) : VendorComponent(parent) {
|
||||
//LoadConfigData
|
||||
m_PercentComplete = 0.0;
|
||||
m_TotalDonated = 0;
|
||||
m_TotalRemaining = 0;
|
||||
|
||||
// custom attribute to calculate other values
|
||||
m_Goal = m_Parent->GetVar<int32_t>(u"donationGoal");
|
||||
if (m_Goal == 0) m_Goal = INT32_MAX;
|
||||
|
||||
// Default to the nexus tower jawbox activity and setup settings
|
||||
m_ActivityId = m_Parent->GetVar<uint32_t>(u"activityID");
|
||||
if ((m_ActivityId == 0) || (m_ActivityId == 117)) {
|
||||
m_ActivityId = 117;
|
||||
m_PercentComplete = 1.0;
|
||||
m_TotalDonated = INT32_MAX;
|
||||
m_TotalRemaining = 0;
|
||||
m_Goal = INT32_MAX;
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_ptr<sql::PreparedStatement> query(Database::CreatePreppedStmt("SELECT SUM(primaryScore) as donation_total FROM leaderboard WHERE game_id = ?;"));
|
||||
query->setInt(1, m_ActivityId);
|
||||
std::unique_ptr<sql::ResultSet> donation_total(query->executeQuery());
|
||||
if (donation_total->next()) m_TotalDonated = donation_total->getInt("donation_total");
|
||||
m_TotalRemaining = m_Goal - m_TotalDonated;
|
||||
m_PercentComplete = m_TotalDonated/static_cast<float>(m_Goal);
|
||||
}
|
||||
|
||||
void DonationVendorComponent::SubmitDonation(uint32_t count) {
|
||||
if (count <= 0 && ((m_TotalDonated + count) > 0)) return;
|
||||
m_TotalDonated += count;
|
||||
m_TotalRemaining = m_Goal - m_TotalDonated;
|
||||
m_PercentComplete = m_TotalDonated/static_cast<float>(m_Goal);
|
||||
m_DirtyDonationVendor = true;
|
||||
}
|
||||
|
||||
void DonationVendorComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
VendorComponent::Serialize(outBitStream, bIsInitialUpdate);
|
||||
outBitStream->Write(bIsInitialUpdate || m_DirtyDonationVendor);
|
||||
if (bIsInitialUpdate || m_DirtyDonationVendor) {
|
||||
outBitStream->Write(m_PercentComplete);
|
||||
outBitStream->Write(m_TotalDonated);
|
||||
outBitStream->Write(m_TotalRemaining);
|
||||
if (!bIsInitialUpdate) m_DirtyDonationVendor = false;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#ifndef __DONATIONVENDORCOMPONENT__H__
|
||||
#define __DONATIONVENDORCOMPONENT__H__
|
||||
|
||||
#include "VendorComponent.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
|
||||
class Entity;
|
||||
|
||||
class DonationVendorComponent final : public VendorComponent {
|
||||
public:
|
||||
inline static const eReplicaComponentType ComponentType = eReplicaComponentType::DONATION_VENDOR;
|
||||
DonationVendorComponent(Entity* parent);
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
uint32_t GetActivityID() {return m_ActivityId;};
|
||||
void SubmitDonation(uint32_t count);
|
||||
|
||||
private:
|
||||
bool m_DirtyDonationVendor = false;
|
||||
float m_PercentComplete = 0.0;
|
||||
int32_t m_TotalDonated = 0;
|
||||
int32_t m_TotalRemaining = 0;
|
||||
uint32_t m_ActivityId = 0;
|
||||
int32_t m_Goal = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif //!__DONATIONVENDORCOMPONENT__H__
|
||||
@@ -116,9 +116,6 @@ Inventory* InventoryComponent::GetInventory(const eInventoryType type) {
|
||||
case eInventoryType::VENDOR_BUYBACK:
|
||||
size = 27u;
|
||||
break;
|
||||
case eInventoryType::DONATION:
|
||||
size = 24u;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -712,7 +709,7 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument* document) {
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool bIsInitialUpdate) {
|
||||
void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool bIsInitialUpdate, unsigned& flags) {
|
||||
if (bIsInitialUpdate || m_Dirty) {
|
||||
outBitStream->Write(true);
|
||||
|
||||
@@ -770,6 +767,10 @@ void InventoryComponent::Serialize(RakNet::BitStream* outBitStream, const bool b
|
||||
outBitStream->Write(false);
|
||||
}
|
||||
|
||||
void InventoryComponent::ResetFlags() {
|
||||
m_Dirty = false;
|
||||
}
|
||||
|
||||
void InventoryComponent::Update(float deltaTime) {
|
||||
for (auto* set : m_Itemsets) {
|
||||
set->Update(deltaTime);
|
||||
@@ -932,8 +933,9 @@ void InventoryComponent::EquipScripts(Item* equippedItem) {
|
||||
int32_t scriptComponentID = compRegistryTable->GetByIDAndType(equippedItem->GetLot(), eReplicaComponentType::SCRIPT, -1);
|
||||
if (scriptComponentID > -1) {
|
||||
CDScriptComponentTable* scriptCompTable = CDClientManager::Instance().GetTable<CDScriptComponentTable>();
|
||||
CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID);
|
||||
auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name);
|
||||
auto scriptCompData = scriptCompTable->GetByID(scriptComponentID);
|
||||
if (!scriptCompData) return;
|
||||
auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData->script_name);
|
||||
if (!itemScript) {
|
||||
Game::logger->Log("InventoryComponent", "null script?");
|
||||
}
|
||||
@@ -947,8 +949,9 @@ void InventoryComponent::UnequipScripts(Item* unequippedItem) {
|
||||
int32_t scriptComponentID = compRegistryTable->GetByIDAndType(unequippedItem->GetLot(), eReplicaComponentType::SCRIPT, -1);
|
||||
if (scriptComponentID > -1) {
|
||||
CDScriptComponentTable* scriptCompTable = CDClientManager::Instance().GetTable<CDScriptComponentTable>();
|
||||
CDScriptComponent scriptCompData = scriptCompTable->GetByID(scriptComponentID);
|
||||
auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData.script_name);
|
||||
auto scriptCompData = scriptCompTable->GetByID(scriptComponentID);
|
||||
if (!scriptCompData) return;
|
||||
auto* itemScript = CppScripts::GetScript(m_Parent, scriptCompData->script_name);
|
||||
if (!itemScript) {
|
||||
Game::logger->Log("InventoryComponent", "null script?");
|
||||
}
|
||||
@@ -1158,7 +1161,19 @@ void InventoryComponent::AddItemSkills(const LOT lot) {
|
||||
|
||||
const auto skill = FindSkill(lot);
|
||||
|
||||
SetSkill(slot, skill);
|
||||
if (skill == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (index != m_Skills.end()) {
|
||||
const auto old = index->second;
|
||||
|
||||
GameMessages::SendRemoveSkill(m_Parent, old);
|
||||
}
|
||||
|
||||
GameMessages::SendAddSkill(m_Parent, skill, static_cast<int>(slot));
|
||||
|
||||
m_Skills.insert_or_assign(slot, skill);
|
||||
}
|
||||
|
||||
void InventoryComponent::RemoveItemSkills(const LOT lot) {
|
||||
@@ -1185,7 +1200,7 @@ void InventoryComponent::RemoveItemSkills(const LOT lot) {
|
||||
if (slot == BehaviorSlot::Primary) {
|
||||
m_Skills.insert_or_assign(BehaviorSlot::Primary, 1);
|
||||
|
||||
GameMessages::SendAddSkill(m_Parent, 1, BehaviorSlot::Primary);
|
||||
GameMessages::SendAddSkill(m_Parent, 1, static_cast<int>(BehaviorSlot::Primary));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1328,8 +1343,12 @@ std::vector<uint32_t> InventoryComponent::FindBuffs(Item* item, bool castOnEquip
|
||||
for (const auto& result : results) {
|
||||
if (result.castOnType == 1) {
|
||||
const auto entry = behaviors->GetSkillByID(result.skillID);
|
||||
if (!entry) {
|
||||
Game::logger->Log("InventoryComponent", "Buff %i not in database!", result.skillID);
|
||||
|
||||
if (entry.skillID == 0) {
|
||||
continue;
|
||||
}
|
||||
if (entry->skillID == 0) {
|
||||
Game::logger->Log("InventoryComponent", "Failed to find buff behavior for skill (%i)!", result.skillID);
|
||||
|
||||
continue;
|
||||
@@ -1340,7 +1359,7 @@ std::vector<uint32_t> InventoryComponent::FindBuffs(Item* item, bool castOnEquip
|
||||
}
|
||||
|
||||
// If item is not a proxy, add its buff to the added buffs.
|
||||
if (item->GetParent() == LWOOBJID_EMPTY) buffs.push_back(static_cast<uint32_t>(entry.behaviorID));
|
||||
if (item->GetParent() == LWOOBJID_EMPTY) buffs.push_back(static_cast<uint32_t>(entry->behaviorID));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1615,29 +1634,3 @@ void InventoryComponent::UpdatePetXml(tinyxml2::XMLDocument* document) {
|
||||
petInventoryElement->LinkEndChild(petElement);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool InventoryComponent::SetSkill(int32_t slot, uint32_t skillId){
|
||||
BehaviorSlot behaviorSlot = BehaviorSlot::Invalid;
|
||||
if (slot == 1 ) behaviorSlot = BehaviorSlot::Primary;
|
||||
else if (slot == 2 ) behaviorSlot = BehaviorSlot::Offhand;
|
||||
else if (slot == 3 ) behaviorSlot = BehaviorSlot::Neck;
|
||||
else if (slot == 4 ) behaviorSlot = BehaviorSlot::Head;
|
||||
else if (slot == 5 ) behaviorSlot = BehaviorSlot::Consumable;
|
||||
else return false;
|
||||
return SetSkill(behaviorSlot, skillId);
|
||||
}
|
||||
|
||||
bool InventoryComponent::SetSkill(BehaviorSlot slot, uint32_t skillId){
|
||||
if (skillId == 0) return false;
|
||||
const auto index = m_Skills.find(slot);
|
||||
if (index != m_Skills.end()) {
|
||||
const auto old = index->second;
|
||||
GameMessages::SendRemoveSkill(m_Parent, old);
|
||||
}
|
||||
|
||||
GameMessages::SendAddSkill(m_Parent, skillId, slot);
|
||||
m_Skills.insert_or_assign(slot, skillId);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -42,9 +42,10 @@ public:
|
||||
explicit InventoryComponent(Entity* parent, tinyxml2::XMLDocument* document = nullptr);
|
||||
|
||||
void Update(float deltaTime) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
void LoadXml(tinyxml2::XMLDocument* document);
|
||||
void UpdateXml(tinyxml2::XMLDocument* document) override;
|
||||
void ResetFlags();
|
||||
|
||||
/**
|
||||
* Returns an inventory of the specified type, if it exists
|
||||
@@ -367,11 +368,6 @@ public:
|
||||
*/
|
||||
void UnequipScripts(Item* unequippedItem);
|
||||
|
||||
std::map<BehaviorSlot, uint32_t> GetSkills(){ return m_Skills; };
|
||||
|
||||
bool SetSkill(int slot, uint32_t skillId);
|
||||
bool SetSkill(BehaviorSlot slot, uint32_t skillId);
|
||||
|
||||
~InventoryComponent() override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -38,7 +38,7 @@ void LUPExhibitComponent::NextExhibit() {
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
|
||||
void LUPExhibitComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void LUPExhibitComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags) {
|
||||
outBitStream->Write1(); // Dirty flag?
|
||||
outBitStream->Write(m_Exhibit);
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
LUPExhibitComponent(Entity* parent);
|
||||
~LUPExhibitComponent();
|
||||
void Update(float deltaTime) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, uint32_t& flags);
|
||||
|
||||
/**
|
||||
* After the timer runs out, this changes the currently exhibited LOT to the next one
|
||||
|
||||
@@ -37,7 +37,7 @@ void LevelProgressionComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
|
||||
m_CharacterVersion = static_cast<eCharacterVersion>(characterVersion);
|
||||
}
|
||||
|
||||
void LevelProgressionComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void LevelProgressionComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
outBitStream->Write(bIsInitialUpdate || m_DirtyLevelInfo);
|
||||
if (bIsInitialUpdate || m_DirtyLevelInfo) outBitStream->Write(m_Level);
|
||||
m_DirtyLevelInfo = false;
|
||||
|
||||
@@ -21,7 +21,7 @@ public:
|
||||
*/
|
||||
LevelProgressionComponent(Entity* parent);
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
|
||||
/**
|
||||
* Save data from this componennt to character XML
|
||||
|
||||
@@ -8,7 +8,7 @@ ModelComponent::ModelComponent(Entity* parent) : Component(parent) {
|
||||
m_userModelID = m_Parent->GetVarAs<LWOOBJID>(u"userModelID");
|
||||
}
|
||||
|
||||
void ModelComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void ModelComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
// ItemComponent Serialization. Pets do not get this serialization.
|
||||
if (!m_Parent->HasComponent(eReplicaComponentType::PET)) {
|
||||
outBitStream->Write1();
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
|
||||
ModelComponent(Entity* parent);
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
|
||||
/**
|
||||
* Returns the original position of the model
|
||||
|
||||
@@ -46,7 +46,7 @@ const std::u16string& ModuleAssemblyComponent::GetAssemblyPartsLOTs() const {
|
||||
return m_AssemblyPartsLOTs;
|
||||
}
|
||||
|
||||
void ModuleAssemblyComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void ModuleAssemblyComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
if (bIsInitialUpdate) {
|
||||
outBitStream->Write1();
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
ModuleAssemblyComponent(Entity* parent);
|
||||
~ModuleAssemblyComponent() override;
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
void Update(float deltaTime) override;
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,77 +10,85 @@
|
||||
#include "EntityManager.h"
|
||||
#include "SimplePhysicsComponent.h"
|
||||
#include "CDClientManager.h"
|
||||
#include "Game.h"
|
||||
#include "dZoneManager.h"
|
||||
|
||||
#include "CDComponentsRegistryTable.h"
|
||||
#include "CDPhysicsComponentTable.h"
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Cache of all lots and their respective speeds
|
||||
*/
|
||||
std::map<LOT, float> m_PhysicsSpeedCache;
|
||||
}
|
||||
std::map<LOT, float> MovementAIComponent::m_PhysicsSpeedCache = {};
|
||||
|
||||
MovementAIComponent::MovementAIComponent(Entity* parent, MovementAIInfo info) : Component(parent) {
|
||||
m_Info = info;
|
||||
m_AtFinalWaypoint = true;
|
||||
m_Info = std::move(info);
|
||||
m_Done = true;
|
||||
|
||||
m_BaseCombatAI = nullptr;
|
||||
|
||||
m_BaseCombatAI = m_Parent->GetComponent<BaseCombatAIComponent>();
|
||||
m_BaseCombatAI = reinterpret_cast<BaseCombatAIComponent*>(m_Parent->GetComponent(eReplicaComponentType::BASE_COMBAT_AI));
|
||||
|
||||
//Try and fix the insane values:
|
||||
if (m_Info.wanderRadius > 5.0f) m_Info.wanderRadius *= 0.5f;
|
||||
if (m_Info.wanderRadius > 5.0f) m_Info.wanderRadius = m_Info.wanderRadius * 0.5f;
|
||||
if (m_Info.wanderRadius > 8.0f) m_Info.wanderRadius = 8.0f;
|
||||
if (m_Info.wanderSpeed > 0.5f) m_Info.wanderSpeed *= 0.5f;
|
||||
if (m_Info.wanderSpeed > 0.5f) m_Info.wanderSpeed = m_Info.wanderSpeed * 0.5f;
|
||||
|
||||
m_BaseSpeed = GetBaseSpeed(m_Parent->GetLOT());
|
||||
|
||||
m_NextWaypoint = m_Parent->GetPosition();
|
||||
m_NextWaypoint = GetCurrentPosition();
|
||||
m_Acceleration = 0.4f;
|
||||
m_PullingToPoint = false;
|
||||
m_PullPoint = NiPoint3::ZERO;
|
||||
m_Interrupted = false;
|
||||
m_PullPoint = {};
|
||||
m_HaltDistance = 0;
|
||||
m_TimeToTravel = 0;
|
||||
m_TimeTravelled = 0;
|
||||
m_Timer = 0;
|
||||
m_CurrentSpeed = 0;
|
||||
m_MaxSpeed = 0;
|
||||
m_Speed = 0;
|
||||
m_TotalTime = 0;
|
||||
m_LockRotation = false;
|
||||
}
|
||||
|
||||
MovementAIComponent::~MovementAIComponent() = default;
|
||||
|
||||
void MovementAIComponent::Update(const float deltaTime) {
|
||||
if (m_PullingToPoint) {
|
||||
if (m_Interrupted) {
|
||||
const auto source = GetCurrentWaypoint();
|
||||
|
||||
const auto speed = deltaTime * 2.5f;
|
||||
|
||||
NiPoint3 velocity = (m_PullPoint - source) * speed;
|
||||
NiPoint3 velocity;
|
||||
|
||||
velocity.x = (m_PullPoint.x - source.x) * speed;
|
||||
velocity.y = (m_PullPoint.y - source.y) * speed;
|
||||
velocity.z = (m_PullPoint.z - source.z) * speed;
|
||||
|
||||
SetPosition(source + velocity);
|
||||
|
||||
if (Vector3::DistanceSquared(m_Parent->GetPosition(), m_PullPoint) < std::pow(2, 2)) {
|
||||
m_PullingToPoint = false;
|
||||
if (Vector3::DistanceSquared(GetCurrentPosition(), m_PullPoint) < 2 * 2) {
|
||||
m_Interrupted = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Are we done?
|
||||
if (AtFinalWaypoint()) return;
|
||||
if (AtFinalWaypoint()) // Are we done?
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_HaltDistance > 0) {
|
||||
// Prevent us from hugging the target
|
||||
if (Vector3::DistanceSquared(ApproximateLocation(), GetDestination()) < std::pow(m_HaltDistance, 2)) {
|
||||
if (Vector3::DistanceSquared(ApproximateLocation(), GetDestination()) < m_HaltDistance * m_HaltDistance) // Prevent us from hugging the target
|
||||
{
|
||||
Stop();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_TimeTravelled += deltaTime;
|
||||
if (m_TimeTravelled < m_TimeToTravel) return;
|
||||
m_TimeTravelled = 0.0f;
|
||||
if (m_Timer > 0) {
|
||||
m_Timer -= deltaTime;
|
||||
|
||||
if (m_Timer > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_Timer = 0;
|
||||
}
|
||||
|
||||
const auto source = GetCurrentWaypoint();
|
||||
|
||||
@@ -93,44 +101,48 @@ void MovementAIComponent::Update(const float deltaTime) {
|
||||
m_NextWaypoint = GetCurrentWaypoint();
|
||||
|
||||
if (m_NextWaypoint == source) {
|
||||
m_TimeToTravel = 0.0f;
|
||||
m_Timer = 0;
|
||||
|
||||
goto nextAction;
|
||||
}
|
||||
|
||||
if (m_CurrentSpeed < m_MaxSpeed) {
|
||||
if (m_CurrentSpeed < m_Speed) {
|
||||
m_CurrentSpeed += m_Acceleration;
|
||||
}
|
||||
|
||||
if (m_CurrentSpeed > m_MaxSpeed) {
|
||||
m_CurrentSpeed = m_MaxSpeed;
|
||||
if (m_CurrentSpeed > m_Speed) {
|
||||
m_CurrentSpeed = m_Speed;
|
||||
}
|
||||
|
||||
const auto speed = m_CurrentSpeed * m_BaseSpeed; // scale speed based on base speed
|
||||
const auto speed = m_CurrentSpeed * m_BaseSpeed;
|
||||
|
||||
const auto delta = m_NextWaypoint - source;
|
||||
|
||||
// Normalize the vector
|
||||
const auto length = delta.Length();
|
||||
const auto length = sqrtf(delta.x * delta.x + delta.y * delta.y + delta.z * delta.z);
|
||||
|
||||
if (length > 0) {
|
||||
velocity = (delta / length) * speed;
|
||||
velocity.x = (delta.x / length) * speed;
|
||||
velocity.y = (delta.y / length) * speed;
|
||||
velocity.z = (delta.z / length) * speed;
|
||||
}
|
||||
|
||||
// Calclute the time it will take to reach the next waypoint with the current speed
|
||||
m_TimeTravelled = 0.0f;
|
||||
m_TimeToTravel = length / speed;
|
||||
m_TotalTime = m_Timer = length / speed;
|
||||
|
||||
SetRotation(NiQuaternion::LookAt(source, m_NextWaypoint));
|
||||
} else {
|
||||
// Check if there are more waypoints in the queue, if so set our next destination to the next waypoint
|
||||
if (m_CurrentPath.empty()) {
|
||||
if (!m_Queue.empty()) {
|
||||
SetDestination(m_Queue.top());
|
||||
|
||||
m_Queue.pop();
|
||||
} else {
|
||||
// We have reached our final waypoint
|
||||
Stop();
|
||||
|
||||
return;
|
||||
}
|
||||
SetDestination(m_CurrentPath.top());
|
||||
|
||||
m_CurrentPath.pop();
|
||||
}
|
||||
|
||||
nextAction:
|
||||
@@ -145,7 +157,7 @@ const MovementAIInfo& MovementAIComponent::GetInfo() const {
|
||||
}
|
||||
|
||||
bool MovementAIComponent::AdvanceWaypointIndex() {
|
||||
if (m_PathIndex >= m_InterpolatedWaypoints.size()) {
|
||||
if (m_PathIndex >= m_CurrentPath.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -155,19 +167,37 @@ bool MovementAIComponent::AdvanceWaypointIndex() {
|
||||
}
|
||||
|
||||
NiPoint3 MovementAIComponent::GetCurrentWaypoint() const {
|
||||
return m_PathIndex >= m_InterpolatedWaypoints.size() ? m_Parent->GetPosition() : m_InterpolatedWaypoints[m_PathIndex];
|
||||
if (m_PathIndex >= m_CurrentPath.size()) {
|
||||
return GetCurrentPosition();
|
||||
}
|
||||
|
||||
return m_CurrentPath[m_PathIndex];
|
||||
}
|
||||
|
||||
NiPoint3 MovementAIComponent::GetNextWaypoint() const {
|
||||
return m_NextWaypoint;
|
||||
}
|
||||
|
||||
NiPoint3 MovementAIComponent::GetCurrentPosition() const {
|
||||
return m_Parent->GetPosition();
|
||||
}
|
||||
|
||||
NiPoint3 MovementAIComponent::ApproximateLocation() const {
|
||||
auto source = m_Parent->GetPosition();
|
||||
auto source = GetCurrentPosition();
|
||||
|
||||
if (AtFinalWaypoint()) return source;
|
||||
if (m_Done) {
|
||||
return source;
|
||||
}
|
||||
|
||||
auto destination = m_NextWaypoint;
|
||||
|
||||
auto percentageToWaypoint = m_TimeToTravel > 0 ? m_TimeTravelled / m_TimeToTravel : 0;
|
||||
auto factor = m_TotalTime > 0 ? (m_TotalTime - m_Timer) / m_TotalTime : 0;
|
||||
|
||||
auto approximation = source + ((destination - source) * percentageToWaypoint);
|
||||
auto x = source.x + factor * (destination.x - source.x);
|
||||
auto y = source.y + factor * (destination.y - source.y);
|
||||
auto z = source.z + factor * (destination.z - source.z);
|
||||
|
||||
NiPoint3 approximation = NiPoint3(x, y, z);
|
||||
|
||||
if (dpWorld::Instance().IsLoaded()) {
|
||||
approximation.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(approximation);
|
||||
@@ -196,20 +226,28 @@ bool MovementAIComponent::Warp(const NiPoint3& point) {
|
||||
return true;
|
||||
}
|
||||
|
||||
float MovementAIComponent::GetTimer() const {
|
||||
return m_Timer;
|
||||
}
|
||||
|
||||
bool MovementAIComponent::AtFinalWaypoint() const {
|
||||
return m_Done;
|
||||
}
|
||||
|
||||
void MovementAIComponent::Stop() {
|
||||
if (AtFinalWaypoint()) return;
|
||||
if (m_Done) {
|
||||
return;
|
||||
}
|
||||
|
||||
SetPosition(ApproximateLocation());
|
||||
|
||||
SetVelocity(NiPoint3::ZERO);
|
||||
|
||||
m_TimeToTravel = 0;
|
||||
m_TimeTravelled = 0;
|
||||
m_TotalTime = m_Timer = 0;
|
||||
|
||||
m_AtFinalWaypoint = true;
|
||||
m_Done = true;
|
||||
|
||||
m_InterpolatedWaypoints.clear();
|
||||
while (!m_CurrentPath.empty()) m_CurrentPath.pop();
|
||||
m_CurrentPath = {};
|
||||
|
||||
m_PathIndex = 0;
|
||||
|
||||
@@ -221,17 +259,20 @@ void MovementAIComponent::Stop() {
|
||||
void MovementAIComponent::PullToPoint(const NiPoint3& point) {
|
||||
Stop();
|
||||
|
||||
m_PullingToPoint = true;
|
||||
m_Interrupted = true;
|
||||
m_PullPoint = point;
|
||||
}
|
||||
|
||||
void MovementAIComponent::SetPath(std::vector<NiPoint3> path) {
|
||||
if (path.empty()) return;
|
||||
std::for_each(path.rbegin(), path.rend() - 1, [this](const NiPoint3& point) {
|
||||
this->m_CurrentPath.push(point);
|
||||
});
|
||||
std::reverse(path.begin(), path.end());
|
||||
|
||||
SetDestination(path.front());
|
||||
for (const auto& point : path) {
|
||||
m_Queue.push(point);
|
||||
}
|
||||
|
||||
SetDestination(m_Queue.top());
|
||||
|
||||
m_Queue.pop();
|
||||
}
|
||||
|
||||
float MovementAIComponent::GetBaseSpeed(LOT lot) {
|
||||
@@ -250,14 +291,26 @@ float MovementAIComponent::GetBaseSpeed(LOT lot) {
|
||||
|
||||
componentID = componentRegistryTable->GetByIDAndType(lot, eReplicaComponentType::CONTROLLABLE_PHYSICS, -1);
|
||||
|
||||
if (componentID == -1) {
|
||||
componentID = componentRegistryTable->GetByIDAndType(lot, eReplicaComponentType::SIMPLE_PHYSICS, -1);
|
||||
if (componentID != -1) {
|
||||
physicsComponent = physicsComponentTable->GetByID(componentID);
|
||||
|
||||
goto foundComponent;
|
||||
}
|
||||
|
||||
physicsComponent = physicsComponentTable->GetByID(componentID);
|
||||
componentID = componentRegistryTable->GetByIDAndType(lot, eReplicaComponentType::SIMPLE_PHYSICS, -1);
|
||||
|
||||
if (componentID != -1) {
|
||||
physicsComponent = physicsComponentTable->GetByID(componentID);
|
||||
|
||||
goto foundComponent;
|
||||
}
|
||||
|
||||
foundComponent:
|
||||
|
||||
// Client defaults speed to 10 and if the speed is also null in the table, it defaults to 10.
|
||||
float speed = physicsComponent != nullptr ? physicsComponent->speed : 10.0f;
|
||||
float speed = 10.0f;
|
||||
|
||||
if (physicsComponent) speed = physicsComponent->speed;
|
||||
|
||||
float delta = fabs(speed) - 1.0f;
|
||||
|
||||
@@ -269,11 +322,39 @@ float MovementAIComponent::GetBaseSpeed(LOT lot) {
|
||||
}
|
||||
|
||||
void MovementAIComponent::SetPosition(const NiPoint3& value) {
|
||||
m_Parent->SetPosition(value);
|
||||
auto* controllablePhysicsComponent = m_Parent->GetComponent<ControllablePhysicsComponent>();
|
||||
|
||||
if (controllablePhysicsComponent != nullptr) {
|
||||
controllablePhysicsComponent->SetPosition(value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto* simplePhysicsComponent = m_Parent->GetComponent<SimplePhysicsComponent>();
|
||||
|
||||
if (simplePhysicsComponent != nullptr) {
|
||||
simplePhysicsComponent->SetPosition(value);
|
||||
}
|
||||
}
|
||||
|
||||
void MovementAIComponent::SetRotation(const NiQuaternion& value) {
|
||||
if (!m_LockRotation) m_Parent->SetRotation(value);
|
||||
if (m_LockRotation) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto* controllablePhysicsComponent = m_Parent->GetComponent<ControllablePhysicsComponent>();
|
||||
|
||||
if (controllablePhysicsComponent != nullptr) {
|
||||
controllablePhysicsComponent->SetRotation(value);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
auto* simplePhysicsComponent = m_Parent->GetComponent<SimplePhysicsComponent>();
|
||||
|
||||
if (simplePhysicsComponent != nullptr) {
|
||||
simplePhysicsComponent->SetRotation(value);
|
||||
}
|
||||
}
|
||||
|
||||
void MovementAIComponent::SetVelocity(const NiPoint3& value) {
|
||||
@@ -292,8 +373,15 @@ void MovementAIComponent::SetVelocity(const NiPoint3& value) {
|
||||
}
|
||||
}
|
||||
|
||||
void MovementAIComponent::SetDestination(const NiPoint3& destination) {
|
||||
if (m_PullingToPoint) return;
|
||||
void MovementAIComponent::SetDestination(const NiPoint3& value) {
|
||||
if (m_Interrupted) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*if (Vector3::DistanceSquared(value, GetDestination()) < 2 * 2)
|
||||
{
|
||||
return;
|
||||
}*/
|
||||
|
||||
const auto location = ApproximateLocation();
|
||||
|
||||
@@ -302,53 +390,97 @@ void MovementAIComponent::SetDestination(const NiPoint3& destination) {
|
||||
}
|
||||
|
||||
std::vector<NiPoint3> computedPath;
|
||||
if (dpWorld::Instance().IsLoaded()) {
|
||||
computedPath = dpWorld::Instance().GetNavMesh()->GetPath(m_Parent->GetPosition(), destination, m_Info.wanderSpeed);
|
||||
}
|
||||
|
||||
// Somehow failed
|
||||
if (computedPath.empty()) {
|
||||
if (dpWorld::Instance().IsLoaded()) {
|
||||
computedPath = dpWorld::Instance().GetNavMesh()->GetPath(GetCurrentPosition(), value, m_Info.wanderSpeed);
|
||||
} else {
|
||||
// Than take 10 points between the current position and the destination and make that the path
|
||||
|
||||
auto start = location;
|
||||
auto point = location;
|
||||
|
||||
auto delta = destination - start;
|
||||
auto delta = value - point;
|
||||
|
||||
auto step = delta / 10.0f;
|
||||
auto step = delta / 10;
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// TODO: Replace this with += when the NiPoint3::operator+= is fixed
|
||||
start = start + step;
|
||||
point = point + step;
|
||||
|
||||
computedPath.push_back(start);
|
||||
computedPath.push_back(point);
|
||||
}
|
||||
}
|
||||
|
||||
m_InterpolatedWaypoints.clear();
|
||||
if (computedPath.empty()) // Somehow failed
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_CurrentPath.clear();
|
||||
|
||||
m_CurrentPath.push_back(location);
|
||||
|
||||
// Simply path
|
||||
for (auto& point : computedPath) {
|
||||
for (auto point : computedPath) {
|
||||
if (dpWorld::Instance().IsLoaded()) {
|
||||
point.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(point);
|
||||
}
|
||||
|
||||
m_InterpolatedWaypoints.push_back(point);
|
||||
m_CurrentPath.push_back(point);
|
||||
}
|
||||
|
||||
m_CurrentPath.push_back(computedPath[computedPath.size() - 1]);
|
||||
|
||||
m_PathIndex = 0;
|
||||
|
||||
m_TimeTravelled = 0;
|
||||
m_TimeToTravel = 0;
|
||||
m_TotalTime = m_Timer = 0;
|
||||
|
||||
m_AtFinalWaypoint = false;
|
||||
m_Done = false;
|
||||
}
|
||||
|
||||
NiPoint3 MovementAIComponent::GetDestination() const {
|
||||
return m_InterpolatedWaypoints.empty() ? m_Parent->GetPosition() : m_InterpolatedWaypoints.back();
|
||||
if (m_CurrentPath.empty()) {
|
||||
return GetCurrentPosition();
|
||||
}
|
||||
|
||||
return m_CurrentPath[m_CurrentPath.size() - 1];
|
||||
}
|
||||
|
||||
void MovementAIComponent::SetMaxSpeed(const float value) {
|
||||
if (value == m_MaxSpeed) return;
|
||||
m_MaxSpeed = value;
|
||||
void MovementAIComponent::SetSpeed(const float value) {
|
||||
m_Speed = value;
|
||||
m_Acceleration = value / 5;
|
||||
}
|
||||
|
||||
float MovementAIComponent::GetSpeed() const {
|
||||
return m_Speed;
|
||||
}
|
||||
|
||||
void MovementAIComponent::SetAcceleration(const float value) {
|
||||
m_Acceleration = value;
|
||||
}
|
||||
|
||||
float MovementAIComponent::GetAcceleration() const {
|
||||
return m_Acceleration;
|
||||
}
|
||||
|
||||
void MovementAIComponent::SetHaltDistance(const float value) {
|
||||
m_HaltDistance = value;
|
||||
}
|
||||
|
||||
float MovementAIComponent::GetHaltDistance() const {
|
||||
return m_HaltDistance;
|
||||
}
|
||||
|
||||
void MovementAIComponent::SetCurrentSpeed(float value) {
|
||||
m_CurrentSpeed = value;
|
||||
}
|
||||
|
||||
float MovementAIComponent::GetCurrentSpeed() const {
|
||||
return m_CurrentSpeed;
|
||||
}
|
||||
|
||||
void MovementAIComponent::SetLockRotation(bool value) {
|
||||
m_LockRotation = value;
|
||||
}
|
||||
|
||||
bool MovementAIComponent::GetLockRotation() const {
|
||||
return m_LockRotation;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Darkflame Universe
|
||||
* Copyright 2023
|
||||
* Copyright 2018
|
||||
*/
|
||||
|
||||
#ifndef MOVEMENTAICOMPONENT_H
|
||||
@@ -60,6 +60,7 @@ public:
|
||||
static const eReplicaComponentType ComponentType = eReplicaComponentType::MOVEMENT_AI;
|
||||
|
||||
MovementAIComponent(Entity* parentEntity, MovementAIInfo info);
|
||||
~MovementAIComponent() override;
|
||||
|
||||
void Update(float deltaTime) override;
|
||||
|
||||
@@ -85,55 +86,61 @@ public:
|
||||
* Sets the max speed at which this entity may run
|
||||
* @param value the speed value to set
|
||||
*/
|
||||
void SetMaxSpeed(float value);
|
||||
void SetSpeed(float value);
|
||||
|
||||
/**
|
||||
* Returns the max speed at which this entity may run
|
||||
* @return the max speed at which this entity may run
|
||||
*/
|
||||
float GetSpeed() const;
|
||||
|
||||
/**
|
||||
* Sets how fast the entity will accelerate when not running at full speed
|
||||
* @param value the acceleration to set
|
||||
*/
|
||||
void SetAcceleration(float value) { m_Acceleration = value; };
|
||||
void SetAcceleration(float value);
|
||||
|
||||
/**
|
||||
* Returns the current speed at which this entity accelerates when not running at full speed
|
||||
* @return the current speed at which this entity accelerates when not running at full speed
|
||||
*/
|
||||
float GetAcceleration() const { return m_Acceleration; };
|
||||
float GetAcceleration() const;
|
||||
|
||||
/**
|
||||
* Sets the halting distance (the distance at which we consider the target to be reached)
|
||||
* @param value the halting distance to set
|
||||
*/
|
||||
void SetHaltDistance(float value) { m_HaltDistance = value; }
|
||||
void SetHaltDistance(float value);
|
||||
|
||||
/**
|
||||
* Returns the current halting distance (the distance at which we consider the target to be reached)
|
||||
* @return the current halting distance
|
||||
*/
|
||||
float GetHaltDistance() const { return m_HaltDistance; }
|
||||
float GetHaltDistance() const;
|
||||
|
||||
/**
|
||||
* Sets the speed the entity is currently running at
|
||||
* @param value the speed value to set
|
||||
*/
|
||||
void SetCurrentSpeed(float value) { m_CurrentSpeed = value; }
|
||||
void SetCurrentSpeed(float value);
|
||||
|
||||
/**
|
||||
* Returns the speed the entity is currently running at
|
||||
* @return the speed the entity is currently running at
|
||||
*/
|
||||
float GetCurrentSpeed() const { return m_CurrentSpeed; }
|
||||
float GetCurrentSpeed() const;
|
||||
|
||||
/**
|
||||
* Locks the rotation of this entity in place, depending on the argument
|
||||
* @param value if true, the entity will be rotationally locked
|
||||
*/
|
||||
void SetLockRotation(bool value) { m_LockRotation = value; }
|
||||
void SetLockRotation(bool value);
|
||||
|
||||
/**
|
||||
* Returns whether this entity is currently rotationally locked
|
||||
* @return true if the entity is rotationally locked, false otherwise
|
||||
*/
|
||||
bool GetLockRotation() const { return m_LockRotation; };
|
||||
bool GetLockRotation() const;
|
||||
|
||||
/**
|
||||
* Attempts to update the waypoint index, making the entity move to the next waypoint
|
||||
@@ -151,7 +158,13 @@ public:
|
||||
* Returns the waypoint this entity is supposed to move towards next
|
||||
* @return the waypoint this entity is supposed to move towards next
|
||||
*/
|
||||
NiPoint3 GetNextWaypoint() const { return m_NextWaypoint; }
|
||||
NiPoint3 GetNextWaypoint() const;
|
||||
|
||||
/**
|
||||
* Returns the current position of this entity
|
||||
* @return the current position of this entity
|
||||
*/
|
||||
NiPoint3 GetCurrentPosition() const;
|
||||
|
||||
/**
|
||||
* Returns the approximate current location of the entity, including y coordinates
|
||||
@@ -167,11 +180,17 @@ public:
|
||||
*/
|
||||
bool Warp(const NiPoint3& point);
|
||||
|
||||
/**
|
||||
* Returns the time it will take to reach the final waypoint according to the current speed
|
||||
* @return the time it will take to reach the final waypoint according to the current speed
|
||||
*/
|
||||
float GetTimer() const;
|
||||
|
||||
/**
|
||||
* Returns if the entity is at its final waypoint
|
||||
* @return if the entity is at its final waypoint
|
||||
*/
|
||||
bool AtFinalWaypoint() const { return m_AtFinalWaypoint; }
|
||||
bool AtFinalWaypoint() const;
|
||||
|
||||
/**
|
||||
* Renders the entity stationary
|
||||
@@ -231,12 +250,17 @@ private:
|
||||
/**
|
||||
* The max speed this entity may move at
|
||||
*/
|
||||
float m_MaxSpeed;
|
||||
float m_Speed;
|
||||
|
||||
/**
|
||||
* The time it will take to reach the next waypoint using the current speed
|
||||
*/
|
||||
float m_TimeTravelled;
|
||||
float m_Timer;
|
||||
|
||||
/**
|
||||
* The total time it will take to reach the waypoint form its starting point
|
||||
*/
|
||||
float m_TotalTime;
|
||||
|
||||
/**
|
||||
* The path this entity is currently traversing
|
||||
@@ -246,7 +270,7 @@ private:
|
||||
/**
|
||||
* If the entity has reached it last waypoint
|
||||
*/
|
||||
bool m_AtFinalWaypoint;
|
||||
bool m_Done;
|
||||
|
||||
/**
|
||||
* The speed the entity is currently moving at
|
||||
@@ -263,11 +287,6 @@ private:
|
||||
*/
|
||||
float m_HaltDistance;
|
||||
|
||||
/**
|
||||
* The total time it will take to reach the waypoint form its starting point
|
||||
*/
|
||||
float m_TimeToTravel;
|
||||
|
||||
/**
|
||||
* The base speed this entity has
|
||||
*/
|
||||
@@ -276,7 +295,7 @@ private:
|
||||
/**
|
||||
* If the AI is currently turned of (e.g. when teleporting to some location)
|
||||
*/
|
||||
bool m_PullingToPoint;
|
||||
bool m_Interrupted;
|
||||
|
||||
/**
|
||||
* A position that the entity is currently moving towards while being interrupted
|
||||
@@ -296,12 +315,17 @@ private:
|
||||
/**
|
||||
* The path the entity is currently following
|
||||
*/
|
||||
std::vector<NiPoint3> m_InterpolatedWaypoints;
|
||||
std::vector<NiPoint3> m_CurrentPath;
|
||||
|
||||
/**
|
||||
* The path from the current position to the destination.
|
||||
* Queue of positions to traverse
|
||||
*/
|
||||
std::stack<NiPoint3> m_CurrentPath;
|
||||
std::stack<NiPoint3> m_Queue;
|
||||
|
||||
/**
|
||||
* Cache of all lots and their respective speeds
|
||||
*/
|
||||
static std::map<LOT, float> m_PhysicsSpeedCache;
|
||||
};
|
||||
|
||||
#endif // MOVEMENTAICOMPONENT_H
|
||||
|
||||
@@ -32,7 +32,7 @@ MoverSubComponent::MoverSubComponent(const NiPoint3& startPos) {
|
||||
|
||||
MoverSubComponent::~MoverSubComponent() = default;
|
||||
|
||||
void MoverSubComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void MoverSubComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) const {
|
||||
outBitStream->Write<bool>(true);
|
||||
|
||||
outBitStream->Write<uint32_t>(static_cast<uint32_t>(mState));
|
||||
@@ -71,7 +71,7 @@ MovingPlatformComponent::~MovingPlatformComponent() {
|
||||
delete static_cast<MoverSubComponent*>(m_MoverSubComponent);
|
||||
}
|
||||
|
||||
void MovingPlatformComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void MovingPlatformComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
// Here we don't serialize the moving platform to let the client simulate the movement
|
||||
|
||||
if (!m_Serialize) {
|
||||
@@ -112,7 +112,7 @@ void MovingPlatformComponent::Serialize(RakNet::BitStream* outBitStream, bool bI
|
||||
if (m_MoverSubComponentType == eMoverSubComponentType::simpleMover) {
|
||||
// TODO
|
||||
} else {
|
||||
mover->Serialize(outBitStream, bIsInitialUpdate);
|
||||
mover->Serialize(outBitStream, bIsInitialUpdate, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ public:
|
||||
MoverSubComponent(const NiPoint3& startPos);
|
||||
~MoverSubComponent();
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate);
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) const;
|
||||
|
||||
/**
|
||||
* The state the platform is currently in
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
MovingPlatformComponent(Entity* parent, const std::string& pathName);
|
||||
~MovingPlatformComponent() override;
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
|
||||
/**
|
||||
* Stops all pathing, called when an entity starts a quick build associated with this platform
|
||||
|
||||
@@ -107,7 +107,7 @@ PetComponent::PetComponent(Entity* parent, uint32_t componentId): Component(pare
|
||||
result.finalize();
|
||||
}
|
||||
|
||||
void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void PetComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
const bool tamed = m_Owner != LWOOBJID_EMPTY;
|
||||
|
||||
outBitStream->Write1(); // Always serialize as dirty for now
|
||||
@@ -395,7 +395,7 @@ void PetComponent::Update(float deltaTime) {
|
||||
}
|
||||
|
||||
auto destination = owner->GetPosition();
|
||||
NiPoint3 position = m_MovementAI->GetParent()->GetPosition();
|
||||
NiPoint3 position = m_MovementAI->GetCurrentPosition();
|
||||
|
||||
float distanceToOwner = Vector3::DistanceSquared(position, destination);
|
||||
|
||||
@@ -466,7 +466,7 @@ skipTresure:
|
||||
|
||||
m_MovementAI->SetHaltDistance(haltDistance);
|
||||
|
||||
m_MovementAI->SetMaxSpeed(2.5f);
|
||||
m_MovementAI->SetSpeed(2.5f);
|
||||
|
||||
m_MovementAI->SetDestination(destination);
|
||||
|
||||
@@ -822,17 +822,17 @@ void PetComponent::Wander() {
|
||||
destination.y = dpWorld::Instance().GetNavMesh()->GetHeightAtPoint(destination);
|
||||
}
|
||||
|
||||
if (Vector3::DistanceSquared(destination, m_MovementAI->GetParent()->GetPosition()) < 2 * 2) {
|
||||
if (Vector3::DistanceSquared(destination, m_MovementAI->GetCurrentPosition()) < 2 * 2) {
|
||||
m_MovementAI->Stop();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_MovementAI->SetMaxSpeed(info.wanderSpeed);
|
||||
m_MovementAI->SetSpeed(info.wanderSpeed);
|
||||
|
||||
m_MovementAI->SetDestination(destination);
|
||||
|
||||
m_Timer += (m_MovementAI->GetParent()->GetPosition().x - destination.x) / info.wanderSpeed;
|
||||
m_Timer += (m_MovementAI->GetCurrentPosition().x - destination.x) / info.wanderSpeed;
|
||||
}
|
||||
|
||||
void PetComponent::Activate(Item* item, bool registerPet, bool fromTaming) {
|
||||
|
||||
@@ -26,7 +26,7 @@ public:
|
||||
explicit PetComponent(Entity* parentEntity, uint32_t componentId);
|
||||
~PetComponent() override;
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
void Update(float deltaTime) override;
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,13 +27,14 @@
|
||||
#include "dpShapeBox.h"
|
||||
#include "dpShapeSphere.h"
|
||||
|
||||
PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : PhysicsComponent(parent) {
|
||||
PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : Component(parent) {
|
||||
m_Position = m_Parent->GetDefaultPosition();
|
||||
m_Rotation = m_Parent->GetDefaultRotation();
|
||||
m_Scale = m_Parent->GetDefaultScale();
|
||||
m_dpEntity = nullptr;
|
||||
|
||||
m_EffectInfoDirty = false;
|
||||
m_PositionInfoDirty = false;
|
||||
|
||||
m_IsPhysicsEffectActive = false;
|
||||
m_EffectType = ePhysicsEffectType::PUSH;
|
||||
@@ -215,7 +216,7 @@ PhantomPhysicsComponent::PhantomPhysicsComponent(Entity* parent) : PhysicsCompon
|
||||
m_dpEntity->SetRotation(m_Rotation);
|
||||
m_dpEntity->SetPosition(m_Position);
|
||||
dpWorld::Instance().AddEntity(m_dpEntity);
|
||||
} else if (info->physicsAsset == "env\\env_won_fv_gas-blocking-volume.hkx") {
|
||||
} else if (info->physicsAsset == "env\\env_won_fv_gas-blocking-volume.hkx"){
|
||||
m_dpEntity = new dpEntity(m_Parent->GetObjectID(), 390.496826f, 111.467964f, 600.821534f, true);
|
||||
m_dpEntity->SetScale(m_Scale);
|
||||
m_dpEntity->SetRotation(m_Rotation);
|
||||
@@ -305,8 +306,19 @@ void PhantomPhysicsComponent::CreatePhysics() {
|
||||
m_HasCreatedPhysics = true;
|
||||
}
|
||||
|
||||
void PhantomPhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
PhysicsComponent::Serialize(outBitStream, bIsInitialUpdate);
|
||||
void PhantomPhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
outBitStream->Write(m_PositionInfoDirty || bIsInitialUpdate);
|
||||
if (m_PositionInfoDirty || bIsInitialUpdate) {
|
||||
outBitStream->Write(m_Position.x);
|
||||
outBitStream->Write(m_Position.y);
|
||||
outBitStream->Write(m_Position.z);
|
||||
outBitStream->Write(m_Rotation.x);
|
||||
outBitStream->Write(m_Rotation.y);
|
||||
outBitStream->Write(m_Rotation.z);
|
||||
outBitStream->Write(m_Rotation.w);
|
||||
|
||||
m_PositionInfoDirty = false;
|
||||
}
|
||||
|
||||
outBitStream->Write(m_EffectInfoDirty || bIsInitialUpdate);
|
||||
if (m_EffectInfoDirty || bIsInitialUpdate) {
|
||||
@@ -336,28 +348,9 @@ void PhantomPhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bI
|
||||
}
|
||||
}
|
||||
|
||||
// Even if we were to implement Friction server side,
|
||||
// it also defaults to 1.0f in the last argument, so we dont need two functions to do the same thing.
|
||||
void ApplyCollisionEffect(const LWOOBJID& target, const ePhysicsEffectType effectType, const float effectScale) {
|
||||
switch (effectType) {
|
||||
case ePhysicsEffectType::GRAVITY_SCALE: {
|
||||
auto* targetEntity = Game::entityManager->GetEntity(target);
|
||||
if (targetEntity) {
|
||||
auto* controllablePhysicsComponent = targetEntity->GetComponent<ControllablePhysicsComponent>();
|
||||
// dont want to apply an effect to nothing.
|
||||
if (!controllablePhysicsComponent) return;
|
||||
controllablePhysicsComponent->SetGravityScale(effectScale);
|
||||
GameMessages::SendSetGravityScale(target, effectScale, targetEntity->GetSystemAddress());
|
||||
}
|
||||
}
|
||||
// The other types are not handled by the server
|
||||
case ePhysicsEffectType::ATTRACT:
|
||||
case ePhysicsEffectType::FRICTION:
|
||||
case ePhysicsEffectType::PUSH:
|
||||
case ePhysicsEffectType::REPULSE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
void PhantomPhysicsComponent::ResetFlags() {
|
||||
m_EffectInfoDirty = false;
|
||||
m_PositionInfoDirty = false;
|
||||
}
|
||||
|
||||
void PhantomPhysicsComponent::Update(float deltaTime) {
|
||||
@@ -365,8 +358,6 @@ void PhantomPhysicsComponent::Update(float deltaTime) {
|
||||
|
||||
//Process enter events
|
||||
for (auto en : m_dpEntity->GetNewObjects()) {
|
||||
if (!en) continue;
|
||||
ApplyCollisionEffect(en->GetObjectID(), m_EffectType, m_DirectionalMultiplier);
|
||||
m_Parent->OnCollisionPhantom(en->GetObjectID());
|
||||
|
||||
//If we are a respawn volume, inform the client:
|
||||
@@ -383,8 +374,6 @@ void PhantomPhysicsComponent::Update(float deltaTime) {
|
||||
|
||||
//Process exit events
|
||||
for (auto en : m_dpEntity->GetRemovedObjects()) {
|
||||
if (!en) continue;
|
||||
ApplyCollisionEffect(en->GetObjectID(), m_EffectType, 1.0f);
|
||||
m_Parent->OnCollisionLeavePhantom(en->GetObjectID());
|
||||
}
|
||||
}
|
||||
@@ -442,11 +431,13 @@ void PhantomPhysicsComponent::SetMax(uint32_t max) {
|
||||
}
|
||||
|
||||
void PhantomPhysicsComponent::SetPosition(const NiPoint3& pos) {
|
||||
PhysicsComponent::SetPosition(pos);
|
||||
m_Position = pos;
|
||||
|
||||
if (m_dpEntity) m_dpEntity->SetPosition(pos);
|
||||
}
|
||||
|
||||
void PhantomPhysicsComponent::SetRotation(const NiQuaternion& rot) {
|
||||
PhysicsComponent::SetRotation(rot);
|
||||
m_Rotation = rot;
|
||||
|
||||
if (m_dpEntity) m_dpEntity->SetRotation(rot);
|
||||
}
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
#include <vector>
|
||||
#include "CppScripts.h"
|
||||
#include "InvalidScript.h"
|
||||
#include "Component.h"
|
||||
#include "eReplicaComponentType.h"
|
||||
#include "PhysicsComponent.h"
|
||||
|
||||
class LDFBaseData;
|
||||
class Entity;
|
||||
@@ -25,14 +25,15 @@ enum class ePhysicsEffectType : uint32_t ;
|
||||
* trigger gameplay events, for example the bus in Avant Gardens that moves around when the player touches its physics
|
||||
* body. Optionally this object can also have effects, like the fans in AG.
|
||||
*/
|
||||
class PhantomPhysicsComponent : public PhysicsComponent {
|
||||
class PhantomPhysicsComponent : public Component {
|
||||
public:
|
||||
static const eReplicaComponentType ComponentType = eReplicaComponentType::PHANTOM_PHYSICS;
|
||||
|
||||
PhantomPhysicsComponent(Entity* parent);
|
||||
~PhantomPhysicsComponent() override;
|
||||
void Update(float deltaTime) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
void ResetFlags();
|
||||
|
||||
/**
|
||||
* Creates the physics shape for this entity based on LDF data
|
||||
@@ -75,17 +76,29 @@ public:
|
||||
*/
|
||||
void SetPhysicsEffectActive(bool val) { m_IsPhysicsEffectActive = val; m_EffectInfoDirty = true; }
|
||||
|
||||
/**
|
||||
* Returns the position of this physics object
|
||||
* @return the position of this physics object
|
||||
*/
|
||||
const NiPoint3& GetPosition() const { return m_Position; }
|
||||
|
||||
/**
|
||||
* Sets the position of this physics object
|
||||
* @param pos the position to set
|
||||
*/
|
||||
void SetPosition(const NiPoint3& pos) override;
|
||||
void SetPosition(const NiPoint3& pos);
|
||||
|
||||
/**
|
||||
* Returns the rotation of this physics object
|
||||
* @return the rotation of this physics object
|
||||
*/
|
||||
const NiQuaternion& GetRotation() const { return m_Rotation; }
|
||||
|
||||
/**
|
||||
* Sets the rotation of this physics object
|
||||
* @param rot the rotation to set
|
||||
*/
|
||||
void SetRotation(const NiQuaternion& rot) override;
|
||||
void SetRotation(const NiQuaternion& rot);
|
||||
|
||||
/**
|
||||
* Returns the effect that's currently active, defaults to 0
|
||||
@@ -122,11 +135,27 @@ public:
|
||||
void SetMax(uint32_t max);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* The position of the physics object
|
||||
*/
|
||||
NiPoint3 m_Position;
|
||||
|
||||
/**
|
||||
* The rotation of the physics object
|
||||
*/
|
||||
NiQuaternion m_Rotation;
|
||||
|
||||
/**
|
||||
* A scale to apply to the size of the physics object
|
||||
*/
|
||||
float m_Scale;
|
||||
|
||||
/**
|
||||
* Whether or not the position has changed and needs to be serialized
|
||||
*/
|
||||
bool m_PositionInfoDirty;
|
||||
|
||||
/**
|
||||
* Whether or not the effect has changed and needs to be serialized
|
||||
*/
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#include "PhysicsComponent.h"
|
||||
|
||||
PhysicsComponent::PhysicsComponent(Entity* parent) : Component(parent) {
|
||||
m_Position = NiPoint3::ZERO;
|
||||
m_Rotation = NiQuaternion::IDENTITY;
|
||||
m_DirtyPosition = false;
|
||||
}
|
||||
|
||||
void PhysicsComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
outBitStream->Write(bIsInitialUpdate || m_DirtyPosition);
|
||||
if (bIsInitialUpdate || m_DirtyPosition) {
|
||||
outBitStream->Write(m_Position.x);
|
||||
outBitStream->Write(m_Position.y);
|
||||
outBitStream->Write(m_Position.z);
|
||||
outBitStream->Write(m_Rotation.x);
|
||||
outBitStream->Write(m_Rotation.y);
|
||||
outBitStream->Write(m_Rotation.z);
|
||||
outBitStream->Write(m_Rotation.w);
|
||||
if (!bIsInitialUpdate) m_DirtyPosition = false;
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
#ifndef __PHYSICSCOMPONENT__H__
|
||||
#define __PHYSICSCOMPONENT__H__
|
||||
|
||||
#include "Component.h"
|
||||
#include "NiPoint3.h"
|
||||
#include "NiQuaternion.h"
|
||||
|
||||
namespace Raknet {
|
||||
class BitStream;
|
||||
};
|
||||
|
||||
class PhysicsComponent : public Component {
|
||||
public:
|
||||
PhysicsComponent(Entity* parent);
|
||||
virtual ~PhysicsComponent() = default;
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
|
||||
const NiPoint3& GetPosition() const { return m_Position; }
|
||||
virtual void SetPosition(const NiPoint3& pos) { if (m_Position == pos) return; m_Position = pos; m_DirtyPosition = true; }
|
||||
|
||||
const NiQuaternion& GetRotation() const { return m_Rotation; }
|
||||
virtual void SetRotation(const NiQuaternion& rot) { if (m_Rotation == rot) return; m_Rotation = rot; m_DirtyPosition = true; }
|
||||
protected:
|
||||
NiPoint3 m_Position;
|
||||
|
||||
NiQuaternion m_Rotation;
|
||||
|
||||
bool m_DirtyPosition;
|
||||
};
|
||||
|
||||
#endif //!__PHYSICSCOMPONENT__H__
|
||||
@@ -6,7 +6,7 @@ PlayerForcedMovementComponent::PlayerForcedMovementComponent(Entity* parent) : C
|
||||
|
||||
PlayerForcedMovementComponent::~PlayerForcedMovementComponent() {}
|
||||
|
||||
void PlayerForcedMovementComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void PlayerForcedMovementComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
outBitStream->Write(m_DirtyInfo || bIsInitialUpdate);
|
||||
if (m_DirtyInfo || bIsInitialUpdate) {
|
||||
outBitStream->Write(m_PlayerOnRail);
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
PlayerForcedMovementComponent(Entity* parent);
|
||||
~PlayerForcedMovementComponent() override;
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
|
||||
/**
|
||||
* @brief Set the Player On Rail object
|
||||
|
||||
@@ -27,7 +27,7 @@ PossessableComponent::PossessableComponent(Entity* parent, uint32_t componentId)
|
||||
result.finalize();
|
||||
}
|
||||
|
||||
void PossessableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||
void PossessableComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
|
||||
outBitStream->Write(m_DirtyPossessable || bIsInitialUpdate);
|
||||
if (m_DirtyPossessable || bIsInitialUpdate) {
|
||||
m_DirtyPossessable = false; // reset flag
|
||||
|
||||
@@ -18,7 +18,7 @@ public:
|
||||
|
||||
PossessableComponent(Entity* parentEntity, uint32_t componentId);
|
||||
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) override;
|
||||
void Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags);
|
||||
|
||||
/**
|
||||
* @brief mounts the Entity
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user