mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-22 05:27:19 +00:00
Merge branch 'main' into guild_temp
This commit is contained in:
commit
6a921f4ee6
@ -94,6 +94,8 @@ int main(int argc, char** argv) {
|
|||||||
uint32_t framesSinceMasterDisconnect = 0;
|
uint32_t framesSinceMasterDisconnect = 0;
|
||||||
uint32_t framesSinceLastSQLPing = 0;
|
uint32_t framesSinceLastSQLPing = 0;
|
||||||
|
|
||||||
|
AuthPackets::LoadClaimCodes();
|
||||||
|
|
||||||
while (!Game::shouldShutdown) {
|
while (!Game::shouldShutdown) {
|
||||||
//Check if we're still connected to master:
|
//Check if we're still connected to master:
|
||||||
if (!Game::server->GetIsConnectedToMaster()) {
|
if (!Game::server->GetIsConnectedToMaster()) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
set(DCHATSERVER_SOURCES
|
set(DCHATSERVER_SOURCES
|
||||||
|
"ChatIgnoreList.cpp"
|
||||||
"ChatPacketHandler.cpp"
|
"ChatPacketHandler.cpp"
|
||||||
"PlayerContainer.cpp"
|
"PlayerContainer.cpp"
|
||||||
)
|
)
|
||||||
|
173
dChatServer/ChatIgnoreList.cpp
Normal file
173
dChatServer/ChatIgnoreList.cpp
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
#include "ChatIgnoreList.h"
|
||||||
|
#include "PlayerContainer.h"
|
||||||
|
#include "eChatInternalMessageType.h"
|
||||||
|
#include "BitStreamUtils.h"
|
||||||
|
#include "PacketUtils.h"
|
||||||
|
#include "Game.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
#include "eObjectBits.h"
|
||||||
|
|
||||||
|
#include "Database.h"
|
||||||
|
|
||||||
|
// A note to future readers, The client handles all the actual ignoring logic:
|
||||||
|
// not allowing teams, rejecting DMs, friends requets etc.
|
||||||
|
// The only thing not auto-handled is instance activities force joining the team on the server.
|
||||||
|
|
||||||
|
void WriteOutgoingReplyHeader(RakNet::BitStream& bitStream, const LWOOBJID& receivingPlayer, const ChatIgnoreList::Response type) {
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT_INTERNAL, eChatInternalMessageType::ROUTE_TO_PLAYER);
|
||||||
|
bitStream.Write(receivingPlayer);
|
||||||
|
|
||||||
|
//portion that will get routed:
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatIgnoreList::GetIgnoreList(Packet* packet) {
|
||||||
|
CINSTREAM_SKIP_HEADER;
|
||||||
|
LWOOBJID playerId;
|
||||||
|
inStream.Read(playerId);
|
||||||
|
|
||||||
|
auto* receiver = Game::playerContainer.GetPlayerData(playerId);
|
||||||
|
if (!receiver) {
|
||||||
|
LOG("Tried to get ignore list, but player %llu not found in container", playerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!receiver->ignoredPlayers.empty()) {
|
||||||
|
LOG_DEBUG("Player %llu already has an ignore list", playerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ignoreList = Database::Get()->GetIgnoreList(static_cast<uint32_t>(playerId));
|
||||||
|
if (ignoreList.empty()) {
|
||||||
|
LOG_DEBUG("Player %llu has no ignores", playerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& ignoredPlayer : ignoreList) {
|
||||||
|
receiver->ignoredPlayers.push_back(IgnoreData{ ignoredPlayer.id, ignoredPlayer.name });
|
||||||
|
GeneralUtils::SetBit(receiver->ignoredPlayers.back().playerId, eObjectBits::CHARACTER);
|
||||||
|
GeneralUtils::SetBit(receiver->ignoredPlayers.back().playerId, eObjectBits::PERSISTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
CBITSTREAM;
|
||||||
|
WriteOutgoingReplyHeader(bitStream, receiver->playerID, ChatIgnoreList::Response::GET_IGNORE);
|
||||||
|
|
||||||
|
bitStream.Write<uint8_t>(false); // Probably is Is Free Trial, but we don't care about that
|
||||||
|
bitStream.Write<uint16_t>(0); // literally spacing due to struct alignment
|
||||||
|
|
||||||
|
bitStream.Write<uint16_t>(receiver->ignoredPlayers.size());
|
||||||
|
for (const auto& ignoredPlayer : receiver->ignoredPlayers) {
|
||||||
|
bitStream.Write(ignoredPlayer.playerId);
|
||||||
|
bitStream.Write(LUWString(ignoredPlayer.playerName, 36));
|
||||||
|
}
|
||||||
|
|
||||||
|
Game::server->Send(&bitStream, packet->systemAddress, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatIgnoreList::AddIgnore(Packet* packet) {
|
||||||
|
CINSTREAM_SKIP_HEADER;
|
||||||
|
LWOOBJID playerId;
|
||||||
|
inStream.Read(playerId);
|
||||||
|
|
||||||
|
auto* receiver = Game::playerContainer.GetPlayerData(playerId);
|
||||||
|
if (!receiver) {
|
||||||
|
LOG("Tried to get ignore list, but player %llu not found in container", playerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int32_t MAX_IGNORES = 32;
|
||||||
|
if (receiver->ignoredPlayers.size() > MAX_IGNORES) {
|
||||||
|
LOG_DEBUG("Player %llu has too many ignores", playerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inStream.IgnoreBytes(4); // ignore some garbage zeros idk
|
||||||
|
|
||||||
|
LUWString toIgnoreName(33);
|
||||||
|
inStream.Read(toIgnoreName);
|
||||||
|
std::string toIgnoreStr = toIgnoreName.GetAsString();
|
||||||
|
|
||||||
|
CBITSTREAM;
|
||||||
|
WriteOutgoingReplyHeader(bitStream, receiver->playerID, ChatIgnoreList::Response::ADD_IGNORE);
|
||||||
|
|
||||||
|
// Check if the player exists
|
||||||
|
LWOOBJID ignoredPlayerId = LWOOBJID_EMPTY;
|
||||||
|
if (toIgnoreStr == receiver->playerName || toIgnoreStr.find("[GM]") == 0) {
|
||||||
|
LOG_DEBUG("Player %llu tried to ignore themselves", playerId);
|
||||||
|
|
||||||
|
bitStream.Write(ChatIgnoreList::AddResponse::GENERAL_ERROR);
|
||||||
|
} else if (std::count(receiver->ignoredPlayers.begin(), receiver->ignoredPlayers.end(), toIgnoreStr) > 0) {
|
||||||
|
LOG_DEBUG("Player %llu is already ignoring %s", playerId, toIgnoreStr.c_str());
|
||||||
|
|
||||||
|
bitStream.Write(ChatIgnoreList::AddResponse::ALREADY_IGNORED);
|
||||||
|
} else {
|
||||||
|
// Get the playerId falling back to query if not online
|
||||||
|
auto* playerData = Game::playerContainer.GetPlayerData(toIgnoreStr);
|
||||||
|
if (!playerData) {
|
||||||
|
// Fall back to query
|
||||||
|
auto player = Database::Get()->GetCharacterInfo(toIgnoreStr);
|
||||||
|
if (!player || player->name != toIgnoreStr) {
|
||||||
|
LOG_DEBUG("Player %s not found", toIgnoreStr.c_str());
|
||||||
|
} else {
|
||||||
|
ignoredPlayerId = player->id;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ignoredPlayerId = playerData->playerID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ignoredPlayerId != LWOOBJID_EMPTY) {
|
||||||
|
Database::Get()->AddIgnore(static_cast<uint32_t>(playerId), static_cast<uint32_t>(ignoredPlayerId));
|
||||||
|
GeneralUtils::SetBit(ignoredPlayerId, eObjectBits::CHARACTER);
|
||||||
|
GeneralUtils::SetBit(ignoredPlayerId, eObjectBits::PERSISTENT);
|
||||||
|
|
||||||
|
receiver->ignoredPlayers.push_back(IgnoreData{ ignoredPlayerId, toIgnoreStr });
|
||||||
|
LOG_DEBUG("Player %llu is ignoring %s", playerId, toIgnoreStr.c_str());
|
||||||
|
|
||||||
|
bitStream.Write(ChatIgnoreList::AddResponse::SUCCESS);
|
||||||
|
} else {
|
||||||
|
bitStream.Write(ChatIgnoreList::AddResponse::PLAYER_NOT_FOUND);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LUWString playerNameSend(toIgnoreStr, 33);
|
||||||
|
bitStream.Write(playerNameSend);
|
||||||
|
bitStream.Write(ignoredPlayerId);
|
||||||
|
|
||||||
|
Game::server->Send(&bitStream, packet->systemAddress, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatIgnoreList::RemoveIgnore(Packet* packet) {
|
||||||
|
CINSTREAM_SKIP_HEADER;
|
||||||
|
LWOOBJID playerId;
|
||||||
|
inStream.Read(playerId);
|
||||||
|
|
||||||
|
auto* receiver = Game::playerContainer.GetPlayerData(playerId);
|
||||||
|
if (!receiver) {
|
||||||
|
LOG("Tried to get ignore list, but player %llu not found in container", playerId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
inStream.IgnoreBytes(4); // ignore some garbage zeros idk
|
||||||
|
|
||||||
|
LUWString removedIgnoreName(33);
|
||||||
|
inStream.Read(removedIgnoreName);
|
||||||
|
std::string removedIgnoreStr = removedIgnoreName.GetAsString();
|
||||||
|
|
||||||
|
auto toRemove = std::remove(receiver->ignoredPlayers.begin(), receiver->ignoredPlayers.end(), removedIgnoreStr);
|
||||||
|
if (toRemove == receiver->ignoredPlayers.end()) {
|
||||||
|
LOG_DEBUG("Player %llu is not ignoring %s", playerId, removedIgnoreStr.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Database::Get()->RemoveIgnore(static_cast<uint32_t>(playerId), static_cast<uint32_t>(toRemove->playerId));
|
||||||
|
receiver->ignoredPlayers.erase(toRemove, receiver->ignoredPlayers.end());
|
||||||
|
|
||||||
|
CBITSTREAM;
|
||||||
|
WriteOutgoingReplyHeader(bitStream, receiver->playerID, ChatIgnoreList::Response::REMOVE_IGNORE);
|
||||||
|
|
||||||
|
bitStream.Write<int8_t>(0);
|
||||||
|
LUWString playerNameSend(removedIgnoreStr, 33);
|
||||||
|
bitStream.Write(playerNameSend);
|
||||||
|
|
||||||
|
Game::server->Send(&bitStream, packet->systemAddress, false);
|
||||||
|
}
|
27
dChatServer/ChatIgnoreList.h
Normal file
27
dChatServer/ChatIgnoreList.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef __CHATIGNORELIST__H__
|
||||||
|
#define __CHATIGNORELIST__H__
|
||||||
|
|
||||||
|
struct Packet;
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace ChatIgnoreList {
|
||||||
|
void GetIgnoreList(Packet* packet);
|
||||||
|
void AddIgnore(Packet* packet);
|
||||||
|
void RemoveIgnore(Packet* packet);
|
||||||
|
|
||||||
|
enum class Response : uint8_t {
|
||||||
|
ADD_IGNORE = 32,
|
||||||
|
REMOVE_IGNORE = 33,
|
||||||
|
GET_IGNORE = 34,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class AddResponse : uint8_t {
|
||||||
|
SUCCESS,
|
||||||
|
ALREADY_IGNORED,
|
||||||
|
PLAYER_NOT_FOUND,
|
||||||
|
GENERAL_ERROR,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__CHATIGNORELIST__H__
|
@ -20,15 +20,13 @@
|
|||||||
#include "eGameMessageType.h"
|
#include "eGameMessageType.h"
|
||||||
#include "eGuildLeaveReason.h"
|
#include "eGuildLeaveReason.h"
|
||||||
|
|
||||||
extern PlayerContainer playerContainer;
|
|
||||||
|
|
||||||
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||||
//Get from the packet which player we want to do something with:
|
//Get from the packet which player we want to do something with:
|
||||||
CINSTREAM_SKIP_HEADER;
|
CINSTREAM_SKIP_HEADER;
|
||||||
LWOOBJID playerID = 0;
|
LWOOBJID playerID = 0;
|
||||||
inStream.Read(playerID);
|
inStream.Read(playerID);
|
||||||
|
|
||||||
auto player = playerContainer.GetPlayerData(playerID);
|
auto player = Game::playerContainer.GetPlayerData(playerID);
|
||||||
if (!player) return;
|
if (!player) return;
|
||||||
|
|
||||||
auto friendsList = Database::Get()->GetFriendsList(playerID);
|
auto friendsList = Database::Get()->GetFriendsList(playerID);
|
||||||
@ -44,7 +42,7 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
|||||||
fd.friendName = friendData.friendName;
|
fd.friendName = friendData.friendName;
|
||||||
|
|
||||||
//Now check if they're online:
|
//Now check if they're online:
|
||||||
auto fr = playerContainer.GetPlayerData(fd.friendID);
|
auto fr = Game::playerContainer.GetPlayerData(fd.friendID);
|
||||||
|
|
||||||
if (fr) {
|
if (fr) {
|
||||||
fd.isOnline = true;
|
fd.isOnline = true;
|
||||||
@ -98,7 +96,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
|||||||
char isBestFriendRequest{};
|
char isBestFriendRequest{};
|
||||||
inStream.Read(isBestFriendRequest);
|
inStream.Read(isBestFriendRequest);
|
||||||
|
|
||||||
auto requestor = playerContainer.GetPlayerData(requestorPlayerID);
|
auto requestor = Game::playerContainer.GetPlayerData(requestorPlayerID);
|
||||||
if (!requestor) {
|
if (!requestor) {
|
||||||
LOG("No requestor player %llu sent to %s found.", requestorPlayerID, playerName.c_str());
|
LOG("No requestor player %llu sent to %s found.", requestorPlayerID, playerName.c_str());
|
||||||
return;
|
return;
|
||||||
@ -108,7 +106,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
|||||||
SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN);
|
SendFriendResponse(requestor, requestor, eAddFriendResponseType::MYTHRAN);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
std::unique_ptr<PlayerData> requestee(playerContainer.GetPlayerData(playerName));
|
std::unique_ptr<PlayerData> requestee(Game::playerContainer.GetPlayerData(playerName));
|
||||||
|
|
||||||
// Check if player is online first
|
// Check if player is online first
|
||||||
if (isBestFriendRequest && !requestee) {
|
if (isBestFriendRequest && !requestee) {
|
||||||
@ -176,7 +174,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
|||||||
|
|
||||||
// Only do updates if there was a change in the bff status.
|
// Only do updates if there was a change in the bff status.
|
||||||
if (oldBestFriendStatus != bestFriendStatus) {
|
if (oldBestFriendStatus != bestFriendStatus) {
|
||||||
auto maxBestFriends = playerContainer.GetMaxNumberOfBestFriends();
|
auto maxBestFriends = Game::playerContainer.GetMaxNumberOfBestFriends();
|
||||||
if (requestee->countOfBestFriends >= maxBestFriends || requestor->countOfBestFriends >= maxBestFriends) {
|
if (requestee->countOfBestFriends >= maxBestFriends || requestor->countOfBestFriends >= maxBestFriends) {
|
||||||
if (requestee->countOfBestFriends >= maxBestFriends) {
|
if (requestee->countOfBestFriends >= maxBestFriends) {
|
||||||
SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false);
|
SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false);
|
||||||
@ -209,7 +207,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
|||||||
if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::WAITINGAPPROVAL, true, true);
|
if (requestor->sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::WAITINGAPPROVAL, true, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto maxFriends = playerContainer.GetMaxNumberOfFriends();
|
auto maxFriends = Game::playerContainer.GetMaxNumberOfFriends();
|
||||||
if (requestee->friends.size() >= maxFriends) {
|
if (requestee->friends.size() >= maxFriends) {
|
||||||
SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false);
|
SendFriendResponse(requestor, requestee.get(), eAddFriendResponseType::THEIRFRIENDLISTFULL, false);
|
||||||
} else if (requestor->friends.size() >= maxFriends) {
|
} else if (requestor->friends.size() >= maxFriends) {
|
||||||
@ -233,8 +231,8 @@ void ChatPacketHandler::HandleFriendResponse(Packet* packet) {
|
|||||||
std::string friendName = PacketUtils::ReadString(0x15, packet, true);
|
std::string friendName = PacketUtils::ReadString(0x15, packet, true);
|
||||||
|
|
||||||
//Now to try and find both of these:
|
//Now to try and find both of these:
|
||||||
auto requestor = playerContainer.GetPlayerData(playerID);
|
auto requestor = Game::playerContainer.GetPlayerData(playerID);
|
||||||
auto requestee = playerContainer.GetPlayerData(friendName);
|
auto requestee = Game::playerContainer.GetPlayerData(friendName);
|
||||||
if (!requestor || !requestee) return;
|
if (!requestor || !requestee) return;
|
||||||
|
|
||||||
eAddFriendResponseType serverResponseCode{};
|
eAddFriendResponseType serverResponseCode{};
|
||||||
@ -316,7 +314,7 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
|||||||
Database::Get()->RemoveFriend(playerID, friendID);
|
Database::Get()->RemoveFriend(playerID, friendID);
|
||||||
|
|
||||||
//Now, we need to send an update to notify the sender (and possibly, receiver) that their friendship has been ended:
|
//Now, we need to send an update to notify the sender (and possibly, receiver) that their friendship has been ended:
|
||||||
auto goonA = playerContainer.GetPlayerData(playerID);
|
auto goonA = Game::playerContainer.GetPlayerData(playerID);
|
||||||
if (goonA) {
|
if (goonA) {
|
||||||
// Remove the friend from our list of friends
|
// Remove the friend from our list of friends
|
||||||
for (auto friendData = goonA->friends.begin(); friendData != goonA->friends.end(); friendData++) {
|
for (auto friendData = goonA->friends.begin(); friendData != goonA->friends.end(); friendData++) {
|
||||||
@ -329,7 +327,7 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
|||||||
SendRemoveFriend(goonA, friendName, true);
|
SendRemoveFriend(goonA, friendName, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto goonB = playerContainer.GetPlayerData(friendID);
|
auto goonB = Game::playerContainer.GetPlayerData(friendID);
|
||||||
if (!goonB) return;
|
if (!goonB) return;
|
||||||
// Do it again for other person
|
// Do it again for other person
|
||||||
for (auto friendData = goonB->friends.begin(); friendData != goonB->friends.end(); friendData++) {
|
for (auto friendData = goonB->friends.begin(); friendData != goonB->friends.end(); friendData++) {
|
||||||
@ -340,7 +338,7 @@ void ChatPacketHandler::HandleRemoveFriend(Packet* packet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string goonAName = GeneralUtils::UTF16ToWTF8(playerContainer.GetName(playerID));
|
std::string goonAName = GeneralUtils::UTF16ToWTF8(Game::playerContainer.GetName(playerID));
|
||||||
SendRemoveFriend(goonB, goonAName, true);
|
SendRemoveFriend(goonB, goonAName, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -349,11 +347,11 @@ void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
|||||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||||
inStream.Read(playerID);
|
inStream.Read(playerID);
|
||||||
|
|
||||||
auto* sender = playerContainer.GetPlayerData(playerID);
|
auto* sender = Game::playerContainer.GetPlayerData(playerID);
|
||||||
|
|
||||||
if (sender == nullptr) return;
|
if (sender == nullptr) return;
|
||||||
|
|
||||||
if (playerContainer.GetIsMuted(sender)) return;
|
if (Game::playerContainer.GetIsMuted(sender)) return;
|
||||||
|
|
||||||
const auto senderName = std::string(sender->playerName.c_str());
|
const auto senderName = std::string(sender->playerName.c_str());
|
||||||
|
|
||||||
@ -405,11 +403,11 @@ void ChatPacketHandler::HandlePrivateChatMessage(Packet* packet) {
|
|||||||
std::string message = PacketUtils::ReadString(0xAA, packet, true, 512);
|
std::string message = PacketUtils::ReadString(0xAA, packet, true, 512);
|
||||||
|
|
||||||
//Get the bois:
|
//Get the bois:
|
||||||
auto goonA = playerContainer.GetPlayerData(senderID);
|
auto goonA = Game::playerContainer.GetPlayerData(senderID);
|
||||||
auto goonB = playerContainer.GetPlayerData(receiverName);
|
auto goonB = Game::playerContainer.GetPlayerData(receiverName);
|
||||||
if (!goonA || !goonB) return;
|
if (!goonA || !goonB) return;
|
||||||
|
|
||||||
if (playerContainer.GetIsMuted(goonA)) return;
|
if (Game::playerContainer.GetIsMuted(goonA)) return;
|
||||||
|
|
||||||
std::string goonAName = goonA->playerName.c_str();
|
std::string goonAName = goonA->playerName.c_str();
|
||||||
std::string goonBName = goonB->playerName.c_str();
|
std::string goonBName = goonB->playerName.c_str();
|
||||||
@ -467,25 +465,25 @@ void ChatPacketHandler::HandleTeamInvite(Packet* packet) {
|
|||||||
inStream.Read(playerID);
|
inStream.Read(playerID);
|
||||||
std::string invitedPlayer = PacketUtils::ReadString(0x14, packet, true);
|
std::string invitedPlayer = PacketUtils::ReadString(0x14, packet, true);
|
||||||
|
|
||||||
auto* player = playerContainer.GetPlayerData(playerID);
|
auto* player = Game::playerContainer.GetPlayerData(playerID);
|
||||||
|
|
||||||
if (player == nullptr) {
|
if (player == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* team = playerContainer.GetTeam(playerID);
|
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||||
|
|
||||||
if (team == nullptr) {
|
if (team == nullptr) {
|
||||||
team = playerContainer.CreateTeam(playerID);
|
team = Game::playerContainer.CreateTeam(playerID);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* other = playerContainer.GetPlayerData(invitedPlayer);
|
auto* other = Game::playerContainer.GetPlayerData(invitedPlayer);
|
||||||
|
|
||||||
if (other == nullptr) {
|
if (other == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playerContainer.GetTeam(other->playerID) != nullptr) {
|
if (Game::playerContainer.GetTeam(other->playerID) != nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,12 +516,12 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* team = playerContainer.GetTeam(leaderID);
|
auto* team = Game::playerContainer.GetTeam(leaderID);
|
||||||
|
|
||||||
if (team == nullptr) {
|
if (team == nullptr) {
|
||||||
LOG("Failed to find team for leader (%llu)", leaderID);
|
LOG("Failed to find team for leader (%llu)", leaderID);
|
||||||
|
|
||||||
team = playerContainer.GetTeam(playerID);
|
team = Game::playerContainer.GetTeam(playerID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (team == nullptr) {
|
if (team == nullptr) {
|
||||||
@ -531,7 +529,7 @@ void ChatPacketHandler::HandleTeamInviteResponse(Packet* packet) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
playerContainer.AddMember(team, playerID);
|
Game::playerContainer.AddMember(team, playerID);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
|
void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
|
||||||
@ -541,12 +539,12 @@ void ChatPacketHandler::HandleTeamLeave(Packet* packet) {
|
|||||||
uint32_t size = 0;
|
uint32_t size = 0;
|
||||||
inStream.Read(size);
|
inStream.Read(size);
|
||||||
|
|
||||||
auto* team = playerContainer.GetTeam(playerID);
|
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||||
|
|
||||||
LOG("(%llu) leaving team", playerID);
|
LOG("(%llu) leaving team", playerID);
|
||||||
|
|
||||||
if (team != nullptr) {
|
if (team != nullptr) {
|
||||||
playerContainer.RemoveMember(team, playerID, false, false, true);
|
Game::playerContainer.RemoveMember(team, playerID, false, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,24 +557,24 @@ void ChatPacketHandler::HandleTeamKick(Packet* packet) {
|
|||||||
|
|
||||||
LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str());
|
LOG("(%llu) kicking (%s) from team", playerID, kickedPlayer.c_str());
|
||||||
|
|
||||||
auto* kicked = playerContainer.GetPlayerData(kickedPlayer);
|
auto* kicked = Game::playerContainer.GetPlayerData(kickedPlayer);
|
||||||
|
|
||||||
LWOOBJID kickedId = LWOOBJID_EMPTY;
|
LWOOBJID kickedId = LWOOBJID_EMPTY;
|
||||||
|
|
||||||
if (kicked != nullptr) {
|
if (kicked != nullptr) {
|
||||||
kickedId = kicked->playerID;
|
kickedId = kicked->playerID;
|
||||||
} else {
|
} else {
|
||||||
kickedId = playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer));
|
kickedId = Game::playerContainer.GetId(GeneralUtils::UTF8ToUTF16(kickedPlayer));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (kickedId == LWOOBJID_EMPTY) return;
|
if (kickedId == LWOOBJID_EMPTY) return;
|
||||||
|
|
||||||
auto* team = playerContainer.GetTeam(playerID);
|
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||||
|
|
||||||
if (team != nullptr) {
|
if (team != nullptr) {
|
||||||
if (team->leaderID != playerID || team->leaderID == kickedId) return;
|
if (team->leaderID != playerID || team->leaderID == kickedId) return;
|
||||||
|
|
||||||
playerContainer.RemoveMember(team, kickedId, false, true, false);
|
Game::playerContainer.RemoveMember(team, kickedId, false, true, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,16 +587,16 @@ void ChatPacketHandler::HandleTeamPromote(Packet* packet) {
|
|||||||
|
|
||||||
LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str());
|
LOG("(%llu) promoting (%s) to team leader", playerID, promotedPlayer.c_str());
|
||||||
|
|
||||||
auto* promoted = playerContainer.GetPlayerData(promotedPlayer);
|
auto* promoted = Game::playerContainer.GetPlayerData(promotedPlayer);
|
||||||
|
|
||||||
if (promoted == nullptr) return;
|
if (promoted == nullptr) return;
|
||||||
|
|
||||||
auto* team = playerContainer.GetTeam(playerID);
|
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||||
|
|
||||||
if (team != nullptr) {
|
if (team != nullptr) {
|
||||||
if (team->leaderID != playerID) return;
|
if (team->leaderID != playerID) return;
|
||||||
|
|
||||||
playerContainer.PromoteMember(team, promoted->playerID);
|
Game::playerContainer.PromoteMember(team, promoted->playerID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,16 +610,16 @@ void ChatPacketHandler::HandleTeamLootOption(Packet* packet) {
|
|||||||
char option;
|
char option;
|
||||||
inStream.Read(option);
|
inStream.Read(option);
|
||||||
|
|
||||||
auto* team = playerContainer.GetTeam(playerID);
|
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||||
|
|
||||||
if (team != nullptr) {
|
if (team != nullptr) {
|
||||||
if (team->leaderID != playerID) return;
|
if (team->leaderID != playerID) return;
|
||||||
|
|
||||||
team->lootFlag = option;
|
team->lootFlag = option;
|
||||||
|
|
||||||
playerContainer.TeamStatusUpdate(team);
|
Game::playerContainer.TeamStatusUpdate(team);
|
||||||
|
|
||||||
playerContainer.UpdateTeamsOnWorld(team, false);
|
Game::playerContainer.UpdateTeamsOnWorld(team, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,18 +628,18 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
|
|||||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||||
inStream.Read(playerID);
|
inStream.Read(playerID);
|
||||||
|
|
||||||
auto* team = playerContainer.GetTeam(playerID);
|
auto* team = Game::playerContainer.GetTeam(playerID);
|
||||||
auto* data = playerContainer.GetPlayerData(playerID);
|
auto* data = Game::playerContainer.GetPlayerData(playerID);
|
||||||
|
|
||||||
if (team != nullptr && data != nullptr) {
|
if (team != nullptr && data != nullptr) {
|
||||||
if (team->local && data->zoneID.GetMapID() != team->zoneId.GetMapID() && data->zoneID.GetCloneID() != team->zoneId.GetCloneID()) {
|
if (team->local && data->zoneID.GetMapID() != team->zoneId.GetMapID() && data->zoneID.GetCloneID() != team->zoneId.GetCloneID()) {
|
||||||
playerContainer.RemoveMember(team, playerID, false, false, true, true);
|
Game::playerContainer.RemoveMember(team, playerID, false, false, true, true);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (team->memberIDs.size() <= 1 && !team->local) {
|
if (team->memberIDs.size() <= 1 && !team->local) {
|
||||||
playerContainer.DisbandTeam(team);
|
Game::playerContainer.DisbandTeam(team);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -652,16 +650,16 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
|
|||||||
ChatPacketHandler::SendTeamSetLeader(data, LWOOBJID_EMPTY);
|
ChatPacketHandler::SendTeamSetLeader(data, LWOOBJID_EMPTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
playerContainer.TeamStatusUpdate(team);
|
Game::playerContainer.TeamStatusUpdate(team);
|
||||||
|
|
||||||
const auto leaderName = GeneralUtils::UTF8ToUTF16(data->playerName);
|
const auto leaderName = GeneralUtils::UTF8ToUTF16(data->playerName);
|
||||||
|
|
||||||
for (const auto memberId : team->memberIDs) {
|
for (const auto memberId : team->memberIDs) {
|
||||||
auto* otherMember = playerContainer.GetPlayerData(memberId);
|
auto* otherMember = Game::playerContainer.GetPlayerData(memberId);
|
||||||
|
|
||||||
if (memberId == playerID) continue;
|
if (memberId == playerID) continue;
|
||||||
|
|
||||||
const auto memberName = playerContainer.GetName(memberId);
|
const auto memberName = Game::playerContainer.GetName(memberId);
|
||||||
|
|
||||||
if (otherMember != nullptr) {
|
if (otherMember != nullptr) {
|
||||||
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID);
|
ChatPacketHandler::SendTeamSetOffWorldFlag(otherMember, data->playerID, data->zoneID);
|
||||||
@ -669,7 +667,7 @@ void ChatPacketHandler::HandleTeamStatusRequest(Packet* packet) {
|
|||||||
ChatPacketHandler::SendTeamAddPlayer(data, false, team->local, false, memberId, memberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0));
|
ChatPacketHandler::SendTeamAddPlayer(data, false, team->local, false, memberId, memberName, otherMember != nullptr ? otherMember->zoneID : LWOZONEID(0, 0, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
playerContainer.UpdateTeamsOnWorld(team, false);
|
Game::playerContainer.UpdateTeamsOnWorld(team, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "eChatInternalMessageType.h"
|
#include "eChatInternalMessageType.h"
|
||||||
#include "eWorldMessageType.h"
|
#include "eWorldMessageType.h"
|
||||||
#include "PacketUtils.h"
|
#include "PacketUtils.h"
|
||||||
|
#include "ChatIgnoreList.h"
|
||||||
|
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
|
|
||||||
@ -35,14 +36,12 @@ namespace Game {
|
|||||||
AssetManager* assetManager = nullptr;
|
AssetManager* assetManager = nullptr;
|
||||||
bool shouldShutdown = false;
|
bool shouldShutdown = false;
|
||||||
std::mt19937 randomEngine;
|
std::mt19937 randomEngine;
|
||||||
|
PlayerContainer playerContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Logger* SetupLogger();
|
Logger* SetupLogger();
|
||||||
void HandlePacket(Packet* packet);
|
void HandlePacket(Packet* packet);
|
||||||
|
|
||||||
PlayerContainer playerContainer;
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
constexpr uint32_t chatFramerate = mediumFramerate;
|
constexpr uint32_t chatFramerate = mediumFramerate;
|
||||||
constexpr uint32_t chatFrameDelta = mediumFrameDelta;
|
constexpr uint32_t chatFrameDelta = mediumFrameDelta;
|
||||||
@ -109,7 +108,7 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
Game::randomEngine = std::mt19937(time(0));
|
Game::randomEngine = std::mt19937(time(0));
|
||||||
|
|
||||||
playerContainer.Initialize();
|
Game::playerContainer.Initialize();
|
||||||
|
|
||||||
//Run it until server gets a kill message from Master:
|
//Run it until server gets a kill message from Master:
|
||||||
auto t = std::chrono::high_resolution_clock::now();
|
auto t = std::chrono::high_resolution_clock::now();
|
||||||
@ -201,19 +200,19 @@ void HandlePacket(Packet* packet) {
|
|||||||
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) {
|
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::CHAT_INTERNAL) {
|
||||||
switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
|
switch (static_cast<eChatInternalMessageType>(packet->data[3])) {
|
||||||
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
|
case eChatInternalMessageType::PLAYER_ADDED_NOTIFICATION:
|
||||||
playerContainer.InsertPlayer(packet);
|
Game::playerContainer.InsertPlayer(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION:
|
case eChatInternalMessageType::PLAYER_REMOVED_NOTIFICATION:
|
||||||
playerContainer.RemovePlayer(packet);
|
Game::playerContainer.RemovePlayer(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatInternalMessageType::MUTE_UPDATE:
|
case eChatInternalMessageType::MUTE_UPDATE:
|
||||||
playerContainer.MuteUpdate(packet);
|
Game::playerContainer.MuteUpdate(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatInternalMessageType::CREATE_TEAM:
|
case eChatInternalMessageType::CREATE_TEAM:
|
||||||
playerContainer.CreateTeamServer(packet);
|
Game::playerContainer.CreateTeamServer(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatInternalMessageType::ANNOUNCEMENT: {
|
case eChatInternalMessageType::ANNOUNCEMENT: {
|
||||||
@ -235,7 +234,15 @@ void HandlePacket(Packet* packet) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::GET_IGNORE_LIST:
|
case eChatMessageType::GET_IGNORE_LIST:
|
||||||
LOG("Asked for ignore list, but is unimplemented right now.");
|
ChatIgnoreList::GetIgnoreList(packet);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case eChatMessageType::ADD_IGNORE:
|
||||||
|
ChatIgnoreList::AddIgnore(packet);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case eChatMessageType::REMOVE_IGNORE:
|
||||||
|
ChatIgnoreList::RemoveIgnore(packet);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case eChatMessageType::TEAM_GET_STATUS:
|
case eChatMessageType::TEAM_GET_STATUS:
|
||||||
|
@ -7,12 +7,26 @@
|
|||||||
#include "dServer.h"
|
#include "dServer.h"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
struct IgnoreData {
|
||||||
|
inline bool operator==(const std::string& other) const noexcept {
|
||||||
|
return playerName == other;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool operator==(const LWOOBJID& other) const noexcept {
|
||||||
|
return playerId == other;
|
||||||
|
}
|
||||||
|
|
||||||
|
LWOOBJID playerId;
|
||||||
|
std::string playerName;
|
||||||
|
};
|
||||||
|
|
||||||
struct PlayerData {
|
struct PlayerData {
|
||||||
LWOOBJID playerID;
|
LWOOBJID playerID;
|
||||||
std::string playerName;
|
std::string playerName;
|
||||||
SystemAddress sysAddr;
|
SystemAddress sysAddr;
|
||||||
LWOZONEID zoneID;
|
LWOZONEID zoneID;
|
||||||
std::vector<FriendData> friends;
|
std::vector<FriendData> friends;
|
||||||
|
std::vector<IgnoreData> ignoredPlayers;
|
||||||
time_t muteExpire;
|
time_t muteExpire;
|
||||||
uint8_t countOfBestFriends = 0;
|
uint8_t countOfBestFriends = 0;
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,7 @@ class AssetManager;
|
|||||||
struct SystemAddress;
|
struct SystemAddress;
|
||||||
class EntityManager;
|
class EntityManager;
|
||||||
class dZoneManager;
|
class dZoneManager;
|
||||||
|
class PlayerContainer;
|
||||||
|
|
||||||
namespace Game {
|
namespace Game {
|
||||||
extern Logger* logger;
|
extern Logger* logger;
|
||||||
@ -26,4 +27,5 @@ namespace Game {
|
|||||||
extern bool shouldShutdown;
|
extern bool shouldShutdown;
|
||||||
extern EntityManager* entityManager;
|
extern EntityManager* entityManager;
|
||||||
extern dZoneManager* zoneManager;
|
extern dZoneManager* zoneManager;
|
||||||
|
extern PlayerContainer playerContainer;
|
||||||
}
|
}
|
||||||
|
@ -166,7 +166,8 @@ enum ePlayerFlag : int32_t {
|
|||||||
NJ_LIGHTNING_SPINJITZU = 2031,
|
NJ_LIGHTNING_SPINJITZU = 2031,
|
||||||
NJ_ICE_SPINJITZU = 2032,
|
NJ_ICE_SPINJITZU = 2032,
|
||||||
NJ_FIRE_SPINJITZU = 2033,
|
NJ_FIRE_SPINJITZU = 2033,
|
||||||
NJ_WU_SHOW_DAILY_CHEST = 2099
|
NJ_WU_SHOW_DAILY_CHEST = 2099,
|
||||||
|
DLU_SKIP_CINEMATICS = 1'000'000,
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //!__EPLAYERFLAG__H__
|
#endif //!__EPLAYERFLAG__H__
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "CDPropertyTemplateTable.h"
|
#include "CDPropertyTemplateTable.h"
|
||||||
#include "CDFeatureGatingTable.h"
|
#include "CDFeatureGatingTable.h"
|
||||||
#include "CDRailActivatorComponent.h"
|
#include "CDRailActivatorComponent.h"
|
||||||
|
#include "CDRewardCodesTable.h"
|
||||||
|
|
||||||
// Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory.
|
// Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory.
|
||||||
// A vanilla CDClient takes about 46MB of memory + the regular world data.
|
// A vanilla CDClient takes about 46MB of memory + the regular world data.
|
||||||
@ -82,6 +83,7 @@ CDClientManager::CDClientManager() {
|
|||||||
CDRailActivatorComponentTable::Instance().LoadValuesFromDatabase();
|
CDRailActivatorComponentTable::Instance().LoadValuesFromDatabase();
|
||||||
CDRarityTableTable::Instance().LoadValuesFromDatabase();
|
CDRarityTableTable::Instance().LoadValuesFromDatabase();
|
||||||
CDRebuildComponentTable::Instance().LoadValuesFromDatabase();
|
CDRebuildComponentTable::Instance().LoadValuesFromDatabase();
|
||||||
|
CDRewardCodesTable::Instance().LoadValuesFromDatabase();
|
||||||
CDRewardsTable::Instance().LoadValuesFromDatabase();
|
CDRewardsTable::Instance().LoadValuesFromDatabase();
|
||||||
CDScriptComponentTable::Instance().LoadValuesFromDatabase();
|
CDScriptComponentTable::Instance().LoadValuesFromDatabase();
|
||||||
CDSkillBehaviorTable::Instance().LoadValuesFromDatabase();
|
CDSkillBehaviorTable::Instance().LoadValuesFromDatabase();
|
||||||
|
@ -44,7 +44,7 @@ std::vector<CDFeatureGating> CDFeatureGatingTable::Query(std::function<bool(CDFe
|
|||||||
|
|
||||||
bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const {
|
bool CDFeatureGatingTable::FeatureUnlocked(const CDFeatureGating& feature) const {
|
||||||
for (const auto& entry : entries) {
|
for (const auto& entry : entries) {
|
||||||
if (entry.featureName == feature.featureName && entry >= feature) {
|
if (entry.featureName == feature.featureName && feature >= entry) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
#include "CDRewardCodesTable.h"
|
||||||
|
|
||||||
|
void CDRewardCodesTable::LoadValuesFromDatabase() {
|
||||||
|
|
||||||
|
// First, get the size of the table
|
||||||
|
unsigned int size = 0;
|
||||||
|
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM RewardCodes");
|
||||||
|
while (!tableSize.eof()) {
|
||||||
|
size = tableSize.getIntField(0, 0);
|
||||||
|
|
||||||
|
tableSize.nextRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
tableSize.finalize();
|
||||||
|
|
||||||
|
// Reserve the size
|
||||||
|
this->entries.reserve(size);
|
||||||
|
|
||||||
|
// Now get the data
|
||||||
|
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM RewardCodes");
|
||||||
|
while (!tableData.eof()) {
|
||||||
|
CDRewardCode entry;
|
||||||
|
entry.id = tableData.getIntField("id", -1);
|
||||||
|
entry.code = tableData.getStringField("code", "");
|
||||||
|
entry.attachmentLOT = tableData.getIntField("attachmentLOT", -1);
|
||||||
|
UNUSED_COLUMN(entry.locStatus = tableData.getIntField("locStatus", -1));
|
||||||
|
UNUSED_COLUMN(entry.gate_version = tableData.getStringField("gate_version", ""));
|
||||||
|
|
||||||
|
this->entries.push_back(entry);
|
||||||
|
tableData.nextRow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOT CDRewardCodesTable::GetAttachmentLOT(uint32_t rewardCodeId) const {
|
||||||
|
for (auto const &entry : this->entries){
|
||||||
|
if (rewardCodeId == entry.id) return entry.attachmentLOT;
|
||||||
|
}
|
||||||
|
return LOT_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t CDRewardCodesTable::GetCodeID(std::string code) const {
|
||||||
|
for (auto const &entry : this->entries){
|
||||||
|
if (code == entry.code) return entry.id;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Custom Classes
|
||||||
|
#include "CDTable.h"
|
||||||
|
|
||||||
|
|
||||||
|
struct CDRewardCode {
|
||||||
|
uint32_t id;
|
||||||
|
std::string code;
|
||||||
|
LOT attachmentLOT;
|
||||||
|
UNUSED(uint32_t locStatus);
|
||||||
|
UNUSED(std::string gate_version);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CDRewardCodesTable : public CDTable<CDRewardCodesTable> {
|
||||||
|
private:
|
||||||
|
std::vector<CDRewardCode> entries;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void LoadValuesFromDatabase();
|
||||||
|
const std::vector<CDRewardCode>& GetEntries() const;
|
||||||
|
LOT GetAttachmentLOT(uint32_t rewardCodeId) const;
|
||||||
|
uint32_t GetCodeID(std::string code) const;
|
||||||
|
};
|
@ -31,6 +31,7 @@ set(DDATABASE_CDCLIENTDATABASE_CDCLIENTTABLES_SOURCES "CDActivitiesTable.cpp"
|
|||||||
"CDRailActivatorComponent.cpp"
|
"CDRailActivatorComponent.cpp"
|
||||||
"CDRarityTableTable.cpp"
|
"CDRarityTableTable.cpp"
|
||||||
"CDRebuildComponentTable.cpp"
|
"CDRebuildComponentTable.cpp"
|
||||||
|
"CDRewardCodesTable.cpp"
|
||||||
"CDRewardsTable.cpp"
|
"CDRewardsTable.cpp"
|
||||||
"CDScriptComponentTable.cpp"
|
"CDScriptComponentTable.cpp"
|
||||||
"CDSkillBehaviorTable.cpp"
|
"CDSkillBehaviorTable.cpp"
|
||||||
|
@ -23,6 +23,9 @@
|
|||||||
#include "IActivityLog.h"
|
#include "IActivityLog.h"
|
||||||
#include "IGuilds.h"
|
#include "IGuilds.h"
|
||||||
#include "IGuildMembers.h"
|
#include "IGuildMembers.h"
|
||||||
|
#include "IIgnoreList.h"
|
||||||
|
#include "IAccountsRewardCodes.h"
|
||||||
|
|
||||||
namespace sql {
|
namespace sql {
|
||||||
class Statement;
|
class Statement;
|
||||||
class PreparedStatement;
|
class PreparedStatement;
|
||||||
@ -39,7 +42,9 @@ class GameDatabase :
|
|||||||
public IMail, public ICommandLog, public IPlayerCheatDetections, public IBugReports,
|
public IMail, public ICommandLog, public IPlayerCheatDetections, public IBugReports,
|
||||||
public IPropertyContents, public IProperty, public IPetNames, public ICharXml,
|
public IPropertyContents, public IProperty, public IPetNames, public ICharXml,
|
||||||
public IMigrationHistory, public IUgc, public IFriends, public ICharInfo,
|
public IMigrationHistory, public IUgc, public IFriends, public ICharInfo,
|
||||||
public IAccounts, public IActivityLog, public IGuilds, public IGuildMembers {
|
public IAccounts, public IActivityLog, public IAccountsRewardCodes, public IIgnoreList,
|
||||||
|
public IGuilds, public IGuildMembers {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~GameDatabase() = default;
|
virtual ~GameDatabase() = default;
|
||||||
// TODO: These should be made private.
|
// TODO: These should be made private.
|
||||||
|
13
dDatabase/GameDatabase/ITables/IAccountsRewardCodes.h
Normal file
13
dDatabase/GameDatabase/ITables/IAccountsRewardCodes.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef __IACCOUNTSREWARDCODES__H__
|
||||||
|
#define __IACCOUNTSREWARDCODES__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class IAccountsRewardCodes {
|
||||||
|
public:
|
||||||
|
virtual void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) = 0;
|
||||||
|
virtual std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__IACCOUNTSREWARDCODES__H__
|
20
dDatabase/GameDatabase/ITables/IIgnoreList.h
Normal file
20
dDatabase/GameDatabase/ITables/IIgnoreList.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef __IIGNORELIST__H__
|
||||||
|
#define __IIGNORELIST__H__
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class IIgnoreList {
|
||||||
|
public:
|
||||||
|
struct Info {
|
||||||
|
std::string name;
|
||||||
|
uint32_t id;
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual std::vector<Info> GetIgnoreList(const uint32_t playerId) = 0;
|
||||||
|
virtual void AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) = 0;
|
||||||
|
virtual void RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //!__IIGNORELIST__H__
|
@ -103,6 +103,11 @@ public:
|
|||||||
std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) override;
|
std::optional<uint32_t> GetDonationTotal(const uint32_t activityId) override;
|
||||||
std::optional<bool> IsPlaykeyActive(const int32_t playkeyId) override;
|
std::optional<bool> IsPlaykeyActive(const int32_t playkeyId) override;
|
||||||
std::vector<IUgc::Model> GetUgcModels(const LWOOBJID& propertyId) override;
|
std::vector<IUgc::Model> GetUgcModels(const LWOOBJID& propertyId) override;
|
||||||
|
void AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
|
||||||
|
void RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) override;
|
||||||
|
std::vector<IIgnoreList::Info> GetIgnoreList(const uint32_t playerId) override;
|
||||||
|
void InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) override;
|
||||||
|
std::vector<uint32_t> GetRewardCodesByAccountID(const uint32_t account_id) override;
|
||||||
std::optional<IGuilds::Guild> CreateGuild(const std::string_view name, const int32_t owner_id, const uint64_t reputation) override;
|
std::optional<IGuilds::Guild> CreateGuild(const std::string_view name, const int32_t owner_id, const uint64_t reputation) override;
|
||||||
std::optional<IGuilds::Guild> GetGuild(const uint32_t guild_id) override;
|
std::optional<IGuilds::Guild> GetGuild(const uint32_t guild_id) override;
|
||||||
std::optional<IGuilds::Guild> GetGuildByName(const std::string_view name) override;
|
std::optional<IGuilds::Guild> GetGuildByName(const std::string_view name) override;
|
||||||
|
17
dDatabase/GameDatabase/MySQL/Tables/AccountsRewardCodes.cpp
Normal file
17
dDatabase/GameDatabase/MySQL/Tables/AccountsRewardCodes.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#include "MySQLDatabase.h"
|
||||||
|
|
||||||
|
void MySQLDatabase::InsertRewardCode(const uint32_t account_id, const uint32_t reward_code) {
|
||||||
|
ExecuteInsert("INSERT IGNORE INTO accounts_rewardcodes (account_id, rewardcode) VALUES (?, ?);", account_id, reward_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint32_t> MySQLDatabase::GetRewardCodesByAccountID(const uint32_t account_id) {
|
||||||
|
auto result = ExecuteSelect("SELECT rewardcode FROM accounts_rewardcodes WHERE account_id = ?;", account_id);
|
||||||
|
|
||||||
|
std::vector<uint32_t> toReturn;
|
||||||
|
toReturn.reserve(result->rowsCount());
|
||||||
|
while (result->next()) {
|
||||||
|
toReturn.push_back(result->getUInt("rewardcode"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return toReturn;
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES
|
set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES
|
||||||
"Accounts.cpp"
|
"Accounts.cpp"
|
||||||
|
"AccountsRewardCodes.cpp"
|
||||||
"ActivityLog.cpp"
|
"ActivityLog.cpp"
|
||||||
"BugReports.cpp"
|
"BugReports.cpp"
|
||||||
"CharInfo.cpp"
|
"CharInfo.cpp"
|
||||||
@ -8,6 +9,7 @@ set(DDATABASES_DATABASES_MYSQL_TABLES_SOURCES
|
|||||||
"Friends.cpp"
|
"Friends.cpp"
|
||||||
"Guilds.cpp"
|
"Guilds.cpp"
|
||||||
"GuildMembers.cpp"
|
"GuildMembers.cpp"
|
||||||
|
"IgnoreList.cpp"
|
||||||
"Leaderboard.cpp"
|
"Leaderboard.cpp"
|
||||||
"Mail.cpp"
|
"Mail.cpp"
|
||||||
"MigrationHistory.cpp"
|
"MigrationHistory.cpp"
|
||||||
|
22
dDatabase/GameDatabase/MySQL/Tables/IgnoreList.cpp
Normal file
22
dDatabase/GameDatabase/MySQL/Tables/IgnoreList.cpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "MySQLDatabase.h"
|
||||||
|
|
||||||
|
std::vector<IIgnoreList::Info> MySQLDatabase::GetIgnoreList(const uint32_t playerId) {
|
||||||
|
auto result = ExecuteSelect("SELECT ci.name AS name, il.ignored_player_id AS ignore_id FROM ignore_list AS il JOIN charinfo AS ci ON il.ignored_player_id = ci.id WHERE il.player_id = ?", playerId);
|
||||||
|
|
||||||
|
std::vector<IIgnoreList::Info> ignoreList;
|
||||||
|
|
||||||
|
ignoreList.reserve(result->rowsCount());
|
||||||
|
while (result->next()) {
|
||||||
|
ignoreList.push_back(IIgnoreList::Info{ result->getString("name").c_str(), result->getUInt("ignore_id") });
|
||||||
|
}
|
||||||
|
|
||||||
|
return ignoreList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySQLDatabase::AddIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
|
||||||
|
ExecuteInsert("INSERT IGNORE INTO ignore_list (player_id, ignored_player_id) VALUES (?, ?)", playerId, ignoredPlayerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MySQLDatabase::RemoveIgnore(const uint32_t playerId, const uint32_t ignoredPlayerId) {
|
||||||
|
ExecuteDelete("DELETE FROM ignore_list WHERE player_id = ? AND ignored_player_id = ?", playerId, ignoredPlayerId);
|
||||||
|
}
|
@ -554,6 +554,12 @@ void Entity::Initialize() {
|
|||||||
Loot::CacheMatrix(activityID);
|
Loot::CacheMatrix(activityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const auto timeBeforeSmash = GetVar<float>(u"tmeSmsh");
|
||||||
|
|
||||||
|
if (timeBeforeSmash > 0) {
|
||||||
|
rebuildComponent->SetTimeBeforeSmash(timeBeforeSmash);
|
||||||
|
}
|
||||||
|
|
||||||
const auto compTime = GetVar<float>(u"compTime");
|
const auto compTime = GetVar<float>(u"compTime");
|
||||||
|
|
||||||
if (compTime > 0) {
|
if (compTime > 0) {
|
||||||
@ -1503,7 +1509,7 @@ void Entity::Smash(const LWOOBJID source, const eKillType killType, const std::u
|
|||||||
destroyableComponent->Smash(source, killType, deathType);
|
destroyableComponent->Smash(source, killType, deathType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Entity::Kill(Entity* murderer) {
|
void Entity::Kill(Entity* murderer, const eKillType killType) {
|
||||||
if (!m_PlayerIsReadyForUpdates) return;
|
if (!m_PlayerIsReadyForUpdates) return;
|
||||||
|
|
||||||
for (const auto& cb : m_DieCallbacks) {
|
for (const auto& cb : m_DieCallbacks) {
|
||||||
@ -1527,7 +1533,7 @@ void Entity::Kill(Entity* murderer) {
|
|||||||
bool waitForDeathAnimation = false;
|
bool waitForDeathAnimation = false;
|
||||||
|
|
||||||
if (destroyableComponent) {
|
if (destroyableComponent) {
|
||||||
waitForDeathAnimation = destroyableComponent->GetDeathBehavior() == 0;
|
waitForDeathAnimation = destroyableComponent->GetDeathBehavior() == 0 && killType != eKillType::SILENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Live waited a hard coded 12 seconds for death animations of type 0 before networking destruction!
|
// Live waited a hard coded 12 seconds for death animations of type 0 before networking destruction!
|
||||||
|
@ -210,7 +210,7 @@ public:
|
|||||||
void RequestActivityExit(Entity* sender, LWOOBJID player, bool canceled);
|
void RequestActivityExit(Entity* sender, LWOOBJID player, bool canceled);
|
||||||
|
|
||||||
void Smash(const LWOOBJID source = LWOOBJID_EMPTY, const eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"");
|
void Smash(const LWOOBJID source = LWOOBJID_EMPTY, const eKillType killType = eKillType::VIOLENT, const std::u16string& deathType = u"");
|
||||||
void Kill(Entity* murderer = nullptr);
|
void Kill(Entity* murderer = nullptr, const eKillType killType = eKillType::SILENT);
|
||||||
void AddRebuildCompleteCallback(const std::function<void(Entity* user)>& callback) const;
|
void AddRebuildCompleteCallback(const std::function<void(Entity* user)>& callback) const;
|
||||||
void AddCollisionPhantomCallback(const std::function<void(Entity* target)>& callback);
|
void AddCollisionPhantomCallback(const std::function<void(Entity* target)>& callback);
|
||||||
void AddDieCallback(const std::function<void()>& callback);
|
void AddDieCallback(const std::function<void()>& callback);
|
||||||
|
@ -207,7 +207,7 @@ void UserManager::RequestCharacterList(const SystemAddress& sysAddr) {
|
|||||||
chars[i]->SaveXMLToDatabase();
|
chars[i]->SaveXMLToDatabase();
|
||||||
|
|
||||||
chars[i]->GetEntity()->SetCharacter(nullptr);
|
chars[i]->GetEntity()->SetCharacter(nullptr);
|
||||||
|
|
||||||
delete chars[i];
|
delete chars[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,60 +275,58 @@ void UserManager::CreateCharacter(const SystemAddress& sysAddr, Packet* packet)
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::stringstream xml;
|
std::stringstream xml;
|
||||||
xml << "<obj v=\"1\"><mf hc=\"" << hairColor << "\" hs=\"" << hairStyle << "\" hd=\"0\" t=\"" << shirtColor << "\" l=\"" << pantsColor;
|
xml << "<obj v=\"1\">";
|
||||||
|
|
||||||
|
xml << "<mf hc=\"" << hairColor << "\" hs=\"" << hairStyle << "\" hd=\"0\" t=\"" << shirtColor << "\" l=\"" << pantsColor;
|
||||||
xml << "\" hdc=\"0\" cd=\"" << shirtStyle << "\" lh=\"" << lh << "\" rh=\"" << rh << "\" es=\"" << eyebrows << "\" ";
|
xml << "\" hdc=\"0\" cd=\"" << shirtStyle << "\" lh=\"" << lh << "\" rh=\"" << rh << "\" es=\"" << eyebrows << "\" ";
|
||||||
xml << "ess=\"" << eyes << "\" ms=\"" << mouth << "\"/>";
|
xml << "ess=\"" << eyes << "\" ms=\"" << mouth << "\"/>";
|
||||||
|
|
||||||
xml << "<char acct=\"" << u->GetAccountID() << "\" cc=\"0\" gm=\"0\" ft=\"0\" llog=\"" << time(NULL) << "\" ";
|
xml << "<char acct=\"" << u->GetAccountID() << "\" cc=\"0\" gm=\"0\" ft=\"0\" llog=\"" << time(NULL) << "\" ";
|
||||||
xml << "ls=\"0\" lzx=\"-626.5847\" lzy=\"613.3515\" lzz=\"-28.6374\" lzrx=\"0.0\" lzry=\"0.7015\" lzrz=\"0.0\" lzrw=\"0.7126\" ";
|
xml << "ls=\"0\" lzx=\"-626.5847\" lzy=\"613.3515\" lzz=\"-28.6374\" lzrx=\"0.0\" lzry=\"0.7015\" lzrz=\"0.0\" lzrw=\"0.7126\" ";
|
||||||
xml << "stt=\"0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;\"></char>";
|
xml << "stt=\"0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;\"></char>";
|
||||||
|
|
||||||
xml << "<dest hm=\"4\" hc=\"4\" im=\"0\" ic=\"0\" am=\"0\" ac=\"0\" d=\"0\"/>";
|
xml << "<dest hm=\"4\" hc=\"4\" im=\"0\" ic=\"0\" am=\"0\" ac=\"0\" d=\"0\"/>";
|
||||||
|
|
||||||
xml << "<inv><bag><b t=\"0\" m=\"20\"/><b t=\"1\" m=\"40\"/><b t=\"2\" m=\"240\"/><b t=\"3\" m=\"240\"/><b t=\"14\" m=\"40\"/></bag><items><in t=\"0\">";
|
xml << "<inv><bag><b t=\"0\" m=\"20\"/><b t=\"1\" m=\"40\"/><b t=\"2\" m=\"240\"/><b t=\"3\" m=\"240\"/><b t=\"14\" m=\"40\"/></bag><items><in t=\"0\">";
|
||||||
std::string xmlSave1 = xml.str();
|
|
||||||
|
|
||||||
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t idforshirt) {
|
LWOOBJID lwoidforshirt = ObjectIDManager::GenerateRandomObjectID();
|
||||||
std::stringstream xml2;
|
LWOOBJID lwoidforpants;
|
||||||
|
|
||||||
LWOOBJID lwoidforshirt = idforshirt;
|
do {
|
||||||
GeneralUtils::SetBit(lwoidforshirt, eObjectBits::CHARACTER);
|
lwoidforpants = ObjectIDManager::GenerateRandomObjectID();
|
||||||
GeneralUtils::SetBit(lwoidforshirt, eObjectBits::PERSISTENT);
|
} while (lwoidforpants == lwoidforshirt); //Make sure we don't have the same ID for both shirt and pants
|
||||||
xml2 << xmlSave1 << "<i l=\"" << shirtLOT << "\" id=\"" << lwoidforshirt << "\" s=\"0\" c=\"1\" eq=\"1\" b=\"1\"/>";
|
|
||||||
|
|
||||||
std::string xmlSave2 = xml2.str();
|
GeneralUtils::SetBit(lwoidforshirt, eObjectBits::CHARACTER);
|
||||||
|
GeneralUtils::SetBit(lwoidforshirt, eObjectBits::PERSISTENT);
|
||||||
|
GeneralUtils::SetBit(lwoidforpants, eObjectBits::CHARACTER);
|
||||||
|
GeneralUtils::SetBit(lwoidforpants, eObjectBits::PERSISTENT);
|
||||||
|
|
||||||
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t idforpants) {
|
xml << "<i l=\"" << shirtLOT << "\" id=\"" << lwoidforshirt << "\" s=\"0\" c=\"1\" eq=\"1\" b=\"1\"/>";
|
||||||
LWOOBJID lwoidforpants = idforpants;
|
xml << "<i l=\"" << pantsLOT << "\" id=\"" << lwoidforpants << "\" s=\"1\" c=\"1\" eq=\"1\" b=\"1\"/>";
|
||||||
GeneralUtils::SetBit(lwoidforpants, eObjectBits::CHARACTER);
|
|
||||||
GeneralUtils::SetBit(lwoidforpants, eObjectBits::PERSISTENT);
|
|
||||||
|
|
||||||
std::stringstream xml3;
|
xml << "</in></items></inv><lvl l=\"1\" cv=\"1\" sb=\"500\"/><flag></flag></obj>";
|
||||||
xml3 << xmlSave2 << "<i l=\"" << pantsLOT << "\" id=\"" << lwoidforpants << "\" s=\"1\" c=\"1\" eq=\"1\" b=\"1\"/>";
|
|
||||||
|
|
||||||
xml3 << "</in></items></inv><lvl l=\"1\" cv=\"1\" sb=\"500\"/><flag></flag></obj>";
|
//Check to see if our name was pre-approved:
|
||||||
|
bool nameOk = IsNamePreapproved(name);
|
||||||
|
if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
|
||||||
|
|
||||||
//Check to see if our name was pre-approved:
|
std::string_view nameToAssign = !name.empty() && nameOk ? name : predefinedName;
|
||||||
bool nameOk = IsNamePreapproved(name);
|
std::string pendingName = !name.empty() && !nameOk ? name : "";
|
||||||
if (!nameOk && u->GetMaxGMLevel() > eGameMasterLevel::FORUM_MODERATOR) nameOk = true;
|
|
||||||
|
|
||||||
std::string_view nameToAssign = !name.empty() && nameOk ? name : predefinedName;
|
ICharInfo::Info info;
|
||||||
std::string pendingName = !name.empty() && !nameOk ? name : "";
|
info.name = nameToAssign;
|
||||||
|
info.pendingName = pendingName;
|
||||||
|
info.id = objectID;
|
||||||
|
info.accountId = u->GetAccountID();
|
||||||
|
|
||||||
ICharInfo::Info info;
|
Database::Get()->InsertNewCharacter(info);
|
||||||
info.name = nameToAssign;
|
|
||||||
info.pendingName = pendingName;
|
|
||||||
info.id = objectID;
|
|
||||||
info.accountId = u->GetAccountID();
|
|
||||||
|
|
||||||
Database::Get()->InsertNewCharacter(info);
|
//Now finally insert our character xml:
|
||||||
|
Database::Get()->InsertCharacterXml(objectID, xml.str());
|
||||||
|
|
||||||
//Now finally insert our character xml:
|
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::SUCCESS);
|
||||||
Database::Get()->InsertCharacterXml(objectID, xml3.str());
|
UserManager::RequestCharacterList(sysAddr);
|
||||||
|
});
|
||||||
WorldPackets::SendCharacterCreationResponse(sysAddr, eCharacterCreationResponse::SUCCESS);
|
|
||||||
UserManager::RequestCharacterList(sysAddr);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet) {
|
void UserManager::DeleteCharacter(const SystemAddress& sysAddr, Packet* packet) {
|
||||||
@ -466,16 +464,18 @@ void UserManager::LoginCharacter(const SystemAddress& sysAddr, uint32_t playerID
|
|||||||
|
|
||||||
uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) {
|
uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) {
|
||||||
try {
|
try {
|
||||||
std::string shirtQuery = "select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == \"character create shirt\" AND icc.color1 == ";
|
auto stmt = CDClientDatabase::CreatePreppedStmt(
|
||||||
shirtQuery += std::to_string(shirtColor);
|
"select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ? AND icc.decal == ?"
|
||||||
shirtQuery += " AND icc.decal == ";
|
);
|
||||||
shirtQuery = shirtQuery + std::to_string(shirtStyle);
|
stmt.bind(1, "character create shirt");
|
||||||
auto tableData = CDClientDatabase::ExecuteQuery(shirtQuery);
|
stmt.bind(2, static_cast<int>(shirtColor));
|
||||||
auto shirtLOT = tableData.getIntField(0, -1);
|
stmt.bind(3, static_cast<int>(shirtStyle));
|
||||||
|
auto tableData = stmt.execQuery();
|
||||||
|
auto shirtLOT = tableData.getIntField(0, 4069);
|
||||||
tableData.finalize();
|
tableData.finalize();
|
||||||
return shirtLOT;
|
return shirtLOT;
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception& ex) {
|
||||||
LOG("Failed to execute query! Using backup...");
|
LOG("Could not look up shirt %i %i: %s", shirtColor, shirtStyle, ex.what());
|
||||||
// in case of no shirt found in CDServer, return problematic red vest.
|
// in case of no shirt found in CDServer, return problematic red vest.
|
||||||
return 4069;
|
return 4069;
|
||||||
}
|
}
|
||||||
@ -483,14 +483,17 @@ uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) {
|
|||||||
|
|
||||||
uint32_t FindCharPantsID(uint32_t pantsColor) {
|
uint32_t FindCharPantsID(uint32_t pantsColor) {
|
||||||
try {
|
try {
|
||||||
std::string pantsQuery = "select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == \"cc pants\" AND icc.color1 == ";
|
auto stmt = CDClientDatabase::CreatePreppedStmt(
|
||||||
pantsQuery += std::to_string(pantsColor);
|
"select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ?"
|
||||||
auto tableData = CDClientDatabase::ExecuteQuery(pantsQuery);
|
);
|
||||||
auto pantsLOT = tableData.getIntField(0, -1);
|
stmt.bind(1, "cc pants");
|
||||||
|
stmt.bind(2, static_cast<int>(pantsColor));
|
||||||
|
auto tableData = stmt.execQuery();
|
||||||
|
auto pantsLOT = tableData.getIntField(0, 2508);
|
||||||
tableData.finalize();
|
tableData.finalize();
|
||||||
return pantsLOT;
|
return pantsLOT;
|
||||||
} catch (const std::exception&) {
|
} catch (const std::exception& ex) {
|
||||||
LOG("Failed to execute query! Using backup...");
|
LOG("Could not look up pants %i: %s", pantsColor, ex.what());
|
||||||
// in case of no pants color found in CDServer, return red pants.
|
// in case of no pants color found in CDServer, return red pants.
|
||||||
return 2508;
|
return 2508;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,10 @@
|
|||||||
#include "Amf3.h"
|
#include "Amf3.h"
|
||||||
#include "eGameMasterLevel.h"
|
#include "eGameMasterLevel.h"
|
||||||
#include "eGameActivity.h"
|
#include "eGameActivity.h"
|
||||||
|
#include "User.h"
|
||||||
|
#include "Database.h"
|
||||||
|
#include "CDRewardCodesTable.h"
|
||||||
|
#include "Mail.h"
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
#include "eObjectBits.h"
|
#include "eObjectBits.h"
|
||||||
@ -77,10 +81,14 @@ CharacterComponent::~CharacterComponent() {
|
|||||||
void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
void CharacterComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||||
|
|
||||||
if (bIsInitialUpdate) {
|
if (bIsInitialUpdate) {
|
||||||
outBitStream->Write0();
|
outBitStream->Write(m_ClaimCodes[0] != 0);
|
||||||
outBitStream->Write0();
|
if (m_ClaimCodes[0] != 0) outBitStream->Write(m_ClaimCodes[0]);
|
||||||
outBitStream->Write0();
|
outBitStream->Write(m_ClaimCodes[1] != 0);
|
||||||
outBitStream->Write0();
|
if (m_ClaimCodes[1] != 0) outBitStream->Write(m_ClaimCodes[1]);
|
||||||
|
outBitStream->Write(m_ClaimCodes[2] != 0);
|
||||||
|
if (m_ClaimCodes[2] != 0) outBitStream->Write(m_ClaimCodes[2]);
|
||||||
|
outBitStream->Write(m_ClaimCodes[3] != 0);
|
||||||
|
if (m_ClaimCodes[3] != 0) outBitStream->Write(m_ClaimCodes[3]);
|
||||||
|
|
||||||
outBitStream->Write(m_Character->GetHairColor());
|
outBitStream->Write(m_Character->GetHairColor());
|
||||||
outBitStream->Write(m_Character->GetHairStyle());
|
outBitStream->Write(m_Character->GetHairStyle());
|
||||||
@ -200,6 +208,13 @@ void CharacterComponent::LoadFromXml(tinyxml2::XMLDocument* doc) {
|
|||||||
SetReputation(0);
|
SetReputation(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
character->QueryUnsigned64Attribute("co", &m_ClaimCodes[0]);
|
||||||
|
character->QueryUnsigned64Attribute("co1", &m_ClaimCodes[1]);
|
||||||
|
character->QueryUnsigned64Attribute("co2", &m_ClaimCodes[2]);
|
||||||
|
character->QueryUnsigned64Attribute("co3", &m_ClaimCodes[3]);
|
||||||
|
|
||||||
|
AwardClaimCodes();
|
||||||
|
|
||||||
character->QueryInt64Attribute("ls", &m_Uscore);
|
character->QueryInt64Attribute("ls", &m_Uscore);
|
||||||
|
|
||||||
// Load the statistics
|
// Load the statistics
|
||||||
@ -324,6 +339,11 @@ void CharacterComponent::UpdateXml(tinyxml2::XMLDocument* doc) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_ClaimCodes[0] != 0) character->SetAttribute("co", m_ClaimCodes[0]);
|
||||||
|
if (m_ClaimCodes[1] != 0) character->SetAttribute("co1", m_ClaimCodes[1]);
|
||||||
|
if (m_ClaimCodes[2] != 0) character->SetAttribute("co2", m_ClaimCodes[2]);
|
||||||
|
if (m_ClaimCodes[3] != 0) character->SetAttribute("co3", m_ClaimCodes[3]);
|
||||||
|
|
||||||
character->SetAttribute("ls", m_Uscore);
|
character->SetAttribute("ls", m_Uscore);
|
||||||
// Custom attribute to keep track of reputation.
|
// Custom attribute to keep track of reputation.
|
||||||
character->SetAttribute("rpt", GetReputation());
|
character->SetAttribute("rpt", GetReputation());
|
||||||
@ -760,4 +780,30 @@ void CharacterComponent::UpdateClientMinimap(bool showFaction, std::string ventu
|
|||||||
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent ? m_Parent->GetSystemAddress() : UNASSIGNED_SYSTEM_ADDRESS, "SetFactionVisibility", arrayToSend);
|
GameMessages::SendUIMessageServerToSingleClient(m_Parent, m_Parent ? m_Parent->GetSystemAddress() : UNASSIGNED_SYSTEM_ADDRESS, "SetFactionVisibility", arrayToSend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CharacterComponent::AwardClaimCodes() {
|
||||||
|
if (!m_Parent) return;
|
||||||
|
auto* user = m_Parent->GetParentUser();
|
||||||
|
if (!user) return;
|
||||||
|
|
||||||
|
auto rewardCodes = Database::Get()->GetRewardCodesByAccountID(user->GetAccountID());
|
||||||
|
if (rewardCodes.empty()) return;
|
||||||
|
|
||||||
|
auto* cdrewardCodes = CDClientManager::Instance().GetTable<CDRewardCodesTable>();
|
||||||
|
for (auto const rewardCode: rewardCodes){
|
||||||
|
LOG_DEBUG("Processing RewardCode %i", rewardCode);
|
||||||
|
const uint32_t rewardCodeIndex = rewardCode >> 6;
|
||||||
|
const uint32_t bitIndex = rewardCode % 64;
|
||||||
|
if (GeneralUtils::CheckBit(m_ClaimCodes[rewardCodeIndex], bitIndex)) continue;
|
||||||
|
m_ClaimCodes[rewardCodeIndex] = GeneralUtils::SetBit(m_ClaimCodes[rewardCodeIndex], bitIndex);
|
||||||
|
|
||||||
|
// Don't send it on this one since it's default and the mail doesn't make sense
|
||||||
|
if (rewardCode == 30) continue;
|
||||||
|
|
||||||
|
auto attachmentLOT = cdrewardCodes->GetAttachmentLOT(rewardCode);
|
||||||
|
std::ostringstream subject;
|
||||||
|
subject << "%[RewardCodes_" << rewardCode << "_subjectText]";
|
||||||
|
std::ostringstream body;
|
||||||
|
body << "%[RewardCodes_" << rewardCode << "_bodyText]";
|
||||||
|
Mail::SendMail(LWOOBJID_EMPTY, "%[MAIL_SYSTEM_NOTIFICATION]", m_Parent, subject.str(), body.str(), attachmentLOT, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "CDMissionsTable.h"
|
#include "CDMissionsTable.h"
|
||||||
#include "tinyxml2.h"
|
#include "tinyxml2.h"
|
||||||
#include "eReplicaComponentType.h"
|
#include "eReplicaComponentType.h"
|
||||||
|
#include <array>
|
||||||
|
|
||||||
enum class eGameActivity : uint32_t;
|
enum class eGameActivity : uint32_t;
|
||||||
|
|
||||||
@ -586,6 +587,10 @@ private:
|
|||||||
LWOOBJID m_LastRocketItemID = LWOOBJID_EMPTY;
|
LWOOBJID m_LastRocketItemID = LWOOBJID_EMPTY;
|
||||||
|
|
||||||
LWOOBJID m_CurrentInteracting = LWOOBJID_EMPTY;
|
LWOOBJID m_CurrentInteracting = LWOOBJID_EMPTY;
|
||||||
|
|
||||||
|
std::array<uint64_t, 4> m_ClaimCodes{};
|
||||||
|
|
||||||
|
void AwardClaimCodes();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CHARACTERCOMPONENT_H
|
#endif // CHARACTERCOMPONENT_H
|
||||||
|
@ -796,7 +796,7 @@ void DestroyableComponent::Smash(const LWOOBJID source, const eKillType killType
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Parent->Kill(owner);
|
m_Parent->Kill(owner, killType);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyableComponent::SetFaction(int32_t factionID, bool ignoreChecks) {
|
void DestroyableComponent::SetFaction(int32_t factionID, bool ignoreChecks) {
|
||||||
|
@ -402,10 +402,10 @@ void PhantomPhysicsComponent::SetDirection(const NiPoint3& pos) {
|
|||||||
void PhantomPhysicsComponent::SpawnVertices() {
|
void PhantomPhysicsComponent::SpawnVertices() {
|
||||||
if (!m_dpEntity) return;
|
if (!m_dpEntity) return;
|
||||||
|
|
||||||
std::cout << m_Parent->GetObjectID() << std::endl;
|
LOG("%llu", m_Parent->GetObjectID());
|
||||||
auto box = static_cast<dpShapeBox*>(m_dpEntity->GetShape());
|
auto box = static_cast<dpShapeBox*>(m_dpEntity->GetShape());
|
||||||
for (auto vert : box->GetVertices()) {
|
for (auto vert : box->GetVertices()) {
|
||||||
std::cout << vert.x << ", " << vert.y << ", " << vert.z << std::endl;
|
LOG("%f, %f, %f", vert.x, vert.y, vert.z);
|
||||||
|
|
||||||
EntityInfo info;
|
EntityInfo info;
|
||||||
info.lot = 33;
|
info.lot = 33;
|
||||||
|
@ -51,7 +51,7 @@ RacingControlComponent::RacingControlComponent(Entity* parent)
|
|||||||
|
|
||||||
m_MainWorld = 1200;
|
m_MainWorld = 1200;
|
||||||
const auto worldID = Game::server->GetZoneID();
|
const auto worldID = Game::server->GetZoneID();
|
||||||
if (Game::zoneManager->CheckIfAccessibleZone((worldID/10)*10)) m_MainWorld = (worldID/10)*10;
|
if (Game::zoneManager->CheckIfAccessibleZone((worldID / 10) * 10)) m_MainWorld = (worldID / 10) * 10;
|
||||||
|
|
||||||
m_ActivityID = 42;
|
m_ActivityID = 42;
|
||||||
CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
|
CDActivitiesTable* activitiesTable = CDClientManager::Instance().GetTable<CDActivitiesTable>();
|
||||||
@ -72,7 +72,7 @@ void RacingControlComponent::OnPlayerLoaded(Entity* player) {
|
|||||||
// If the race has already started, send the player back to the main world.
|
// If the race has already started, send the player back to the main world.
|
||||||
if (m_Loaded || !vehicle) {
|
if (m_Loaded || !vehicle) {
|
||||||
auto* playerInstance = dynamic_cast<Player*>(player);
|
auto* playerInstance = dynamic_cast<Player*>(player);
|
||||||
if(playerInstance){
|
if (playerInstance) {
|
||||||
playerInstance->SendToZone(m_MainWorld);
|
playerInstance->SendToZone(m_MainWorld);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -106,12 +106,12 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
|
|||||||
if (item == nullptr) {
|
if (item == nullptr) {
|
||||||
LOG("Failed to find item");
|
LOG("Failed to find item");
|
||||||
auto* playerInstance = dynamic_cast<Player*>(player);
|
auto* playerInstance = dynamic_cast<Player*>(player);
|
||||||
if(playerInstance){
|
if (playerInstance) {
|
||||||
m_LoadedPlayers--;
|
m_LoadedPlayers--;
|
||||||
playerInstance->SendToZone(m_MainWorld);
|
playerInstance->SendToZone(m_MainWorld);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate the vehicle's starting position.
|
// Calculate the vehicle's starting position.
|
||||||
@ -213,6 +213,7 @@ void RacingControlComponent::LoadPlayerVehicle(Entity* player,
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0 });
|
0 });
|
||||||
|
m_AllPlayersReady = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct and serialize everything when done.
|
// Construct and serialize everything when done.
|
||||||
@ -330,7 +331,7 @@ void RacingControlComponent::OnRequestDie(Entity* player) {
|
|||||||
// Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live.
|
// Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live.
|
||||||
if (destroyableComponent) destroyableComponent->SetImagination(respawnImagination);
|
if (destroyableComponent) destroyableComponent->SetImagination(respawnImagination);
|
||||||
Game::entityManager->SerializeEntity(vehicle);
|
Game::entityManager->SerializeEntity(vehicle);
|
||||||
});
|
});
|
||||||
|
|
||||||
auto* characterComponent = player->GetComponent<CharacterComponent>();
|
auto* characterComponent = player->GetComponent<CharacterComponent>();
|
||||||
if (characterComponent != nullptr) {
|
if (characterComponent != nullptr) {
|
||||||
@ -384,11 +385,11 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player, int32_t bu
|
|||||||
|
|
||||||
// Calculate the score, different loot depending on player count
|
// Calculate the score, different loot depending on player count
|
||||||
auto playersRating = m_LoadedPlayers;
|
auto playersRating = m_LoadedPlayers;
|
||||||
if(m_LoadedPlayers == 1 && m_SoloRacing) {
|
if (m_LoadedPlayers == 1 && m_SoloRacing) {
|
||||||
playersRating *= 2;
|
playersRating *= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto score = playersRating * 10 + data->finished;
|
const auto score = playersRating * 10 + data->finished;
|
||||||
Loot::GiveActivityLoot(player, m_Parent, m_ActivityID, score);
|
Loot::GiveActivityLoot(player, m_Parent, m_ActivityID, score);
|
||||||
|
|
||||||
// Giving rewards
|
// Giving rewards
|
||||||
@ -436,64 +437,82 @@ void RacingControlComponent::HandleMessageBoxResponse(Entity* player, int32_t bu
|
|||||||
|
|
||||||
void RacingControlComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
void RacingControlComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate) {
|
||||||
// BEGIN Scripted Activity
|
// BEGIN Scripted Activity
|
||||||
|
|
||||||
outBitStream->Write1();
|
outBitStream->Write1();
|
||||||
|
|
||||||
outBitStream->Write(static_cast<uint32_t>(m_RacingPlayers.size()));
|
outBitStream->Write(static_cast<uint32_t>(m_RacingPlayers.size()));
|
||||||
for (const auto& player : m_RacingPlayers) {
|
for (const auto& player : m_RacingPlayers) {
|
||||||
outBitStream->Write(player.playerID);
|
outBitStream->Write(player.playerID);
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
outBitStream->Write(player.data[0]);
|
||||||
outBitStream->Write(player.data[i]);
|
if (player.finished != 0) outBitStream->Write<float>(player.raceTime);
|
||||||
}
|
else outBitStream->Write(player.data[1]);
|
||||||
|
if (player.finished != 0) outBitStream->Write<float>(player.bestLapTime);
|
||||||
|
else outBitStream->Write(player.data[2]);
|
||||||
|
if (player.finished == 1) outBitStream->Write<float>(1.0f);
|
||||||
|
else outBitStream->Write(player.data[3]);
|
||||||
|
outBitStream->Write(player.data[4]);
|
||||||
|
outBitStream->Write(player.data[5]);
|
||||||
|
outBitStream->Write(player.data[6]);
|
||||||
|
outBitStream->Write(player.data[7]);
|
||||||
|
outBitStream->Write(player.data[8]);
|
||||||
|
outBitStream->Write(player.data[9]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// END Scripted Activity
|
// END Scripted Activity
|
||||||
|
|
||||||
outBitStream->Write1(); // Dirty?
|
outBitStream->Write1();
|
||||||
outBitStream->Write(static_cast<uint16_t>(m_RacingPlayers.size()));
|
outBitStream->Write(static_cast<uint16_t>(m_RacingPlayers.size()));
|
||||||
|
|
||||||
outBitStream->Write(!m_RacingPlayers.empty());
|
outBitStream->Write(!m_AllPlayersReady);
|
||||||
if (!m_RacingPlayers.empty()) {
|
if (!m_AllPlayersReady) {
|
||||||
|
int32_t numReady = 0;
|
||||||
for (const auto& player : m_RacingPlayers) {
|
for (const auto& player : m_RacingPlayers) {
|
||||||
outBitStream->Write1(); // Has more date
|
outBitStream->Write1(); // Has more player data
|
||||||
|
|
||||||
outBitStream->Write(player.playerID);
|
outBitStream->Write(player.playerID);
|
||||||
outBitStream->Write(player.vehicleID);
|
outBitStream->Write(player.vehicleID);
|
||||||
outBitStream->Write(player.playerIndex);
|
outBitStream->Write(player.playerIndex);
|
||||||
outBitStream->Write(player.playerLoaded);
|
outBitStream->Write(player.playerLoaded);
|
||||||
|
if (player.playerLoaded) numReady++;
|
||||||
}
|
}
|
||||||
|
|
||||||
outBitStream->Write0(); // No more data
|
outBitStream->Write0(); // No more data
|
||||||
|
if (numReady == m_RacingPlayers.size()) m_AllPlayersReady = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
outBitStream->Write(!m_RacingPlayers.empty());
|
outBitStream->Write(!m_RacingPlayers.empty());
|
||||||
if (!m_RacingPlayers.empty()) {
|
if (!m_RacingPlayers.empty()) {
|
||||||
for (const auto& player : m_RacingPlayers) {
|
for (const auto& player : m_RacingPlayers) {
|
||||||
|
if (player.finished == 0) continue;
|
||||||
outBitStream->Write1(); // Has more date
|
outBitStream->Write1(); // Has more date
|
||||||
|
|
||||||
outBitStream->Write(player.playerID);
|
outBitStream->Write(player.playerID);
|
||||||
outBitStream->Write<uint32_t>(0);
|
outBitStream->Write(player.finished);
|
||||||
}
|
}
|
||||||
|
|
||||||
outBitStream->Write0(); // No more data
|
outBitStream->Write0(); // No more data
|
||||||
}
|
}
|
||||||
|
|
||||||
outBitStream->Write1(); // Dirty?
|
outBitStream->Write(bIsInitialUpdate);
|
||||||
|
if (bIsInitialUpdate) {
|
||||||
outBitStream->Write(m_RemainingLaps);
|
outBitStream->Write(m_RemainingLaps);
|
||||||
|
outBitStream->Write(static_cast<uint16_t>(m_PathName.size()));
|
||||||
outBitStream->Write(static_cast<uint16_t>(m_PathName.size()));
|
for (const auto character : m_PathName) {
|
||||||
for (const auto character : m_PathName) {
|
outBitStream->Write(character);
|
||||||
outBitStream->Write(character);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
outBitStream->Write1(); // ???
|
outBitStream->Write(!m_RacingPlayers.empty());
|
||||||
outBitStream->Write1(); // ???
|
if (!m_RacingPlayers.empty()) {
|
||||||
|
for (const auto& player : m_RacingPlayers) {
|
||||||
|
if (player.finished == 0) continue;
|
||||||
|
outBitStream->Write1(); // Has more data
|
||||||
|
outBitStream->Write(player.playerID);
|
||||||
|
outBitStream->Write<float>(player.bestLapTime);
|
||||||
|
outBitStream->Write<float>(player.raceTime);
|
||||||
|
}
|
||||||
|
|
||||||
outBitStream->Write(m_LeadingPlayer);
|
outBitStream->Write0(); // No more data
|
||||||
outBitStream->Write(m_RaceBestLap);
|
}
|
||||||
outBitStream->Write(m_RaceBestTime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RacingPlayerInfo* RacingControlComponent::GetPlayerData(LWOOBJID playerID) {
|
RacingPlayerInfo* RacingControlComponent::GetPlayerData(LWOOBJID playerID) {
|
||||||
@ -569,7 +588,7 @@ void RacingControlComponent::Update(float deltaTime) {
|
|||||||
|
|
||||||
LoadPlayerVehicle(player, positionNumber + 1, true);
|
LoadPlayerVehicle(player, positionNumber + 1, true);
|
||||||
|
|
||||||
m_Loaded = true;
|
Game::entityManager->SerializeEntity(m_Parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Loaded = true;
|
m_Loaded = true;
|
||||||
@ -757,6 +776,8 @@ void RacingControlComponent::Update(float deltaTime) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_Finished != 0) Game::entityManager->SerializeEntity(m_Parent);
|
||||||
|
|
||||||
// Loop through all the waypoints and see if the player has reached a
|
// Loop through all the waypoints and see if the player has reached a
|
||||||
// new checkpoint
|
// new checkpoint
|
||||||
uint32_t respawnIndex = 0;
|
uint32_t respawnIndex = 0;
|
||||||
@ -849,8 +870,6 @@ void RacingControlComponent::Update(float deltaTime) {
|
|||||||
if (characterComponent != nullptr) {
|
if (characterComponent != nullptr) {
|
||||||
characterComponent->TrackRaceCompleted(m_Finished == 1);
|
characterComponent->TrackRaceCompleted(m_Finished == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Figure out how to update the GUI leaderboard.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -865,28 +884,3 @@ void RacingControlComponent::Update(float deltaTime) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RacingControlComponent::FormatTimeString(time_t time) {
|
|
||||||
int32_t min = time / 60;
|
|
||||||
time -= min * 60;
|
|
||||||
int32_t sec = time;
|
|
||||||
|
|
||||||
std::string minText;
|
|
||||||
std::string secText;
|
|
||||||
|
|
||||||
if (min <= 0) {
|
|
||||||
minText = "0";
|
|
||||||
} else {
|
|
||||||
minText = std::to_string(min);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sec <= 0) {
|
|
||||||
secText = "00";
|
|
||||||
} else if (sec <= 9) {
|
|
||||||
secText = "0" + std::to_string(sec);
|
|
||||||
} else {
|
|
||||||
secText = std::to_string(sec);
|
|
||||||
}
|
|
||||||
|
|
||||||
return minText + ":" + secText + ".00";
|
|
||||||
}
|
|
||||||
|
@ -151,13 +151,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
RacingPlayerInfo* GetPlayerData(LWOOBJID playerID);
|
RacingPlayerInfo* GetPlayerData(LWOOBJID playerID);
|
||||||
|
|
||||||
/**
|
|
||||||
* Formats a time to a string, currently unused
|
|
||||||
* @param time the time to format
|
|
||||||
* @return the time formatted as string
|
|
||||||
*/
|
|
||||||
static std::string FormatTimeString(time_t time);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -251,4 +244,5 @@ private:
|
|||||||
* Value for message box response to know if we are exiting the race via the activity dialogue
|
* Value for message box response to know if we are exiting the race via the activity dialogue
|
||||||
*/
|
*/
|
||||||
const int32_t m_ActivityExitConfirm = 1;
|
const int32_t m_ActivityExitConfirm = 1;
|
||||||
|
bool m_AllPlayersReady = false;
|
||||||
};
|
};
|
||||||
|
@ -6,6 +6,13 @@
|
|||||||
#include "eReplicaComponentType.h"
|
#include "eReplicaComponentType.h"
|
||||||
|
|
||||||
struct RemoteInputInfo {
|
struct RemoteInputInfo {
|
||||||
|
RemoteInputInfo() {
|
||||||
|
m_RemoteInputX = 0;
|
||||||
|
m_RemoteInputY = 0;
|
||||||
|
m_IsPowersliding = false;
|
||||||
|
m_IsModified = false;
|
||||||
|
}
|
||||||
|
|
||||||
void operator=(const RemoteInputInfo& other) {
|
void operator=(const RemoteInputInfo& other) {
|
||||||
m_RemoteInputX = other.m_RemoteInputX;
|
m_RemoteInputX = other.m_RemoteInputX;
|
||||||
m_RemoteInputY = other.m_RemoteInputY;
|
m_RemoteInputY = other.m_RemoteInputY;
|
||||||
|
@ -34,6 +34,8 @@
|
|||||||
#include "eMissionTaskType.h"
|
#include "eMissionTaskType.h"
|
||||||
#include "eReplicaComponentType.h"
|
#include "eReplicaComponentType.h"
|
||||||
#include "eConnectionType.h"
|
#include "eConnectionType.h"
|
||||||
|
#include "ePlayerFlag.h"
|
||||||
|
#include "dConfig.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -173,6 +175,13 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
|
|||||||
GameMessages::SendPlayerReady(entity, sysAddr);
|
GameMessages::SendPlayerReady(entity, sysAddr);
|
||||||
GameMessages::SendPlayerReady(Game::zoneManager->GetZoneControlObject(), sysAddr);
|
GameMessages::SendPlayerReady(Game::zoneManager->GetZoneControlObject(), sysAddr);
|
||||||
|
|
||||||
|
if (Game::config->GetValue("allow_players_to_skip_cinematics") != "1"
|
||||||
|
|| !entity->GetCharacter()
|
||||||
|
|| !entity->GetCharacter()->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS)) return;
|
||||||
|
entity->AddCallbackTimer(0.5f, [entity, sysAddr]() {
|
||||||
|
if (!entity) return;
|
||||||
|
GameMessages::SendEndCinematic(entity->GetObjectID(), u"", sysAddr);
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,13 +253,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
|
|||||||
|
|
||||||
case eGameMessageType::REQUEST_RESURRECT: {
|
case eGameMessageType::REQUEST_RESURRECT: {
|
||||||
GameMessages::SendResurrect(entity);
|
GameMessages::SendResurrect(entity);
|
||||||
/*auto* dest = static_cast<DestroyableComponent*>(entity->GetComponent(eReplicaComponentType::DESTROYABLE));
|
|
||||||
if (dest) {
|
|
||||||
dest->SetHealth(4);
|
|
||||||
dest->SetArmor(0);
|
|
||||||
dest->SetImagination(6);
|
|
||||||
Game::entityManager->SerializeEntity(entity);
|
|
||||||
}*/
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case eGameMessageType::GET_HOT_PROPERTY_DATA: {
|
case eGameMessageType::GET_HOT_PROPERTY_DATA: {
|
||||||
@ -339,11 +341,8 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
|
|||||||
RakNet::BitStream bitStreamLocal;
|
RakNet::BitStream bitStreamLocal;
|
||||||
BitStreamUtils::WriteHeader(bitStreamLocal, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
|
BitStreamUtils::WriteHeader(bitStreamLocal, eConnectionType::CLIENT, eClientMessageType::GAME_MSG);
|
||||||
bitStreamLocal.Write(entity->GetObjectID());
|
bitStreamLocal.Write(entity->GetObjectID());
|
||||||
//bitStreamLocal.Write((unsigned short)eGameMessageType::ECHO_SYNC_SKILL);
|
|
||||||
//bitStreamLocal.Write(inStream);
|
|
||||||
|
|
||||||
SyncSkill sync = SyncSkill(inStream); // inStream replaced &bitStream
|
SyncSkill sync = SyncSkill(inStream); // inStream replaced &bitStream
|
||||||
//sync.Serialize(&bitStreamLocal);
|
|
||||||
|
|
||||||
ostringstream buffer;
|
ostringstream buffer;
|
||||||
|
|
||||||
@ -353,8 +352,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream* inStream, const System
|
|||||||
buffer << setw(2) << hex << setfill('0') << (int)s << " ";
|
buffer << setw(2) << hex << setfill('0') << (int)s << " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
//cout << buffer.str() << endl;
|
|
||||||
|
|
||||||
if (usr != nullptr) {
|
if (usr != nullptr) {
|
||||||
RakNet::BitStream* bs = new RakNet::BitStream((unsigned char*)sync.sBitStream.c_str(), sync.sBitStream.size(), false);
|
RakNet::BitStream* bs = new RakNet::BitStream((unsigned char*)sync.sBitStream.c_str(), sync.sBitStream.size(), false);
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include "eControlScheme.h"
|
#include "eControlScheme.h"
|
||||||
#include "eStateChangeType.h"
|
#include "eStateChangeType.h"
|
||||||
#include "eConnectionType.h"
|
#include "eConnectionType.h"
|
||||||
|
#include "ePlayerFlag.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <future>
|
#include <future>
|
||||||
@ -943,14 +944,7 @@ void GameMessages::SendResurrect(Entity* entity) {
|
|||||||
destroyableComponent->SetImagination(imaginationToRestore);
|
destroyableComponent->SetImagination(imaginationToRestore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
auto cont = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS));
|
|
||||||
if (cont && entity->GetLOT() == 1) {
|
|
||||||
cont->SetPosition(entity->GetRespawnPosition());
|
|
||||||
cont->SetRotation(entity->GetRespawnRotation());
|
|
||||||
}
|
|
||||||
|
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
CMSGHEADER;
|
CMSGHEADER;
|
||||||
@ -1143,18 +1137,16 @@ void GameMessages::SendPlayerReachedRespawnCheckpoint(Entity* entity, const NiPo
|
|||||||
bitStream.Write(position.y);
|
bitStream.Write(position.y);
|
||||||
bitStream.Write(position.z);
|
bitStream.Write(position.z);
|
||||||
|
|
||||||
auto con = static_cast<ControllablePhysicsComponent*>(entity->GetComponent(eReplicaComponentType::CONTROLLABLE_PHYSICS));
|
const bool isNotIdentity = rotation != NiQuaternion::IDENTITY;
|
||||||
if (con) {
|
bitStream.Write(isNotIdentity);
|
||||||
auto rot = con->GetRotation();
|
|
||||||
bitStream.Write(rot.x);
|
if (isNotIdentity) {
|
||||||
bitStream.Write(rot.y);
|
bitStream.Write(rotation.w);
|
||||||
bitStream.Write(rot.z);
|
bitStream.Write(rotation.x);
|
||||||
bitStream.Write(rot.w);
|
bitStream.Write(rotation.y);
|
||||||
|
bitStream.Write(rotation.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
//bitStream.Write(position);
|
|
||||||
//bitStream.Write(rotation);
|
|
||||||
|
|
||||||
SystemAddress sysAddr = entity->GetSystemAddress();
|
SystemAddress sysAddr = entity->GetSystemAddress();
|
||||||
SEND_PACKET;
|
SEND_PACKET;
|
||||||
}
|
}
|
||||||
@ -5027,6 +5019,14 @@ void GameMessages::HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity)
|
|||||||
if (emoteID == 0) return;
|
if (emoteID == 0) return;
|
||||||
std::string sAnimationName = "deaded"; //Default name in case we fail to get the emote
|
std::string sAnimationName = "deaded"; //Default name in case we fail to get the emote
|
||||||
|
|
||||||
|
CDEmoteTableTable* emotes = CDClientManager::Instance().GetTable<CDEmoteTableTable>();
|
||||||
|
if (emotes) {
|
||||||
|
CDEmoteTable* emote = emotes->GetEmote(emoteID);
|
||||||
|
if (emote) sAnimationName = emote->animationName;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderComponent::PlayAnimation(entity, sAnimationName);
|
||||||
|
|
||||||
MissionComponent* missionComponent = entity->GetComponent<MissionComponent>();
|
MissionComponent* missionComponent = entity->GetComponent<MissionComponent>();
|
||||||
if (!missionComponent) return;
|
if (!missionComponent) return;
|
||||||
|
|
||||||
@ -5052,14 +5052,6 @@ void GameMessages::HandlePlayEmote(RakNet::BitStream* inStream, Entity* entity)
|
|||||||
missionComponent->Progress(eMissionTaskType::EMOTE, emoteID, scripted->GetObjectID());
|
missionComponent->Progress(eMissionTaskType::EMOTE, emoteID, scripted->GetObjectID());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CDEmoteTableTable* emotes = CDClientManager::Instance().GetTable<CDEmoteTableTable>();
|
|
||||||
if (emotes) {
|
|
||||||
CDEmoteTable* emote = emotes->GetEmote(emoteID);
|
|
||||||
if (emote) sAnimationName = emote->animationName;
|
|
||||||
}
|
|
||||||
|
|
||||||
RenderComponent::PlayAnimation(entity, sAnimationName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameMessages::HandleModularBuildConvertModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
|
void GameMessages::HandleModularBuildConvertModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||||
@ -5172,6 +5164,14 @@ void GameMessages::HandleMissionDialogOK(RakNet::BitStream* inStream, Entity* en
|
|||||||
} else if (iMissionState == eMissionState::READY_TO_COMPLETE || iMissionState == eMissionState::COMPLETE_READY_TO_COMPLETE) {
|
} else if (iMissionState == eMissionState::READY_TO_COMPLETE || iMissionState == eMissionState::COMPLETE_READY_TO_COMPLETE) {
|
||||||
missionComponent->CompleteMission(missionID);
|
missionComponent->CompleteMission(missionID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Game::config->GetValue("allow_players_to_skip_cinematics") != "1"
|
||||||
|
|| !player->GetCharacter()
|
||||||
|
|| !player->GetCharacter()->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS)) return;
|
||||||
|
player->AddCallbackTimer(0.5f, [player]() {
|
||||||
|
if (!player) return;
|
||||||
|
GameMessages::SendEndCinematic(player->GetObjectID(), u"", player->GetSystemAddress());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameMessages::HandleRequestLinkedMission(RakNet::BitStream* inStream, Entity* entity) {
|
void GameMessages::HandleRequestLinkedMission(RakNet::BitStream* inStream, Entity* entity) {
|
||||||
|
@ -83,8 +83,10 @@
|
|||||||
#include "eChatInternalMessageType.h"
|
#include "eChatInternalMessageType.h"
|
||||||
#include "eMasterMessageType.h"
|
#include "eMasterMessageType.h"
|
||||||
|
|
||||||
|
#include "CDRewardCodesTable.h"
|
||||||
#include "CDObjectsTable.h"
|
#include "CDObjectsTable.h"
|
||||||
#include "CDZoneTableTable.h"
|
#include "CDZoneTableTable.h"
|
||||||
|
#include "ePlayerFlag.h"
|
||||||
|
|
||||||
void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr) {
|
void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr) {
|
||||||
auto commandCopy = command;
|
auto commandCopy = command;
|
||||||
@ -171,6 +173,21 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chatCommand == "toggleskipcinematics" && (Game::config->GetValue("allow_players_to_skip_cinematics") == "1" || entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER)) {
|
||||||
|
auto* character = entity->GetCharacter();
|
||||||
|
if (!character) return;
|
||||||
|
bool current = character->GetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS);
|
||||||
|
character->SetPlayerFlag(ePlayerFlag::DLU_SKIP_CINEMATICS, !current);
|
||||||
|
if (!current) {
|
||||||
|
ChatPackets::SendSystemMessage(sysAddr, u"You have elected to skip cinematics. Note that not all cinematics can be skipped, but most will be skipped now.");
|
||||||
|
} else {
|
||||||
|
ChatPackets::SendSystemMessage(sysAddr, u"Cinematics will no longer be skipped.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
//HANDLE ALL NON GM SLASH COMMANDS RIGHT HERE!
|
//HANDLE ALL NON GM SLASH COMMANDS RIGHT HERE!
|
||||||
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
@ -1372,7 +1389,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
|
|||||||
|
|
||||||
ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(position.x)) + u", " + (GeneralUtils::to_u16string(position.y)) + u", " + (GeneralUtils::to_u16string(position.z)) + u">");
|
ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(position.x)) + u", " + (GeneralUtils::to_u16string(position.y)) + u", " + (GeneralUtils::to_u16string(position.z)) + u">");
|
||||||
|
|
||||||
std::cout << position.x << ", " << position.y << ", " << position.z << std::endl;
|
LOG("Position: %f, %f, %f", position.x, position.y, position.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chatCommand == "rot" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
|
if (chatCommand == "rot" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
|
||||||
@ -1380,14 +1397,14 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
|
|||||||
|
|
||||||
ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(rotation.w)) + u", " + (GeneralUtils::to_u16string(rotation.x)) + u", " + (GeneralUtils::to_u16string(rotation.y)) + u", " + (GeneralUtils::to_u16string(rotation.z)) + u">");
|
ChatPackets::SendSystemMessage(sysAddr, u"<" + (GeneralUtils::to_u16string(rotation.w)) + u", " + (GeneralUtils::to_u16string(rotation.x)) + u", " + (GeneralUtils::to_u16string(rotation.y)) + u", " + (GeneralUtils::to_u16string(rotation.z)) + u">");
|
||||||
|
|
||||||
std::cout << rotation.w << ", " << rotation.x << ", " << rotation.y << ", " << rotation.z << std::endl;
|
LOG("Rotation: %f, %f, %f, %f", rotation.w, rotation.x, rotation.y, rotation.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chatCommand == "locrow" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
|
if (chatCommand == "locrow" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
|
||||||
const auto position = entity->GetPosition();
|
const auto position = entity->GetPosition();
|
||||||
const auto rotation = entity->GetRotation();
|
const auto rotation = entity->GetRotation();
|
||||||
|
|
||||||
std::cout << "<location x=\"" << position.x << "\" y=\"" << position.y << "\" z=\"" << position.z << "\" rw=\"" << rotation.w << "\" rx=\"" << rotation.x << "\" ry=\"" << rotation.y << "\" rz=\"" << rotation.z << "\" />" << std::endl;
|
LOG("<location x=\"%f\" y=\"%f\" z=\"%f\" rw=\"%f\" rx=\"%f\" ry=\"%f\" rz=\"%f\" />", position.x, position.y, position.z, rotation.w, rotation.x, rotation.y, rotation.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (chatCommand == "playlvlfx" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
|
if (chatCommand == "playlvlfx" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER) {
|
||||||
@ -1652,7 +1669,7 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
|
|||||||
|
|
||||||
auto sphere = static_cast<dpShapeSphere*>(prox.second->GetShape());
|
auto sphere = static_cast<dpShapeSphere*>(prox.second->GetShape());
|
||||||
auto pos = prox.second->GetPosition();
|
auto pos = prox.second->GetPosition();
|
||||||
std::cout << prox.first << ", r: " << sphere->GetRadius() << ", pos: " << pos.x << "," << pos.y << "," << pos.z << std::endl;
|
LOG("Proximity: %s, r: %f, pos: %f, %f, %f", prox.first.c_str(), sphere->GetRadius(), pos.x, pos.y, pos.z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1895,6 +1912,13 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chatCommand == "setrewardcode" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() == 1) {
|
||||||
|
auto* cdrewardCodes = CDClientManager::Instance().GetTable<CDRewardCodesTable>();
|
||||||
|
|
||||||
|
auto id = cdrewardCodes->GetCodeID(args[0]);
|
||||||
|
if (id != -1) Database::Get()->InsertRewardCode(user->GetAccountID(), id);
|
||||||
|
}
|
||||||
|
|
||||||
if (chatCommand == "inspect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) {
|
if (chatCommand == "inspect" && entity->GetGMLevel() >= eGameMasterLevel::DEVELOPER && args.size() >= 1) {
|
||||||
Entity* closest = nullptr;
|
Entity* closest = nullptr;
|
||||||
|
|
||||||
|
@ -29,6 +29,22 @@
|
|||||||
#include "eMasterMessageType.h"
|
#include "eMasterMessageType.h"
|
||||||
#include "eGameMasterLevel.h"
|
#include "eGameMasterLevel.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
std::vector<uint32_t> claimCodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AuthPackets::LoadClaimCodes() {
|
||||||
|
if(!claimCodes.empty()) return;
|
||||||
|
auto rcstring = Game::config->GetValue("rewardcodes");
|
||||||
|
auto codestrings = GeneralUtils::SplitString(rcstring, ',');
|
||||||
|
for(auto const &codestring: codestrings){
|
||||||
|
uint32_t code = -1;
|
||||||
|
if(GeneralUtils::TryParse(codestring, code) && code != -1){
|
||||||
|
claimCodes.push_back(code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AuthPackets::HandleHandshake(dServer* server, Packet* packet) {
|
void AuthPackets::HandleHandshake(dServer* server, Packet* packet) {
|
||||||
RakNet::BitStream inStream(packet->data, packet->length, false);
|
RakNet::BitStream inStream(packet->data, packet->length, false);
|
||||||
uint64_t header = inStream.Read(header);
|
uint64_t header = inStream.Read(header);
|
||||||
@ -129,6 +145,10 @@ void AuthPackets::HandleLoginRequest(dServer* server, Packet* packet) {
|
|||||||
AuthPackets::SendLoginResponse(server, system, eLoginResponse::SUCCESS, "", zoneIP, zonePort, username);
|
AuthPackets::SendLoginResponse(server, system, eLoginResponse::SUCCESS, "", zoneIP, zonePort, username);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for(auto const code: claimCodes){
|
||||||
|
Database::Get()->InsertRewardCode(accountInfo->id, code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AuthPackets::SendLoginResponse(dServer* server, const SystemAddress& sysAddr, eLoginResponse responseCode, const std::string& errorMsg, const std::string& wServerIP, uint16_t wServerPort, std::string username) {
|
void AuthPackets::SendLoginResponse(dServer* server, const SystemAddress& sysAddr, eLoginResponse responseCode, const std::string& errorMsg, const std::string& wServerIP, uint16_t wServerPort, std::string username) {
|
||||||
|
@ -15,6 +15,8 @@ namespace AuthPackets {
|
|||||||
|
|
||||||
void HandleLoginRequest(dServer* server, Packet* packet);
|
void HandleLoginRequest(dServer* server, Packet* packet);
|
||||||
void SendLoginResponse(dServer* server, const SystemAddress& sysAddr, eLoginResponse responseCode, const std::string& errorMsg, const std::string& wServerIP, uint16_t wServerPort, std::string username);
|
void SendLoginResponse(dServer* server, const SystemAddress& sysAddr, eLoginResponse responseCode, const std::string& errorMsg, const std::string& wServerIP, uint16_t wServerPort, std::string username);
|
||||||
|
void LoadClaimCodes();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // AUTHPACKETS_H
|
#endif // AUTHPACKETS_H
|
||||||
|
@ -22,7 +22,7 @@ dpEntity::dpEntity(const LWOOBJID& objectID, dpShapeType shapeType, bool isStati
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
std::cout << "No shape for shapeType: " << (int)shapeType << std::endl;
|
LOG("No shape for shapeType: %d", static_cast<int32_t>(shapeType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,15 +83,9 @@ void dpEntity::CheckCollision(dpEntity* other) {
|
|||||||
if (isColliding && !wasFound) {
|
if (isColliding && !wasFound) {
|
||||||
m_CurrentlyCollidingObjects.emplace(other->GetObjectID(), other);
|
m_CurrentlyCollidingObjects.emplace(other->GetObjectID(), other);
|
||||||
m_NewObjects.push_back(other);
|
m_NewObjects.push_back(other);
|
||||||
|
|
||||||
//if (m_CollisionShape->GetShapeType() == dpShapeType::Sphere && other->GetShape()->GetShapeType() == dpShapeType::Sphere)
|
|
||||||
//std::cout << "started sphere col at: " << other->GetPosition().x << ", " << other->GetPosition().y << ", " << other->GetPosition().z << std::endl;
|
|
||||||
} else if (!isColliding && wasFound) {
|
} else if (!isColliding && wasFound) {
|
||||||
m_CurrentlyCollidingObjects.erase(other->GetObjectID());
|
m_CurrentlyCollidingObjects.erase(other->GetObjectID());
|
||||||
m_RemovedObjects.push_back(other);
|
m_RemovedObjects.push_back(other);
|
||||||
|
|
||||||
//if (m_CollisionShape->GetShapeType() == dpShapeType::Sphere && other->GetShape()->GetShapeType() == dpShapeType::Sphere)
|
|
||||||
// std::cout << "stopped sphere col at: " << other->GetPosition().x << ", " << other->GetPosition().y << ", " << other->GetPosition().z << std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,8 +8,6 @@ dpGrid::dpGrid(int numCells, int cellSize) {
|
|||||||
CELL_SIZE = cellSize;
|
CELL_SIZE = cellSize;
|
||||||
m_DeleteGrid = true;
|
m_DeleteGrid = true;
|
||||||
|
|
||||||
//dumb method but i can't be bothered
|
|
||||||
|
|
||||||
//fill x
|
//fill x
|
||||||
for (int i = 0; i < NUM_CELLS; i++) {
|
for (int i = 0; i < NUM_CELLS; i++) {
|
||||||
m_Cells.push_back(std::vector<std::forward_list<dpEntity*>>());
|
m_Cells.push_back(std::vector<std::forward_list<dpEntity*>>());
|
||||||
|
@ -10,7 +10,7 @@ dpShapeBase::~dpShapeBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool dpShapeBase::IsColliding(dpShapeBase* other) {
|
bool dpShapeBase::IsColliding(dpShapeBase* other) {
|
||||||
std::cout << "Base shapes do not have any *shape* to them, and thus cannot be overlapping." << std::endl;
|
LOG("Base shapes do not have any *shape* to them, and thus cannot be overlapping.");
|
||||||
std::cout << "You should be using a shape class inherited from this base class." << std::endl;
|
LOG("You should be using a shape class inherited from this base class.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ bool dpShapeBox::IsColliding(dpShapeBase* other) {
|
|||||||
return dpCollisionChecks::CheckBoxes(m_ParentEntity, other->GetParentEntity());
|
return dpCollisionChecks::CheckBoxes(m_ParentEntity, other->GetParentEntity());
|
||||||
|
|
||||||
default:
|
default:
|
||||||
std::cout << "No collision detection for: " << (int)m_ShapeType << "-to-" << (int)other->GetShapeType() << " collision!" << std::endl;
|
LOG("No collision detection for: %i-to-%i collision!", static_cast<int32_t>(m_ShapeType), static_cast<int32_t>(other->GetShapeType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -72,10 +72,7 @@ void dpShapeBox::SetScale(float scale) {
|
|||||||
m_Height *= scale;
|
m_Height *= scale;
|
||||||
m_Depth *= scale;
|
m_Depth *= scale;
|
||||||
|
|
||||||
//fuuuckkk yoouu
|
|
||||||
InitVertices();
|
InitVertices();
|
||||||
|
|
||||||
//SetRotation(m_ParentEntity->GetRotation());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void dpShapeBox::SetRotation(const NiQuaternion& rotation) {
|
void dpShapeBox::SetRotation(const NiQuaternion& rotation) {
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "dpShapeSphere.h"
|
#include "dpShapeSphere.h"
|
||||||
#include "dpCollisionChecks.h"
|
#include "dpCollisionChecks.h"
|
||||||
|
#include "Game.h"
|
||||||
|
#include "Logger.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
dpShapeSphere::dpShapeSphere(dpEntity* parentEntity, float radius) :
|
dpShapeSphere::dpShapeSphere(dpEntity* parentEntity, float radius) :
|
||||||
@ -22,7 +24,7 @@ bool dpShapeSphere::IsColliding(dpShapeBase* other) {
|
|||||||
return dpCollisionChecks::CheckSphereBox(m_ParentEntity, other->GetParentEntity());
|
return dpCollisionChecks::CheckSphereBox(m_ParentEntity, other->GetParentEntity());
|
||||||
|
|
||||||
default:
|
default:
|
||||||
std::cout << "No collision detection for: " << (int)m_ShapeType << "-to-" << (int)other->GetShapeType() << " collision!" << std::endl;
|
LOG("No collision detection for: %i-to-%i collision!", static_cast<int32_t>(m_ShapeType), static_cast<int32_t>(other->GetShapeType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
//This file included for reference only
|
|
||||||
|
|
||||||
/*#include <iostream>
|
|
||||||
#include <chrono>
|
|
||||||
#include <thread>
|
|
||||||
#include "dpWorld.h"
|
|
||||||
|
|
||||||
#include "NiQuaternion.hpp"
|
|
||||||
#include "NiPoint3.hpp"
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
std::cout << "dPhysics test engine" << std::endl;
|
|
||||||
|
|
||||||
//Test rotation code:
|
|
||||||
NiPoint3 p(1.0f, 0.0f, 0.0f);
|
|
||||||
|
|
||||||
float angle = 45.0f;
|
|
||||||
NiQuaternion q = NiQuaternion::CreateFromAxisAngle(NiPoint3(0.0f, 0.0f, 1.0f), angle);
|
|
||||||
|
|
||||||
NiPoint3 rotated = p.RotateByQuaternion(q);
|
|
||||||
|
|
||||||
std::cout << "OG: " << p.x << ", " << p.y << ", " << p.z << std::endl;
|
|
||||||
std::cout << "Quater: " << q.x << ", " << q.y << ", " << q.z << ", " << q.w << " angle: " << angle << std::endl;
|
|
||||||
std::cout << "Rotated: " << rotated.x << ", " << rotated.y << ", " << rotated.z << std::endl;
|
|
||||||
|
|
||||||
//Test some collisions:
|
|
||||||
dpWorld::GetInstance().Initialize(1000);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
dpWorld::GetInstance().StepWorld(1.0f/60.0f);
|
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(16));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}*/
|
|
@ -1033,9 +1033,8 @@ void HandlePacket(Packet* packet) {
|
|||||||
Game::entityManager->ConstructAllEntities(packet->systemAddress);
|
Game::entityManager->ConstructAllEntities(packet->systemAddress);
|
||||||
|
|
||||||
auto* characterComponent = player->GetComponent<CharacterComponent>();
|
auto* characterComponent = player->GetComponent<CharacterComponent>();
|
||||||
if (characterComponent) {
|
if (!characterComponent) return;
|
||||||
player->GetComponent<CharacterComponent>()->RocketUnEquip(player);
|
characterComponent->RocketUnEquip(player);
|
||||||
}
|
|
||||||
|
|
||||||
// Do charxml fixes here
|
// Do charxml fixes here
|
||||||
auto* levelComponent = player->GetComponent<LevelProgressionComponent>();
|
auto* levelComponent = player->GetComponent<LevelProgressionComponent>();
|
||||||
|
@ -16,6 +16,12 @@
|
|||||||
#include "AssetManager.h"
|
#include "AssetManager.h"
|
||||||
#include "dConfig.h"
|
#include "dConfig.h"
|
||||||
|
|
||||||
|
void Level::SceneObjectDataChunk::PrintAllObjects() const {
|
||||||
|
for (const auto& [id, sceneObj] : objects) {
|
||||||
|
LOG("ID: %d LOT: %d", id, sceneObj.lot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Level::Level(Zone* parentZone, const std::string& filepath) {
|
Level::Level(Zone* parentZone, const std::string& filepath) {
|
||||||
m_ParentZone = parentZone;
|
m_ParentZone = parentZone;
|
||||||
|
|
||||||
@ -33,9 +39,9 @@ Level::Level(Zone* parentZone, const std::string& filepath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Level::~Level() {
|
Level::~Level() {
|
||||||
for (std::map<uint32_t, Header>::iterator it = m_ChunkHeaders.begin(); it != m_ChunkHeaders.end(); ++it) {
|
for (auto& [id, header] : m_ChunkHeaders) {
|
||||||
if (it->second.id == Level::ChunkTypeID::FileInfo) delete it->second.fileInfo;
|
if (header.id == Level::ChunkTypeID::FileInfo) delete header.fileInfo;
|
||||||
if (it->second.id == Level::ChunkTypeID::SceneObjectData) delete it->second.sceneObjects;
|
if (header.id == Level::ChunkTypeID::SceneObjectData) delete header.sceneObjects;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,8 +254,8 @@ void Level::ReadSceneObjectDataChunk(std::istream& file, Header& header) {
|
|||||||
BinaryIO::BinaryRead(file, obj.id);
|
BinaryIO::BinaryRead(file, obj.id);
|
||||||
BinaryIO::BinaryRead(file, obj.lot);
|
BinaryIO::BinaryRead(file, obj.lot);
|
||||||
|
|
||||||
/*if (header.fileInfo->version >= 0x26)*/ BinaryIO::BinaryRead(file, obj.value1);
|
/*if (header.fileInfo->version >= 0x26)*/ BinaryIO::BinaryRead(file, obj.nodeType);
|
||||||
/*if (header.fileInfo->version >= 0x20)*/ BinaryIO::BinaryRead(file, obj.value2);
|
/*if (header.fileInfo->version >= 0x20)*/ BinaryIO::BinaryRead(file, obj.glomId);
|
||||||
|
|
||||||
BinaryIO::BinaryRead(file, obj.position);
|
BinaryIO::BinaryRead(file, obj.position);
|
||||||
BinaryIO::BinaryRead(file, obj.rotation);
|
BinaryIO::BinaryRead(file, obj.rotation);
|
||||||
|
@ -30,11 +30,7 @@ public:
|
|||||||
struct SceneObjectDataChunk {
|
struct SceneObjectDataChunk {
|
||||||
std::map<LWOOBJID, SceneObject> objects;
|
std::map<LWOOBJID, SceneObject> objects;
|
||||||
|
|
||||||
const void PrintAllObjects() {
|
void PrintAllObjects() const;
|
||||||
for (std::map<LWOOBJID, SceneObject>::iterator it = objects.begin(); it != objects.end(); ++it) {
|
|
||||||
std::cout << "\t ID: " << it->first << " LOT: " << it->second.lot << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t GetObjectCount() { return objects.size(); }
|
uint32_t GetObjectCount() { return objects.size(); }
|
||||||
};
|
};
|
||||||
|
@ -148,6 +148,8 @@ struct PropertyPath {
|
|||||||
float repMultiplier;
|
float repMultiplier;
|
||||||
PropertyRentalPeriod rentalPeriod;
|
PropertyRentalPeriod rentalPeriod;
|
||||||
PropertyAchievmentRequired achievementRequired;
|
PropertyAchievmentRequired achievementRequired;
|
||||||
|
|
||||||
|
// Player respawn coordinates in the main zone (not the property zone)
|
||||||
NiPoint3 playerZoneCoords;
|
NiPoint3 playerZoneCoords;
|
||||||
float maxBuildHeight;
|
float maxBuildHeight;
|
||||||
};
|
};
|
||||||
|
@ -12,8 +12,8 @@ struct mapCompareLwoSceneIDs {
|
|||||||
struct SceneObject {
|
struct SceneObject {
|
||||||
LWOOBJID id;
|
LWOOBJID id;
|
||||||
LOT lot;
|
LOT lot;
|
||||||
uint32_t value1;
|
uint32_t nodeType;
|
||||||
uint32_t value2;
|
uint32_t glomId;
|
||||||
NiPoint3 position;
|
NiPoint3 position;
|
||||||
NiQuaternion rotation;
|
NiQuaternion rotation;
|
||||||
float scale = 1.0f;
|
float scale = 1.0f;
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
|resurrect|`/resurrect`|Resurrects the player.||
|
|resurrect|`/resurrect`|Resurrects the player.||
|
||||||
|requestmailcount|`/requestmailcount`|Sends notification with number of unread messages in the player's mailbox.||
|
|requestmailcount|`/requestmailcount`|Sends notification with number of unread messages in the player's mailbox.||
|
||||||
|who|`/who`|Displays in chat all players on the instance.||
|
|who|`/who`|Displays in chat all players on the instance.||
|
||||||
|
|togglenameplate|`/togglenameplate`|Turns the nameplate above your head that is visible to other players off and on.|8 or if `allow_nameplate_off` is set to exactly `1` in the settings|
|
||||||
|
|toggleskipcinematics|`/toggleskipcinematics`|Skips mission and world load related cinematics.|8 or if `allow_players_to_skip_cinematics` is set to exactly `1` in the settings then 0|
|
||||||
|
|
||||||
## Moderation Commands
|
## Moderation Commands
|
||||||
|
|
||||||
@ -49,7 +51,6 @@ These commands are primarily for development and testing. The usage of many of t
|
|||||||
|
|
||||||
|Command|Usage|Description|Admin Level Requirement|
|
|Command|Usage|Description|Admin Level Requirement|
|
||||||
|--- |--- |--- |--- |
|
|--- |--- |--- |--- |
|
||||||
|togglenameplate|`/togglenameplate`|Turns the nameplate above your head that is visible to other players off and on.|8 or if `allow_nameplate_off` is set to exactly `1` in the settings|
|
|
||||||
|fix-stats|`/fix-stats`|Resets skills, buffs, and destroyables.||
|
|fix-stats|`/fix-stats`|Resets skills, buffs, and destroyables.||
|
||||||
|join|`/join <password>`|Joins a private zone with given password.||
|
|join|`/join <password>`|Joins a private zone with given password.||
|
||||||
|leave-zone|`/leave-zone`|If you are in an instanced zone, transfers you to the closest main world. For example, if you are in an instance of Avant Gardens Survival or the Spider Queen Battle, you are sent to Avant Gardens. If you are in the Battle of Nimbus Station, you are sent to Nimbus Station.||
|
|leave-zone|`/leave-zone`|If you are in an instanced zone, transfers you to the closest main world. For example, if you are in an instance of Avant Gardens Survival or the Spider Queen Battle, you are sent to Avant Gardens. If you are in the Battle of Nimbus Station, you are sent to Nimbus Station.||
|
||||||
@ -112,6 +113,7 @@ These commands are primarily for development and testing. The usage of many of t
|
|||||||
|setfaction|`/setfaction <faction id>`|Clears the users current factions and sets it|8|
|
|setfaction|`/setfaction <faction id>`|Clears the users current factions and sets it|8|
|
||||||
|addfaction|`/addfaction <faction id>`|Add the faction to the users list of factions|8|
|
|addfaction|`/addfaction <faction id>`|Add the faction to the users list of factions|8|
|
||||||
|getfactions|`/getfactions`|Shows the player's factions|8|
|
|getfactions|`/getfactions`|Shows the player's factions|8|
|
||||||
|
|setrewardcode|`/setrewardcode <code>`|Sets the rewardcode for the account you are logged into if it's a valid rewardcode, See cdclient table `RewardCodes`|8|
|
||||||
## Detailed `/inspect` Usage
|
## Detailed `/inspect` Usage
|
||||||
|
|
||||||
`/inspect <component> (-m <waypoint> | -a <animation> | -s | -p | -f (faction) | -t)`
|
`/inspect <component> (-m <waypoint> | -a <animation> | -s | -p | -f (faction) | -t)`
|
||||||
|
6
migrations/dlu/13_ignore_list.sql
Normal file
6
migrations/dlu/13_ignore_list.sql
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS ignore_list (
|
||||||
|
player_id BIGINT NOT NULL REFERENCES charinfo(id) ON DELETE CASCADE,
|
||||||
|
ignored_player_id BIGINT NOT NULL REFERENCES charinfo(id) ON DELETE CASCADE,
|
||||||
|
|
||||||
|
PRIMARY KEY (player_id, ignored_player_id)
|
||||||
|
);
|
5
migrations/dlu/14_reward_codes.sql
Normal file
5
migrations/dlu/14_reward_codes.sql
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS accounts_rewardcodes (
|
||||||
|
account_id INT NOT NULL REFERENCES accounts(id) ON DELETE CASCADE,
|
||||||
|
rewardcode INT NOT NULL,
|
||||||
|
PRIMARY KEY (account_id, rewardcode)
|
||||||
|
);
|
@ -4,3 +4,11 @@ port=1001
|
|||||||
# 0 or 1, should ignore playkeys
|
# 0 or 1, should ignore playkeys
|
||||||
# If 1 everyone with an account will be able to login, regardless of if they have a key or not
|
# If 1 everyone with an account will be able to login, regardless of if they have a key or not
|
||||||
dont_use_keys=0
|
dont_use_keys=0
|
||||||
|
|
||||||
|
# list of rewardcodes to set on the accounts by default
|
||||||
|
# ex: 30,1,0,3
|
||||||
|
# See RewardCodes in the CDclient for what codes exist
|
||||||
|
# Default 4,30
|
||||||
|
# 4 allows LEGOClub access
|
||||||
|
# 30 makes the client not consume bricks when in bbb mode
|
||||||
|
rewardcodes=4,30
|
||||||
|
@ -61,6 +61,7 @@ allow_nameplate_off=0
|
|||||||
# Turn logging of IP addresses for anti-cheat reporting on (1) or off(0)
|
# Turn logging of IP addresses for anti-cheat reporting on (1) or off(0)
|
||||||
log_ip_addresses_for_anti_cheat=1
|
log_ip_addresses_for_anti_cheat=1
|
||||||
|
|
||||||
|
# These are the 5 items items that are shown in the "Help" menu in-game along with their coresponding descriptions below.
|
||||||
help_0_summary=Got an issue?
|
help_0_summary=Got an issue?
|
||||||
help_1_summary=Stuck loading?
|
help_1_summary=Stuck loading?
|
||||||
help_2_summary=Missing features?
|
help_2_summary=Missing features?
|
||||||
@ -72,3 +73,6 @@ help_1_description=Try switching networks, using a VPN, or using your phone's ho
|
|||||||
help_2_description=While DarkflameServer is a mostly complete emulator, there are still some features that aren't implemented. You can track these on the GitHub issues page.<br/><br/>
|
help_2_description=While DarkflameServer is a mostly complete emulator, there are still some features that aren't implemented. You can track these on the GitHub issues page.<br/><br/>
|
||||||
help_3_description=Skill issue!<br/><br/>
|
help_3_description=Skill issue!<br/><br/>
|
||||||
help_4_description=Visit Discussions on the DarkflameServer GitHub page<br/>to ask questions and collaborate with other devs!<br/><br/>
|
help_4_description=Visit Discussions on the DarkflameServer GitHub page<br/>to ask questions and collaborate with other devs!<br/><br/>
|
||||||
|
|
||||||
|
# Toggleable quality of life feature to allow users to skip most cinematics.
|
||||||
|
allow_players_to_skip_cinematics=0
|
||||||
|
@ -71,25 +71,15 @@ TEST(dCommonTests, AMF3InsertionAssociativeTest) {
|
|||||||
array.Insert<std::vector<uint32_t>>("Undefined", {});
|
array.Insert<std::vector<uint32_t>>("Undefined", {});
|
||||||
array.Insert("Null", nullptr);
|
array.Insert("Null", nullptr);
|
||||||
|
|
||||||
std::cout << "test" << std::endl;
|
|
||||||
ASSERT_EQ(array.Get<const char*>("CString")->GetValueType(), eAmf::String);
|
ASSERT_EQ(array.Get<const char*>("CString")->GetValueType(), eAmf::String);
|
||||||
std::cout << "test" << std::endl;
|
|
||||||
ASSERT_EQ(array.Get<std::string>("String")->GetValueType(), eAmf::String);
|
ASSERT_EQ(array.Get<std::string>("String")->GetValueType(), eAmf::String);
|
||||||
std::cout << "test" << std::endl;
|
|
||||||
ASSERT_EQ(array.Get<bool>("False")->GetValueType(), eAmf::False);
|
ASSERT_EQ(array.Get<bool>("False")->GetValueType(), eAmf::False);
|
||||||
std::cout << "test" << std::endl;
|
|
||||||
ASSERT_EQ(array.Get<bool>("True")->GetValueType(), eAmf::True);
|
ASSERT_EQ(array.Get<bool>("True")->GetValueType(), eAmf::True);
|
||||||
std::cout << "test" << std::endl;
|
|
||||||
ASSERT_EQ(array.Get<int32_t>("Integer")->GetValueType(), eAmf::Integer);
|
ASSERT_EQ(array.Get<int32_t>("Integer")->GetValueType(), eAmf::Integer);
|
||||||
std::cout << "test" << std::endl;
|
|
||||||
ASSERT_EQ(array.Get<double>("Double")->GetValueType(), eAmf::Double);
|
ASSERT_EQ(array.Get<double>("Double")->GetValueType(), eAmf::Double);
|
||||||
std::cout << "test" << std::endl;
|
|
||||||
ASSERT_EQ(array.GetArray("Array")->GetValueType(), eAmf::Array);
|
ASSERT_EQ(array.GetArray("Array")->GetValueType(), eAmf::Array);
|
||||||
std::cout << "test" << std::endl;
|
|
||||||
ASSERT_EQ(array.Get<nullptr_t>("Null")->GetValueType(), eAmf::Null);
|
ASSERT_EQ(array.Get<nullptr_t>("Null")->GetValueType(), eAmf::Null);
|
||||||
std::cout << "test" << std::endl;
|
|
||||||
ASSERT_EQ(array.Get<std::vector<uint32_t>>("Undefined")->GetValueType(), eAmf::Undefined);
|
ASSERT_EQ(array.Get<std::vector<uint32_t>>("Undefined")->GetValueType(), eAmf::Undefined);
|
||||||
std::cout << "test" << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(dCommonTests, AMF3InsertionDenseTest) {
|
TEST(dCommonTests, AMF3InsertionDenseTest) {
|
||||||
|
Loading…
Reference in New Issue
Block a user