mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-12-18 03:37:23 -06:00
Compare commits
21 Commits
comp-seria
...
chat-http-
| Author | SHA1 | Date | |
|---|---|---|---|
| 214626222c | |||
| ce5bd68067 | |||
| 9192dca4e6 | |||
| 06607c9b55 | |||
| c3ea448be0 | |||
| ff721ed49b | |||
| bce03ca08d | |||
| faee5b72e7 | |||
| 77143fc2cf | |||
| 3801a97722 | |||
| 5e16c13a58 | |||
|
|
0367c67c85 | ||
|
|
8fdc212cda | ||
| 29e759f793 | |||
| 63f9a9f9d4 | |||
| 850ad2aa15 | |||
| ed7b33d8ab | |||
| 55a52b6cc0 | |||
| 99e7349f6c | |||
|
|
fafe2aefad | ||
|
|
5049f215ba |
@@ -96,6 +96,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
|||||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
find_package(MariaDB)
|
find_package(MariaDB)
|
||||||
|
find_package(JSON)
|
||||||
|
|
||||||
# Create a /resServer directory
|
# Create a /resServer directory
|
||||||
make_directory(${CMAKE_BINARY_DIR}/resServer)
|
make_directory(${CMAKE_BINARY_DIR}/resServer)
|
||||||
@@ -284,7 +285,7 @@ add_subdirectory(dPhysics)
|
|||||||
add_subdirectory(dServer)
|
add_subdirectory(dServer)
|
||||||
|
|
||||||
# Create a list of common libraries shared between all binaries
|
# Create a list of common libraries shared between all binaries
|
||||||
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "MariaDB::ConnCpp" "magic_enum")
|
set(COMMON_LIBRARIES "dCommon" "dDatabase" "dNet" "raknet" "MariaDB::ConnCpp" "magic_enum" "nlohmann_json::nlohmann_json")
|
||||||
|
|
||||||
# Add platform specific common libraries
|
# Add platform specific common libraries
|
||||||
if(UNIX)
|
if(UNIX)
|
||||||
|
|||||||
20
cmake/FindJSON.cmake
Normal file
20
cmake/FindJSON.cmake
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
include(FetchContent)
|
||||||
|
|
||||||
|
message(STATUS "Fetching json...")
|
||||||
|
|
||||||
|
FetchContent_Declare(
|
||||||
|
json
|
||||||
|
GIT_REPOSITORY https://github.com/nlohmann/json
|
||||||
|
GIT_TAG v3.11.3
|
||||||
|
)
|
||||||
|
|
||||||
|
FetchContent_GetProperties(json)
|
||||||
|
if(NOT json_POPULATED)
|
||||||
|
FetchContent_Populate(json)
|
||||||
|
add_subdirectory(${json_SOURCE_DIR} ${json_BINARY_DIR} EXCLUDE_FROM_ALL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
FetchContent_MakeAvailable(json)
|
||||||
|
|
||||||
|
message(STATUS "json fetched and is now ready.")
|
||||||
|
set(JSON_FOUND TRUE)
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
set(DCHATSERVER_SOURCES
|
set(DCHATSERVER_SOURCES
|
||||||
|
"ChatWebApi.cpp"
|
||||||
"ChatIgnoreList.cpp"
|
"ChatIgnoreList.cpp"
|
||||||
"ChatPacketHandler.cpp"
|
"ChatPacketHandler.cpp"
|
||||||
"PlayerContainer.cpp"
|
"PlayerContainer.cpp"
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "eGameMessageType.h"
|
#include "eGameMessageType.h"
|
||||||
#include "StringifiedEnum.h"
|
#include "StringifiedEnum.h"
|
||||||
#include "eGameMasterLevel.h"
|
#include "eGameMasterLevel.h"
|
||||||
|
#include "ChatPackets.h"
|
||||||
|
|
||||||
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:
|
||||||
@@ -354,6 +355,67 @@ void ChatPacketHandler::HandleGMLevelUpdate(Packet* packet) {
|
|||||||
inStream.Read(player.gmLevel);
|
inStream.Read(player.gmLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ChatPacketHandler::HandleWho(Packet* packet) {
|
||||||
|
CINSTREAM_SKIP_HEADER;
|
||||||
|
FindPlayerRequest request;
|
||||||
|
request.Deserialize(inStream);
|
||||||
|
|
||||||
|
const auto& sender = Game::playerContainer.GetPlayerData(request.requestor);
|
||||||
|
if (!sender) return;
|
||||||
|
|
||||||
|
const auto& player = Game::playerContainer.GetPlayerData(request.playerName.GetAsString());
|
||||||
|
bool online = player;
|
||||||
|
|
||||||
|
CBITSTREAM;
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||||
|
bitStream.Write(request.requestor);
|
||||||
|
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::WHO_RESPONSE);
|
||||||
|
bitStream.Write<uint8_t>(online);
|
||||||
|
bitStream.Write(player.zoneID.GetMapID());
|
||||||
|
bitStream.Write(player.zoneID.GetInstanceID());
|
||||||
|
bitStream.Write(player.zoneID.GetCloneID());
|
||||||
|
bitStream.Write(request.playerName);
|
||||||
|
|
||||||
|
SystemAddress sysAddr = sender.sysAddr;
|
||||||
|
SEND_PACKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatPacketHandler::HandleShowAll(Packet* packet) {
|
||||||
|
CINSTREAM_SKIP_HEADER;
|
||||||
|
ShowAllRequest request;
|
||||||
|
request.Deserialize(inStream);
|
||||||
|
|
||||||
|
const auto& sender = Game::playerContainer.GetPlayerData(request.requestor);
|
||||||
|
if (!sender) return;
|
||||||
|
|
||||||
|
CBITSTREAM;
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WORLD_ROUTE_PACKET);
|
||||||
|
bitStream.Write(request.requestor);
|
||||||
|
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::SHOW_ALL_RESPONSE);
|
||||||
|
bitStream.Write<uint8_t>(!request.displayZoneData && !request.displayIndividualPlayers);
|
||||||
|
bitStream.Write(Game::playerContainer.GetPlayerCount());
|
||||||
|
bitStream.Write(Game::playerContainer.GetSimCount());
|
||||||
|
bitStream.Write<uint8_t>(request.displayIndividualPlayers);
|
||||||
|
bitStream.Write<uint8_t>(request.displayZoneData);
|
||||||
|
if (request.displayZoneData || request.displayIndividualPlayers){
|
||||||
|
for (auto& [playerID, playerData ]: Game::playerContainer.GetAllPlayers()){
|
||||||
|
if (!playerData) continue;
|
||||||
|
bitStream.Write<uint8_t>(0); // structure packing
|
||||||
|
if (request.displayIndividualPlayers) bitStream.Write(LUWString(playerData.playerName));
|
||||||
|
if (request.displayZoneData) {
|
||||||
|
bitStream.Write(playerData.zoneID.GetMapID());
|
||||||
|
bitStream.Write(playerData.zoneID.GetInstanceID());
|
||||||
|
bitStream.Write(playerData.zoneID.GetCloneID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SystemAddress sysAddr = sender.sysAddr;
|
||||||
|
SEND_PACKET;
|
||||||
|
}
|
||||||
|
|
||||||
// the structure the client uses to send this packet is shared in many chat messages
|
// the structure the client uses to send this packet is shared in many chat messages
|
||||||
// that are sent to the server. Because of this, there are large gaps of unused data in chat messages
|
// that are sent to the server. Because of this, there are large gaps of unused data in chat messages
|
||||||
void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
void ChatPacketHandler::HandleChatMessage(Packet* packet) {
|
||||||
|
|||||||
@@ -50,6 +50,8 @@ namespace ChatPacketHandler {
|
|||||||
void HandleFriendResponse(Packet* packet);
|
void HandleFriendResponse(Packet* packet);
|
||||||
void HandleRemoveFriend(Packet* packet);
|
void HandleRemoveFriend(Packet* packet);
|
||||||
void HandleGMLevelUpdate(Packet* packet);
|
void HandleGMLevelUpdate(Packet* packet);
|
||||||
|
void HandleWho(Packet* packet);
|
||||||
|
void HandleShowAll(Packet* packet);
|
||||||
|
|
||||||
void HandleChatMessage(Packet* packet);
|
void HandleChatMessage(Packet* packet);
|
||||||
void HandlePrivateChatMessage(Packet* packet);
|
void HandlePrivateChatMessage(Packet* packet);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "eWorldMessageType.h"
|
#include "eWorldMessageType.h"
|
||||||
#include "ChatIgnoreList.h"
|
#include "ChatIgnoreList.h"
|
||||||
#include "StringifiedEnum.h"
|
#include "StringifiedEnum.h"
|
||||||
|
#include "ChatWebApi.h"
|
||||||
|
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Server.h"
|
#include "Server.h"
|
||||||
@@ -36,7 +37,7 @@ namespace Game {
|
|||||||
AssetManager* assetManager = nullptr;
|
AssetManager* assetManager = nullptr;
|
||||||
Game::signal_t lastSignal = 0;
|
Game::signal_t lastSignal = 0;
|
||||||
std::mt19937 randomEngine;
|
std::mt19937 randomEngine;
|
||||||
PlayerContainer playerContainer;
|
PlayerContainer playerContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandlePacket(Packet* packet);
|
void HandlePacket(Packet* packet);
|
||||||
@@ -122,6 +123,9 @@ int main(int argc, char** argv) {
|
|||||||
uint32_t framesSinceMasterDisconnect = 0;
|
uint32_t framesSinceMasterDisconnect = 0;
|
||||||
uint32_t framesSinceLastSQLPing = 0;
|
uint32_t framesSinceLastSQLPing = 0;
|
||||||
|
|
||||||
|
// start the web api thread
|
||||||
|
std::thread webAPIThread(ChatWebApi::Listen, ourPort);
|
||||||
|
|
||||||
Game::logger->Flush(); // once immediately before main loop
|
Game::logger->Flush(); // once immediately before main loop
|
||||||
while (!Game::ShouldShutdown()) {
|
while (!Game::ShouldShutdown()) {
|
||||||
//Check if we're still connected to master:
|
//Check if we're still connected to master:
|
||||||
@@ -174,6 +178,10 @@ int main(int argc, char** argv) {
|
|||||||
delete Game::server;
|
delete Game::server;
|
||||||
delete Game::logger;
|
delete Game::logger;
|
||||||
delete Game::config;
|
delete Game::config;
|
||||||
|
|
||||||
|
// rejoin the web api thread
|
||||||
|
ChatWebApi::Stop();
|
||||||
|
webAPIThread.join();
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -289,7 +297,11 @@ void HandlePacket(Packet* packet) {
|
|||||||
Game::playerContainer.RemovePlayer(packet);
|
Game::playerContainer.RemovePlayer(packet);
|
||||||
break;
|
break;
|
||||||
case eChatMessageType::WHO:
|
case eChatMessageType::WHO:
|
||||||
|
ChatPacketHandler::HandleWho(packet);
|
||||||
|
break;
|
||||||
case eChatMessageType::SHOW_ALL:
|
case eChatMessageType::SHOW_ALL:
|
||||||
|
ChatPacketHandler::HandleShowAll(packet);
|
||||||
|
break;
|
||||||
case eChatMessageType::USER_CHANNEL_CHAT_MESSAGE:
|
case eChatMessageType::USER_CHANNEL_CHAT_MESSAGE:
|
||||||
case eChatMessageType::WORLD_DISCONNECT_REQUEST:
|
case eChatMessageType::WORLD_DISCONNECT_REQUEST:
|
||||||
case eChatMessageType::WORLD_PROXIMITY_RESPONSE:
|
case eChatMessageType::WORLD_PROXIMITY_RESPONSE:
|
||||||
|
|||||||
93
dChatServer/ChatWebApi.cpp
Normal file
93
dChatServer/ChatWebApi.cpp
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#include "ChatWebApi.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "dCommonVars.h"
|
||||||
|
#include "eConnectionType.h"
|
||||||
|
#include "eChatMessageType.h"
|
||||||
|
#include "httplib.h"
|
||||||
|
#include "dServer.h"
|
||||||
|
#include "PlayerContainer.h"
|
||||||
|
#include "dConfig.h"
|
||||||
|
#include "httplib.h"
|
||||||
|
#include "nlohmann/json.hpp"
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
httplib::Server m_APIServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChatWebApi::Listen(const uint32_t port) {
|
||||||
|
if (Game::config->GetValue("enable_chat_web_api") != "1") {
|
||||||
|
LOG("Chat Web API is disabled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LOG("Chat Web API is enabled, starting web server...");
|
||||||
|
|
||||||
|
m_APIServer.Post("/announce", [](const httplib::Request& req, httplib::Response& res) {
|
||||||
|
const json data = json::parse(req.body);
|
||||||
|
if (!data.contains("title")) {
|
||||||
|
res.set_content("{\"error\":\"Missing paramater: title\"}", "application/json");
|
||||||
|
res.status = 400;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::string title = data["title"];
|
||||||
|
if (!data.contains("message")) {
|
||||||
|
res.set_content("{\"error\":\"Missing paramater: message\"}", "application/json");
|
||||||
|
res.status = 400;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::string message = data["message"];
|
||||||
|
// build and send the packet to all world servers
|
||||||
|
CBITSTREAM;
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GM_ANNOUNCE);
|
||||||
|
bitStream.Write<uint32_t>(title.size());
|
||||||
|
bitStream.Write(title);
|
||||||
|
bitStream.Write<uint32_t>(message.size());
|
||||||
|
bitStream.Write(message);
|
||||||
|
Game::server->Send(bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_APIServer.Get("/players", [](const httplib::Request& req, httplib::Response& res) {
|
||||||
|
auto data = json::array();
|
||||||
|
for (auto& [playerID, playerData ]: Game::playerContainer.GetAllPlayers()){
|
||||||
|
if (!playerData) continue;
|
||||||
|
data.push_back(playerData.to_json());
|
||||||
|
}
|
||||||
|
res.set_content(data.dump(), "application/json");
|
||||||
|
if (data.empty()) res.status = 204;
|
||||||
|
});
|
||||||
|
|
||||||
|
m_APIServer.Get("/teams", [](const httplib::Request& req, httplib::Response& res) {
|
||||||
|
auto data = json::array();
|
||||||
|
for (auto& teamData: Game::playerContainer.GetAllTeams()){
|
||||||
|
if (!teamData) continue;
|
||||||
|
json toInsert;
|
||||||
|
toInsert["id"] = teamData->teamID;
|
||||||
|
toInsert["loot_flag"] = teamData->lootFlag;
|
||||||
|
toInsert["local"] = teamData->local;
|
||||||
|
|
||||||
|
auto& leader = Game::playerContainer.GetPlayerData(teamData->leaderID);
|
||||||
|
toInsert["leader"] = leader.to_json();
|
||||||
|
|
||||||
|
json members;
|
||||||
|
for (auto& member : teamData->memberIDs){
|
||||||
|
auto playerData = Game::playerContainer.GetPlayerData(member);
|
||||||
|
if (!playerData) continue;
|
||||||
|
members.push_back(playerData.to_json());
|
||||||
|
}
|
||||||
|
toInsert["members"] = members;
|
||||||
|
data.push_back(toInsert);
|
||||||
|
}
|
||||||
|
res.set_content(data.dump(), "application/json");
|
||||||
|
if (data.empty()) res.status = 204;
|
||||||
|
});
|
||||||
|
|
||||||
|
m_APIServer.listen(Game::config->GetValue("chat_web_api_listen_address").c_str(), port);
|
||||||
|
};
|
||||||
|
|
||||||
|
void ChatWebApi::Stop(){
|
||||||
|
LOG("Stopping Chat Web API server...");
|
||||||
|
m_APIServer.stop();
|
||||||
|
}
|
||||||
6
dChatServer/ChatWebApi.h
Normal file
6
dChatServer/ChatWebApi.h
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace ChatWebApi {
|
||||||
|
void Listen(const uint32_t port);
|
||||||
|
void Stop();
|
||||||
|
};
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
#include "PlayerContainer.h"
|
#include "PlayerContainer.h"
|
||||||
#include "dNetCommon.h"
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "dNetCommon.h"
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "ChatPacketHandler.h"
|
#include "ChatPacketHandler.h"
|
||||||
@@ -11,7 +13,24 @@
|
|||||||
#include "eConnectionType.h"
|
#include "eConnectionType.h"
|
||||||
#include "ChatPackets.h"
|
#include "ChatPackets.h"
|
||||||
#include "dConfig.h"
|
#include "dConfig.h"
|
||||||
#include "eChatMessageType.h"
|
#include "eChatMessageType.h"
|
||||||
|
|
||||||
|
using json = nlohmann::json;
|
||||||
|
|
||||||
|
const json PlayerData::to_json() const {
|
||||||
|
json data;
|
||||||
|
data["id"] = this->playerID;
|
||||||
|
data["name"] = this->playerName;
|
||||||
|
data["gm_level"] = this->gmLevel;
|
||||||
|
data["muted"] = this->GetIsMuted();
|
||||||
|
|
||||||
|
json zoneID;
|
||||||
|
zoneID["map_id"] = std::to_string(this->zoneID.GetMapID());
|
||||||
|
zoneID["instance_id"] = std::to_string(this->zoneID.GetInstanceID());
|
||||||
|
zoneID["clone_id"] = std::to_string(this->zoneID.GetCloneID());
|
||||||
|
data["zone_id"] = zoneID;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
void PlayerContainer::Initialize() {
|
void PlayerContainer::Initialize() {
|
||||||
m_MaxNumberOfBestFriends =
|
m_MaxNumberOfBestFriends =
|
||||||
@@ -49,6 +68,7 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
|
|||||||
data.sysAddr = packet->systemAddress;
|
data.sysAddr = packet->systemAddress;
|
||||||
|
|
||||||
m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName);
|
m_Names[data.playerID] = GeneralUtils::UTF8ToUTF16(data.playerName);
|
||||||
|
m_PlayerCount++;
|
||||||
|
|
||||||
LOG("Added user: %s (%llu), zone: %i", data.playerName.c_str(), data.playerID, data.zoneID.GetMapID());
|
LOG("Added user: %s (%llu), zone: %i", data.playerName.c_str(), data.playerID, data.zoneID.GetMapID());
|
||||||
|
|
||||||
@@ -87,6 +107,7 @@ void PlayerContainer::RemovePlayer(Packet* packet) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_PlayerCount--;
|
||||||
LOG("Removed user: %llu", playerID);
|
LOG("Removed user: %llu", playerID);
|
||||||
m_Players.erase(playerID);
|
m_Players.erase(playerID);
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "dServer.h"
|
#include "dServer.h"
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include "nlohmann/json.hpp"
|
||||||
|
|
||||||
enum class eGameMasterLevel : uint8_t;
|
enum class eGameMasterLevel : uint8_t;
|
||||||
|
|
||||||
@@ -36,6 +37,8 @@ struct PlayerData {
|
|||||||
return muteExpire == 1 || muteExpire > time(NULL);
|
return muteExpire == 1 || muteExpire > time(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const nlohmann::json to_json() const;
|
||||||
|
|
||||||
SystemAddress sysAddr{};
|
SystemAddress sysAddr{};
|
||||||
LWOZONEID zoneID{};
|
LWOZONEID zoneID{};
|
||||||
LWOOBJID playerID = LWOOBJID_EMPTY;
|
LWOOBJID playerID = LWOOBJID_EMPTY;
|
||||||
@@ -71,6 +74,9 @@ public:
|
|||||||
const PlayerData& GetPlayerData(const std::string& playerName);
|
const PlayerData& GetPlayerData(const std::string& playerName);
|
||||||
PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID);
|
PlayerData& GetPlayerDataMutable(const LWOOBJID& playerID);
|
||||||
PlayerData& GetPlayerDataMutable(const std::string& playerName);
|
PlayerData& GetPlayerDataMutable(const std::string& playerName);
|
||||||
|
uint32_t GetPlayerCount() { return m_PlayerCount; };
|
||||||
|
uint32_t GetSimCount() { return m_SimCount; };
|
||||||
|
const std::map<LWOOBJID, PlayerData>& GetAllPlayers() { return m_Players; };
|
||||||
|
|
||||||
TeamData* CreateLocalTeam(std::vector<LWOOBJID> members);
|
TeamData* CreateLocalTeam(std::vector<LWOOBJID> members);
|
||||||
TeamData* CreateTeam(LWOOBJID leader, bool local = false);
|
TeamData* CreateTeam(LWOOBJID leader, bool local = false);
|
||||||
@@ -85,6 +91,7 @@ public:
|
|||||||
LWOOBJID GetId(const std::u16string& playerName);
|
LWOOBJID GetId(const std::u16string& playerName);
|
||||||
uint32_t GetMaxNumberOfBestFriends() { return m_MaxNumberOfBestFriends; }
|
uint32_t GetMaxNumberOfBestFriends() { return m_MaxNumberOfBestFriends; }
|
||||||
uint32_t GetMaxNumberOfFriends() { return m_MaxNumberOfFriends; }
|
uint32_t GetMaxNumberOfFriends() { return m_MaxNumberOfFriends; }
|
||||||
|
const std::vector<TeamData*>& GetAllTeams() { return mTeams;};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
LWOOBJID m_TeamIDCounter = 0;
|
LWOOBJID m_TeamIDCounter = 0;
|
||||||
@@ -93,5 +100,7 @@ private:
|
|||||||
std::unordered_map<LWOOBJID, std::u16string> m_Names;
|
std::unordered_map<LWOOBJID, std::u16string> m_Names;
|
||||||
uint32_t m_MaxNumberOfBestFriends = 5;
|
uint32_t m_MaxNumberOfBestFriends = 5;
|
||||||
uint32_t m_MaxNumberOfFriends = 50;
|
uint32_t m_MaxNumberOfFriends = 50;
|
||||||
|
uint32_t m_PlayerCount = 0;
|
||||||
|
uint32_t m_SimCount = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,23 +8,23 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline size_t MinSize(size_t size, const std::basic_string_view<T>& string) {
|
static inline size_t MinSize(const size_t size, const std::basic_string_view<T> string) {
|
||||||
if (size == size_t(-1) || size > string.size()) {
|
if (size == SIZE_MAX || size > string.size()) {
|
||||||
return string.size();
|
return string.size();
|
||||||
} else {
|
} else {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool IsLeadSurrogate(char16_t c) {
|
inline bool IsLeadSurrogate(const char16_t c) {
|
||||||
return (0xD800 <= c) && (c <= 0xDBFF);
|
return (0xD800 <= c) && (c <= 0xDBFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool IsTrailSurrogate(char16_t c) {
|
inline bool IsTrailSurrogate(const char16_t c) {
|
||||||
return (0xDC00 <= c) && (c <= 0xDFFF);
|
return (0xDC00 <= c) && (c <= 0xDFFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void PushUTF8CodePoint(std::string& ret, char32_t cp) {
|
inline void PushUTF8CodePoint(std::string& ret, const char32_t cp) {
|
||||||
if (cp <= 0x007F) {
|
if (cp <= 0x007F) {
|
||||||
ret.push_back(static_cast<uint8_t>(cp));
|
ret.push_back(static_cast<uint8_t>(cp));
|
||||||
} else if (cp <= 0x07FF) {
|
} else if (cp <= 0x07FF) {
|
||||||
@@ -46,16 +46,16 @@ inline void PushUTF8CodePoint(std::string& ret, char32_t cp) {
|
|||||||
|
|
||||||
constexpr const char16_t REPLACEMENT_CHARACTER = 0xFFFD;
|
constexpr const char16_t REPLACEMENT_CHARACTER = 0xFFFD;
|
||||||
|
|
||||||
bool _IsSuffixChar(uint8_t c) {
|
bool static _IsSuffixChar(const uint8_t c) {
|
||||||
return (c & 0xC0) == 0x80;
|
return (c & 0xC0) == 0x80;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
bool GeneralUtils::details::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||||
size_t rem = slice.length();
|
const size_t rem = slice.length();
|
||||||
if (slice.empty()) return false;
|
if (slice.empty()) return false;
|
||||||
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&slice.front());
|
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&slice.front());
|
||||||
if (rem > 0) {
|
if (rem > 0) {
|
||||||
uint8_t first = bytes[0];
|
const uint8_t first = bytes[0];
|
||||||
if (first < 0x80) { // 1 byte character
|
if (first < 0x80) { // 1 byte character
|
||||||
out = static_cast<uint32_t>(first & 0x7F);
|
out = static_cast<uint32_t>(first & 0x7F);
|
||||||
slice.remove_prefix(1);
|
slice.remove_prefix(1);
|
||||||
@@ -64,7 +64,7 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
|||||||
// middle byte, not valid at start, fall through
|
// middle byte, not valid at start, fall through
|
||||||
} else if (first < 0xE0) { // two byte character
|
} else if (first < 0xE0) { // two byte character
|
||||||
if (rem > 1) {
|
if (rem > 1) {
|
||||||
uint8_t second = bytes[1];
|
const uint8_t second = bytes[1];
|
||||||
if (_IsSuffixChar(second)) {
|
if (_IsSuffixChar(second)) {
|
||||||
out = (static_cast<uint32_t>(first & 0x1F) << 6)
|
out = (static_cast<uint32_t>(first & 0x1F) << 6)
|
||||||
+ static_cast<uint32_t>(second & 0x3F);
|
+ static_cast<uint32_t>(second & 0x3F);
|
||||||
@@ -74,8 +74,8 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
|||||||
}
|
}
|
||||||
} else if (first < 0xF0) { // three byte character
|
} else if (first < 0xF0) { // three byte character
|
||||||
if (rem > 2) {
|
if (rem > 2) {
|
||||||
uint8_t second = bytes[1];
|
const uint8_t second = bytes[1];
|
||||||
uint8_t third = bytes[2];
|
const uint8_t third = bytes[2];
|
||||||
if (_IsSuffixChar(second) && _IsSuffixChar(third)) {
|
if (_IsSuffixChar(second) && _IsSuffixChar(third)) {
|
||||||
out = (static_cast<uint32_t>(first & 0x0F) << 12)
|
out = (static_cast<uint32_t>(first & 0x0F) << 12)
|
||||||
+ (static_cast<uint32_t>(second & 0x3F) << 6)
|
+ (static_cast<uint32_t>(second & 0x3F) << 6)
|
||||||
@@ -86,9 +86,9 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
|||||||
}
|
}
|
||||||
} else if (first < 0xF8) { // four byte character
|
} else if (first < 0xF8) { // four byte character
|
||||||
if (rem > 3) {
|
if (rem > 3) {
|
||||||
uint8_t second = bytes[1];
|
const uint8_t second = bytes[1];
|
||||||
uint8_t third = bytes[2];
|
const uint8_t third = bytes[2];
|
||||||
uint8_t fourth = bytes[3];
|
const uint8_t fourth = bytes[3];
|
||||||
if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) {
|
if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) {
|
||||||
out = (static_cast<uint32_t>(first & 0x07) << 18)
|
out = (static_cast<uint32_t>(first & 0x07) << 18)
|
||||||
+ (static_cast<uint32_t>(second & 0x3F) << 12)
|
+ (static_cast<uint32_t>(second & 0x3F) << 12)
|
||||||
@@ -107,7 +107,7 @@ bool GeneralUtils::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// See <https://www.ietf.org/rfc/rfc2781.html#section-2.1>
|
/// See <https://www.ietf.org/rfc/rfc2781.html#section-2.1>
|
||||||
bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) {
|
bool PushUTF16CodePoint(std::u16string& output, const uint32_t U, const size_t size) {
|
||||||
if (output.length() >= size) return false;
|
if (output.length() >= size) return false;
|
||||||
if (U < 0x10000) {
|
if (U < 0x10000) {
|
||||||
// If U < 0x10000, encode U as a 16-bit unsigned integer and terminate.
|
// If U < 0x10000, encode U as a 16-bit unsigned integer and terminate.
|
||||||
@@ -120,7 +120,7 @@ bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) {
|
|||||||
// Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
|
// Let U' = U - 0x10000. Because U is less than or equal to 0x10FFFF,
|
||||||
// U' must be less than or equal to 0xFFFFF. That is, U' can be
|
// U' must be less than or equal to 0xFFFFF. That is, U' can be
|
||||||
// represented in 20 bits.
|
// represented in 20 bits.
|
||||||
uint32_t Ut = U - 0x10000;
|
const uint32_t Ut = U - 0x10000;
|
||||||
|
|
||||||
// Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
|
// Initialize two 16-bit unsigned integers, W1 and W2, to 0xD800 and
|
||||||
// 0xDC00, respectively. These integers each have 10 bits free to
|
// 0xDC00, respectively. These integers each have 10 bits free to
|
||||||
@@ -141,25 +141,25 @@ bool PushUTF16CodePoint(std::u16string& output, uint32_t U, size_t size) {
|
|||||||
} else return false;
|
} else return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view& string, size_t size) {
|
std::u16string GeneralUtils::UTF8ToUTF16(const std::string_view string, const size_t size) {
|
||||||
size_t newSize = MinSize(size, string);
|
const size_t newSize = MinSize(size, string);
|
||||||
std::u16string output;
|
std::u16string output;
|
||||||
output.reserve(newSize);
|
output.reserve(newSize);
|
||||||
std::string_view iterator = string;
|
std::string_view iterator = string;
|
||||||
|
|
||||||
uint32_t c;
|
uint32_t c;
|
||||||
while (_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {}
|
while (details::_NextUTF8Char(iterator, c) && PushUTF16CodePoint(output, c, size)) {}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Converts an std::string (ASCII) to UCS-2 / UTF-16
|
//! Converts an std::string (ASCII) to UCS-2 / UTF-16
|
||||||
std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t size) {
|
std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view string, const size_t size) {
|
||||||
size_t newSize = MinSize(size, string);
|
const size_t newSize = MinSize(size, string);
|
||||||
std::u16string ret;
|
std::u16string ret;
|
||||||
ret.reserve(newSize);
|
ret.reserve(newSize);
|
||||||
|
|
||||||
for (size_t i = 0; i < newSize; i++) {
|
for (size_t i = 0; i < newSize; ++i) {
|
||||||
char c = string[i];
|
const char c = string[i];
|
||||||
// Note: both 7-bit ascii characters and REPLACEMENT_CHARACTER fit in one char16_t
|
// Note: both 7-bit ascii characters and REPLACEMENT_CHARACTER fit in one char16_t
|
||||||
ret.push_back((c > 0 && c <= 127) ? static_cast<char16_t>(c) : REPLACEMENT_CHARACTER);
|
ret.push_back((c > 0 && c <= 127) ? static_cast<char16_t>(c) : REPLACEMENT_CHARACTER);
|
||||||
}
|
}
|
||||||
@@ -169,18 +169,18 @@ std::u16string GeneralUtils::ASCIIToUTF16(const std::string_view& string, size_t
|
|||||||
|
|
||||||
//! Converts a (potentially-ill-formed) UTF-16 string to UTF-8
|
//! Converts a (potentially-ill-formed) UTF-16 string to UTF-8
|
||||||
//! See: <http://simonsapin.github.io/wtf-8/#decoding-ill-formed-utf-16>
|
//! See: <http://simonsapin.github.io/wtf-8/#decoding-ill-formed-utf-16>
|
||||||
std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t size) {
|
std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view string, const size_t size) {
|
||||||
size_t newSize = MinSize(size, string);
|
const size_t newSize = MinSize(size, string);
|
||||||
std::string ret;
|
std::string ret;
|
||||||
ret.reserve(newSize);
|
ret.reserve(newSize);
|
||||||
|
|
||||||
for (size_t i = 0; i < newSize; i++) {
|
for (size_t i = 0; i < newSize; ++i) {
|
||||||
char16_t u = string[i];
|
const char16_t u = string[i];
|
||||||
if (IsLeadSurrogate(u) && (i + 1) < newSize) {
|
if (IsLeadSurrogate(u) && (i + 1) < newSize) {
|
||||||
char16_t next = string[i + 1];
|
const char16_t next = string[i + 1];
|
||||||
if (IsTrailSurrogate(next)) {
|
if (IsTrailSurrogate(next)) {
|
||||||
i += 1;
|
i += 1;
|
||||||
char32_t cp = 0x10000
|
const char32_t cp = 0x10000
|
||||||
+ ((static_cast<char32_t>(u) - 0xD800) << 10)
|
+ ((static_cast<char32_t>(u) - 0xD800) << 10)
|
||||||
+ (static_cast<char32_t>(next) - 0xDC00);
|
+ (static_cast<char32_t>(next) - 0xDC00);
|
||||||
PushUTF8CodePoint(ret, cp);
|
PushUTF8CodePoint(ret, cp);
|
||||||
@@ -195,40 +195,40 @@ std::string GeneralUtils::UTF16ToWTF8(const std::u16string_view& string, size_t
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneralUtils::CaseInsensitiveStringCompare(const std::string& a, const std::string& b) {
|
bool GeneralUtils::CaseInsensitiveStringCompare(const std::string_view a, const std::string_view b) {
|
||||||
return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { return tolower(a) == tolower(b); });
|
return std::equal(a.begin(), a.end(), b.begin(), b.end(), [](char a, char b) { return tolower(a) == tolower(b); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Bits
|
// MARK: Bits
|
||||||
|
|
||||||
//! Sets a specific bit in a signed 64-bit integer
|
//! Sets a specific bit in a signed 64-bit integer
|
||||||
int64_t GeneralUtils::SetBit(int64_t value, uint32_t index) {
|
int64_t GeneralUtils::SetBit(int64_t value, const uint32_t index) {
|
||||||
return value |= 1ULL << index;
|
return value |= 1ULL << index;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Clears a specific bit in a signed 64-bit integer
|
//! Clears a specific bit in a signed 64-bit integer
|
||||||
int64_t GeneralUtils::ClearBit(int64_t value, uint32_t index) {
|
int64_t GeneralUtils::ClearBit(int64_t value, const uint32_t index) {
|
||||||
return value &= ~(1ULL << index);
|
return value &= ~(1ULL << index);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Checks a specific bit in a signed 64-bit integer
|
//! Checks a specific bit in a signed 64-bit integer
|
||||||
bool GeneralUtils::CheckBit(int64_t value, uint32_t index) {
|
bool GeneralUtils::CheckBit(int64_t value, const uint32_t index) {
|
||||||
return value & (1ULL << index);
|
return value & (1ULL << index);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GeneralUtils::ReplaceInString(std::string& str, const std::string& from, const std::string& to) {
|
bool GeneralUtils::ReplaceInString(std::string& str, const std::string_view from, const std::string_view to) {
|
||||||
size_t start_pos = str.find(from);
|
const size_t start_pos = str.find(from);
|
||||||
if (start_pos == std::string::npos)
|
if (start_pos == std::string::npos)
|
||||||
return false;
|
return false;
|
||||||
str.replace(start_pos, from.length(), to);
|
str.replace(start_pos, from.length(), to);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t delimiter) {
|
std::vector<std::wstring> GeneralUtils::SplitString(const std::wstring_view str, const wchar_t delimiter) {
|
||||||
std::vector<std::wstring> vector = std::vector<std::wstring>();
|
std::vector<std::wstring> vector = std::vector<std::wstring>();
|
||||||
std::wstring current;
|
std::wstring current;
|
||||||
|
|
||||||
for (const auto& c : str) {
|
for (const wchar_t c : str) {
|
||||||
if (c == delimiter) {
|
if (c == delimiter) {
|
||||||
vector.push_back(current);
|
vector.push_back(current);
|
||||||
current = L"";
|
current = L"";
|
||||||
@@ -237,15 +237,15 @@ std::vector<std::wstring> GeneralUtils::SplitString(std::wstring& str, wchar_t d
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vector.push_back(current);
|
vector.push_back(std::move(current));
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string& str, char16_t delimiter) {
|
std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string_view str, const char16_t delimiter) {
|
||||||
std::vector<std::u16string> vector = std::vector<std::u16string>();
|
std::vector<std::u16string> vector = std::vector<std::u16string>();
|
||||||
std::u16string current;
|
std::u16string current;
|
||||||
|
|
||||||
for (const auto& c : str) {
|
for (const char16_t c : str) {
|
||||||
if (c == delimiter) {
|
if (c == delimiter) {
|
||||||
vector.push_back(current);
|
vector.push_back(current);
|
||||||
current = u"";
|
current = u"";
|
||||||
@@ -254,17 +254,15 @@ std::vector<std::u16string> GeneralUtils::SplitString(const std::u16string& str,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vector.push_back(current);
|
vector.push_back(std::move(current));
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char delimiter) {
|
std::vector<std::string> GeneralUtils::SplitString(const std::string_view str, const char delimiter) {
|
||||||
std::vector<std::string> vector = std::vector<std::string>();
|
std::vector<std::string> vector = std::vector<std::string>();
|
||||||
std::string current = "";
|
std::string current = "";
|
||||||
|
|
||||||
for (size_t i = 0; i < str.length(); i++) {
|
for (const char c : str) {
|
||||||
char c = str[i];
|
|
||||||
|
|
||||||
if (c == delimiter) {
|
if (c == delimiter) {
|
||||||
vector.push_back(current);
|
vector.push_back(current);
|
||||||
current = "";
|
current = "";
|
||||||
@@ -273,8 +271,7 @@ std::vector<std::string> GeneralUtils::SplitString(const std::string& str, char
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vector.push_back(current);
|
vector.push_back(std::move(current));
|
||||||
|
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,7 +280,7 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) {
|
|||||||
inStream.Read<uint32_t>(length);
|
inStream.Read<uint32_t>(length);
|
||||||
|
|
||||||
std::u16string string;
|
std::u16string string;
|
||||||
for (auto i = 0; i < length; i++) {
|
for (uint32_t i = 0; i < length; ++i) {
|
||||||
uint16_t c;
|
uint16_t c;
|
||||||
inStream.Read(c);
|
inStream.Read(c);
|
||||||
string.push_back(c);
|
string.push_back(c);
|
||||||
@@ -292,29 +289,29 @@ std::u16string GeneralUtils::ReadWString(RakNet::BitStream& inStream) {
|
|||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::string& folder) {
|
std::vector<std::string> GeneralUtils::GetSqlFileNamesFromFolder(const std::string_view folder) {
|
||||||
// Because we dont know how large the initial number before the first _ is we need to make it a map like so.
|
// Because we dont know how large the initial number before the first _ is we need to make it a map like so.
|
||||||
std::map<uint32_t, std::string> filenames{};
|
std::map<uint32_t, std::string> filenames{};
|
||||||
for (auto& t : std::filesystem::directory_iterator(folder)) {
|
for (const auto& t : std::filesystem::directory_iterator(folder)) {
|
||||||
auto filename = t.path().filename().string();
|
auto filename = t.path().filename().string();
|
||||||
auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0));
|
const auto index = std::stoi(GeneralUtils::SplitString(filename, '_').at(0));
|
||||||
filenames.insert(std::make_pair(index, filename));
|
filenames.emplace(index, std::move(filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now sort the map by the oldest migration.
|
// Now sort the map by the oldest migration.
|
||||||
std::vector<std::string> sortedFiles{};
|
std::vector<std::string> sortedFiles{};
|
||||||
auto fileIterator = filenames.begin();
|
auto fileIterator = filenames.cbegin();
|
||||||
std::map<uint32_t, std::string>::iterator oldest = filenames.begin();
|
auto oldest = filenames.cbegin();
|
||||||
while (!filenames.empty()) {
|
while (!filenames.empty()) {
|
||||||
if (fileIterator == filenames.end()) {
|
if (fileIterator == filenames.cend()) {
|
||||||
sortedFiles.push_back(oldest->second);
|
sortedFiles.push_back(oldest->second);
|
||||||
filenames.erase(oldest);
|
filenames.erase(oldest);
|
||||||
fileIterator = filenames.begin();
|
fileIterator = filenames.cbegin();
|
||||||
oldest = filenames.begin();
|
oldest = filenames.cbegin();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (oldest->first > fileIterator->first) oldest = fileIterator;
|
if (oldest->first > fileIterator->first) oldest = fileIterator;
|
||||||
fileIterator++;
|
++fileIterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
return sortedFiles;
|
return sortedFiles;
|
||||||
|
|||||||
@@ -3,17 +3,18 @@
|
|||||||
// C++
|
// C++
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <random>
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <functional>
|
||||||
|
#include <optional>
|
||||||
|
#include <random>
|
||||||
|
#include <span>
|
||||||
|
#include <stdexcept>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <optional>
|
|
||||||
#include <functional>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <stdexcept>
|
|
||||||
#include "BitStream.h"
|
#include "BitStream.h"
|
||||||
#include "NiPoint3.h"
|
#include "NiPoint3.h"
|
||||||
|
|
||||||
#include "dPlatforms.h"
|
#include "dPlatforms.h"
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
@@ -32,29 +33,31 @@ namespace GeneralUtils {
|
|||||||
//! Converts a plain ASCII string to a UTF-16 string
|
//! Converts a plain ASCII string to a UTF-16 string
|
||||||
/*!
|
/*!
|
||||||
\param string The string to convert
|
\param string The string to convert
|
||||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
\param size A size to trim the string to. Default is SIZE_MAX (No trimming)
|
||||||
\return An UTF-16 representation of the string
|
\return An UTF-16 representation of the string
|
||||||
*/
|
*/
|
||||||
std::u16string ASCIIToUTF16(const std::string_view& string, size_t size = -1);
|
std::u16string ASCIIToUTF16(const std::string_view string, const size_t size = SIZE_MAX);
|
||||||
|
|
||||||
//! Converts a UTF-8 String to a UTF-16 string
|
//! Converts a UTF-8 String to a UTF-16 string
|
||||||
/*!
|
/*!
|
||||||
\param string The string to convert
|
\param string The string to convert
|
||||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
\param size A size to trim the string to. Default is SIZE_MAX (No trimming)
|
||||||
\return An UTF-16 representation of the string
|
\return An UTF-16 representation of the string
|
||||||
*/
|
*/
|
||||||
std::u16string UTF8ToUTF16(const std::string_view& string, size_t size = -1);
|
std::u16string UTF8ToUTF16(const std::string_view string, const size_t size = SIZE_MAX);
|
||||||
|
|
||||||
//! Internal, do not use
|
namespace details {
|
||||||
bool _NextUTF8Char(std::string_view& slice, uint32_t& out);
|
//! Internal, do not use
|
||||||
|
bool _NextUTF8Char(std::string_view& slice, uint32_t& out);
|
||||||
|
}
|
||||||
|
|
||||||
//! Converts a UTF-16 string to a UTF-8 string
|
//! Converts a UTF-16 string to a UTF-8 string
|
||||||
/*!
|
/*!
|
||||||
\param string The string to convert
|
\param string The string to convert
|
||||||
\param size A size to trim the string to. Default is -1 (No trimming)
|
\param size A size to trim the string to. Default is SIZE_MAX (No trimming)
|
||||||
\return An UTF-8 representation of the string
|
\return An UTF-8 representation of the string
|
||||||
*/
|
*/
|
||||||
std::string UTF16ToWTF8(const std::u16string_view& string, size_t size = -1);
|
std::string UTF16ToWTF8(const std::u16string_view string, const size_t size = SIZE_MAX);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compares two basic strings but does so ignoring case sensitivity
|
* Compares two basic strings but does so ignoring case sensitivity
|
||||||
@@ -62,7 +65,7 @@ namespace GeneralUtils {
|
|||||||
* \param b the second string to compare against the first string
|
* \param b the second string to compare against the first string
|
||||||
* @return if the two strings are equal
|
* @return if the two strings are equal
|
||||||
*/
|
*/
|
||||||
bool CaseInsensitiveStringCompare(const std::string& a, const std::string& b);
|
bool CaseInsensitiveStringCompare(const std::string_view a, const std::string_view b);
|
||||||
|
|
||||||
// MARK: Bits
|
// MARK: Bits
|
||||||
|
|
||||||
@@ -70,9 +73,9 @@ namespace GeneralUtils {
|
|||||||
|
|
||||||
//! Sets a bit on a numerical value
|
//! Sets a bit on a numerical value
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void SetBit(T& value, eObjectBits bits) {
|
inline void SetBit(T& value, const eObjectBits bits) {
|
||||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||||
auto index = static_cast<size_t>(bits);
|
const auto index = static_cast<size_t>(bits);
|
||||||
if (index > (sizeof(T) * 8) - 1) {
|
if (index > (sizeof(T) * 8) - 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -82,9 +85,9 @@ namespace GeneralUtils {
|
|||||||
|
|
||||||
//! Clears a bit on a numerical value
|
//! Clears a bit on a numerical value
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline void ClearBit(T& value, eObjectBits bits) {
|
inline void ClearBit(T& value, const eObjectBits bits) {
|
||||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||||
auto index = static_cast<size_t>(bits);
|
const auto index = static_cast<size_t>(bits);
|
||||||
if (index > (sizeof(T) * 8 - 1)) {
|
if (index > (sizeof(T) * 8 - 1)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -97,14 +100,14 @@ namespace GeneralUtils {
|
|||||||
\param value The value to set the bit for
|
\param value The value to set the bit for
|
||||||
\param index The index of the bit
|
\param index The index of the bit
|
||||||
*/
|
*/
|
||||||
int64_t SetBit(int64_t value, uint32_t index);
|
int64_t SetBit(int64_t value, const uint32_t index);
|
||||||
|
|
||||||
//! Clears a specific bit in a signed 64-bit integer
|
//! Clears a specific bit in a signed 64-bit integer
|
||||||
/*!
|
/*!
|
||||||
\param value The value to clear the bit from
|
\param value The value to clear the bit from
|
||||||
\param index The index of the bit
|
\param index The index of the bit
|
||||||
*/
|
*/
|
||||||
int64_t ClearBit(int64_t value, uint32_t index);
|
int64_t ClearBit(int64_t value, const uint32_t index);
|
||||||
|
|
||||||
//! Checks a specific bit in a signed 64-bit integer
|
//! Checks a specific bit in a signed 64-bit integer
|
||||||
/*!
|
/*!
|
||||||
@@ -112,19 +115,19 @@ namespace GeneralUtils {
|
|||||||
\param index The index of the bit
|
\param index The index of the bit
|
||||||
\return Whether or not the bit is set
|
\return Whether or not the bit is set
|
||||||
*/
|
*/
|
||||||
bool CheckBit(int64_t value, uint32_t index);
|
bool CheckBit(int64_t value, const uint32_t index);
|
||||||
|
|
||||||
bool ReplaceInString(std::string& str, const std::string& from, const std::string& to);
|
bool ReplaceInString(std::string& str, const std::string_view from, const std::string_view to);
|
||||||
|
|
||||||
std::u16string ReadWString(RakNet::BitStream& inStream);
|
std::u16string ReadWString(RakNet::BitStream& inStream);
|
||||||
|
|
||||||
std::vector<std::wstring> SplitString(std::wstring& str, wchar_t delimiter);
|
std::vector<std::wstring> SplitString(const std::wstring_view str, const wchar_t delimiter);
|
||||||
|
|
||||||
std::vector<std::u16string> SplitString(const std::u16string& str, char16_t delimiter);
|
std::vector<std::u16string> SplitString(const std::u16string_view str, const char16_t delimiter);
|
||||||
|
|
||||||
std::vector<std::string> SplitString(const std::string& str, char delimiter);
|
std::vector<std::string> SplitString(const std::string_view str, const char delimiter);
|
||||||
|
|
||||||
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string& folder);
|
std::vector<std::string> GetSqlFileNamesFromFolder(const std::string_view folder);
|
||||||
|
|
||||||
// Concept constraining to enum types
|
// Concept constraining to enum types
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -144,7 +147,7 @@ namespace GeneralUtils {
|
|||||||
|
|
||||||
// If a boolean, present an alias to an intermediate integral type for parsing
|
// If a boolean, present an alias to an intermediate integral type for parsing
|
||||||
template <Numeric T> requires std::same_as<T, bool>
|
template <Numeric T> requires std::same_as<T, bool>
|
||||||
struct numeric_parse<T> { using type = uint32_t; };
|
struct numeric_parse<T> { using type = uint8_t; };
|
||||||
|
|
||||||
// Shorthand type alias
|
// Shorthand type alias
|
||||||
template <Numeric T>
|
template <Numeric T>
|
||||||
@@ -205,7 +208,7 @@ namespace GeneralUtils {
|
|||||||
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
|
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::string& strX, const std::string& strY, const std::string& strZ) {
|
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::string_view strX, const std::string_view strY, const std::string_view strZ) {
|
||||||
const auto x = TryParse<float>(strX);
|
const auto x = TryParse<float>(strX);
|
||||||
if (!x) return std::nullopt;
|
if (!x) return std::nullopt;
|
||||||
|
|
||||||
@@ -217,17 +220,17 @@ namespace GeneralUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The TryParse overload for handling NiPoint3 by passingn a reference to a vector of three strings
|
* The TryParse overload for handling NiPoint3 by passing a span of three strings
|
||||||
* @param str The string vector representing the X, Y, and Xcoordinates
|
* @param str The string vector representing the X, Y, and Z coordinates
|
||||||
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
|
* @returns An std::optional containing the desired NiPoint3 if it can be constructed from the string parameters
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::vector<std::string>& str) {
|
[[nodiscard]] std::optional<NiPoint3> TryParse(const std::span<const std::string> str) {
|
||||||
return (str.size() == 3) ? TryParse<NiPoint3>(str[0], str[1], str[2]) : std::nullopt;
|
return (str.size() == 3) ? TryParse<NiPoint3>(str[0], str[1], str[2]) : std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::u16string to_u16string(T value) {
|
std::u16string to_u16string(const T value) {
|
||||||
return GeneralUtils::ASCIIToUTF16(std::to_string(value));
|
return GeneralUtils::ASCIIToUTF16(std::to_string(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,7 +249,7 @@ namespace GeneralUtils {
|
|||||||
\param max The maximum to generate to
|
\param max The maximum to generate to
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline T GenerateRandomNumber(std::size_t min, std::size_t max) {
|
inline T GenerateRandomNumber(const std::size_t min, const std::size_t max) {
|
||||||
// Make sure it is a numeric type
|
// Make sure it is a numeric type
|
||||||
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
static_assert(std::is_arithmetic<T>::value, "Not an arithmetic type");
|
||||||
|
|
||||||
@@ -273,10 +276,10 @@ namespace GeneralUtils {
|
|||||||
|
|
||||||
// on Windows we need to undef these or else they conflict with our numeric limits calls
|
// on Windows we need to undef these or else they conflict with our numeric limits calls
|
||||||
// DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS
|
// DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS DEVELOPERS
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#undef min
|
#undef min
|
||||||
#undef max
|
#undef max
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
inline T GenerateRandomNumber() {
|
inline T GenerateRandomNumber() {
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "CDScriptComponentTable.h"
|
#include "CDScriptComponentTable.h"
|
||||||
#include "CDSkillBehaviorTable.h"
|
#include "CDSkillBehaviorTable.h"
|
||||||
#include "CDZoneTableTable.h"
|
#include "CDZoneTableTable.h"
|
||||||
|
#include "CDTamingBuildPuzzleTable.h"
|
||||||
#include "CDVendorComponentTable.h"
|
#include "CDVendorComponentTable.h"
|
||||||
#include "CDActivitiesTable.h"
|
#include "CDActivitiesTable.h"
|
||||||
#include "CDPackageComponentTable.h"
|
#include "CDPackageComponentTable.h"
|
||||||
@@ -41,8 +42,6 @@
|
|||||||
#include "CDRewardCodesTable.h"
|
#include "CDRewardCodesTable.h"
|
||||||
#include "CDPetComponentTable.h"
|
#include "CDPetComponentTable.h"
|
||||||
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
#ifndef CDCLIENT_CACHE_ALL
|
#ifndef CDCLIENT_CACHE_ALL
|
||||||
// Uncomment this to cache the full cdclient database into memory. This will make the server load faster, but will use more memory.
|
// 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.
|
||||||
@@ -55,13 +54,6 @@
|
|||||||
#define CDCLIENT_DONT_CACHE_TABLE(x)
|
#define CDCLIENT_DONT_CACHE_TABLE(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class CDClientConnectionException : public std::exception {
|
|
||||||
public:
|
|
||||||
virtual const char* what() const throw() {
|
|
||||||
return "CDClientDatabase is not connected!";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Using a macro to reduce repetitive code and issues from copy and paste.
|
// Using a macro to reduce repetitive code and issues from copy and paste.
|
||||||
// As a note, ## in a macro is used to concatenate two tokens together.
|
// As a note, ## in a macro is used to concatenate two tokens together.
|
||||||
|
|
||||||
@@ -108,11 +100,14 @@ DEFINE_TABLE_STORAGE(CDRewardCodesTable);
|
|||||||
DEFINE_TABLE_STORAGE(CDRewardsTable);
|
DEFINE_TABLE_STORAGE(CDRewardsTable);
|
||||||
DEFINE_TABLE_STORAGE(CDScriptComponentTable);
|
DEFINE_TABLE_STORAGE(CDScriptComponentTable);
|
||||||
DEFINE_TABLE_STORAGE(CDSkillBehaviorTable);
|
DEFINE_TABLE_STORAGE(CDSkillBehaviorTable);
|
||||||
|
DEFINE_TABLE_STORAGE(CDTamingBuildPuzzleTable);
|
||||||
DEFINE_TABLE_STORAGE(CDVendorComponentTable);
|
DEFINE_TABLE_STORAGE(CDVendorComponentTable);
|
||||||
DEFINE_TABLE_STORAGE(CDZoneTableTable);
|
DEFINE_TABLE_STORAGE(CDZoneTableTable);
|
||||||
|
|
||||||
void CDClientManager::LoadValuesFromDatabase() {
|
void CDClientManager::LoadValuesFromDatabase() {
|
||||||
if (!CDClientDatabase::isConnected) throw CDClientConnectionException();
|
if (!CDClientDatabase::isConnected) {
|
||||||
|
throw std::runtime_error{ "CDClientDatabase is not connected!" };
|
||||||
|
}
|
||||||
|
|
||||||
CDActivityRewardsTable::Instance().LoadValuesFromDatabase();
|
CDActivityRewardsTable::Instance().LoadValuesFromDatabase();
|
||||||
CDActivitiesTable::Instance().LoadValuesFromDatabase();
|
CDActivitiesTable::Instance().LoadValuesFromDatabase();
|
||||||
@@ -152,6 +147,7 @@ void CDClientManager::LoadValuesFromDatabase() {
|
|||||||
CDRewardsTable::Instance().LoadValuesFromDatabase();
|
CDRewardsTable::Instance().LoadValuesFromDatabase();
|
||||||
CDScriptComponentTable::Instance().LoadValuesFromDatabase();
|
CDScriptComponentTable::Instance().LoadValuesFromDatabase();
|
||||||
CDSkillBehaviorTable::Instance().LoadValuesFromDatabase();
|
CDSkillBehaviorTable::Instance().LoadValuesFromDatabase();
|
||||||
|
CDTamingBuildPuzzleTable::Instance().LoadValuesFromDatabase();
|
||||||
CDVendorComponentTable::Instance().LoadValuesFromDatabase();
|
CDVendorComponentTable::Instance().LoadValuesFromDatabase();
|
||||||
CDZoneTableTable::Instance().LoadValuesFromDatabase();
|
CDZoneTableTable::Instance().LoadValuesFromDatabase();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ void CDPetComponentTable::LoadValuesFromDatabase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CDPetComponentTable::LoadValuesFromDefaults() {
|
void CDPetComponentTable::LoadValuesFromDefaults() {
|
||||||
GetEntriesMutable().insert(std::make_pair(defaultEntry.id, defaultEntry));
|
GetEntriesMutable().emplace(defaultEntry.id, defaultEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
CDPetComponent& CDPetComponentTable::GetByID(const uint32_t componentID) {
|
CDPetComponent& CDPetComponentTable::GetByID(const uint32_t componentID) {
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
#include "CDTamingBuildPuzzleTable.h"
|
||||||
|
|
||||||
|
void CDTamingBuildPuzzleTable::LoadValuesFromDatabase() {
|
||||||
|
// First, get the size of the table
|
||||||
|
uint32_t size = 0;
|
||||||
|
auto tableSize = CDClientDatabase::ExecuteQuery("SELECT COUNT(*) FROM TamingBuildPuzzles");
|
||||||
|
while (!tableSize.eof()) {
|
||||||
|
size = tableSize.getIntField(0, 0);
|
||||||
|
tableSize.nextRow();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserve the size
|
||||||
|
auto& entries = GetEntriesMutable();
|
||||||
|
entries.reserve(size);
|
||||||
|
|
||||||
|
// Now get the data
|
||||||
|
auto tableData = CDClientDatabase::ExecuteQuery("SELECT * FROM TamingBuildPuzzles");
|
||||||
|
while (!tableData.eof()) {
|
||||||
|
const auto lot = static_cast<LOT>(tableData.getIntField("NPCLot", LOT_NULL));
|
||||||
|
entries.emplace(lot, CDTamingBuildPuzzle{
|
||||||
|
.puzzleModelLot = lot,
|
||||||
|
.validPieces{ tableData.getStringField("ValidPiecesLXF") },
|
||||||
|
.timeLimit = static_cast<float>(tableData.getFloatField("Timelimit", 30.0f)),
|
||||||
|
.numValidPieces = tableData.getIntField("NumValidPieces", 6),
|
||||||
|
.imaginationCost = tableData.getIntField("imagCostPerBuild", 10)
|
||||||
|
});
|
||||||
|
tableData.nextRow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const CDTamingBuildPuzzle* CDTamingBuildPuzzleTable::GetByLOT(const LOT lot) const {
|
||||||
|
const auto& entries = GetEntries();
|
||||||
|
const auto itr = entries.find(lot);
|
||||||
|
return itr != entries.cend() ? &itr->second : nullptr;
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "CDTable.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information for the minigame to be completed
|
||||||
|
*/
|
||||||
|
struct CDTamingBuildPuzzle {
|
||||||
|
UNUSED_COLUMN(uint32_t id = 0;)
|
||||||
|
|
||||||
|
// The LOT of the object that is to be created
|
||||||
|
LOT puzzleModelLot = LOT_NULL;
|
||||||
|
|
||||||
|
// The LOT of the NPC
|
||||||
|
UNUSED_COLUMN(LOT npcLot = LOT_NULL;)
|
||||||
|
|
||||||
|
// The .lxfml file that contains the bricks required to build the model
|
||||||
|
std::string validPieces{};
|
||||||
|
|
||||||
|
// The .lxfml file that contains the bricks NOT required to build the model
|
||||||
|
UNUSED_COLUMN(std::string invalidPieces{};)
|
||||||
|
|
||||||
|
// Difficulty value
|
||||||
|
UNUSED_COLUMN(int32_t difficulty = 1;)
|
||||||
|
|
||||||
|
// The time limit to complete the build
|
||||||
|
float timeLimit = 30.0f;
|
||||||
|
|
||||||
|
// The number of pieces required to complete the minigame
|
||||||
|
int32_t numValidPieces = 6;
|
||||||
|
|
||||||
|
// Number of valid pieces
|
||||||
|
UNUSED_COLUMN(int32_t totalNumPieces = 16;)
|
||||||
|
|
||||||
|
// Model name
|
||||||
|
UNUSED_COLUMN(std::string modelName{};)
|
||||||
|
|
||||||
|
// The .lxfml file that contains the full model
|
||||||
|
UNUSED_COLUMN(std::string fullModel{};)
|
||||||
|
|
||||||
|
// The duration of the pet taming minigame
|
||||||
|
UNUSED_COLUMN(float duration = 45.0f;)
|
||||||
|
|
||||||
|
// The imagination cost for the tamer to start the minigame
|
||||||
|
int32_t imaginationCost = 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CDTamingBuildPuzzleTable : public CDTable<CDTamingBuildPuzzleTable, std::unordered_map<LOT, CDTamingBuildPuzzle>> {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Load values from the CD client database
|
||||||
|
*/
|
||||||
|
void LoadValuesFromDatabase();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the pet ability table corresponding to the pet LOT
|
||||||
|
* @returns A pointer to the corresponding table, or nullptr if one cannot be found
|
||||||
|
*/
|
||||||
|
[[nodiscard]]
|
||||||
|
const CDTamingBuildPuzzle* GetByLOT(const LOT lot) const;
|
||||||
|
};
|
||||||
@@ -36,5 +36,6 @@ set(DDATABASE_CDCLIENTDATABASE_CDCLIENTTABLES_SOURCES "CDActivitiesTable.cpp"
|
|||||||
"CDRewardsTable.cpp"
|
"CDRewardsTable.cpp"
|
||||||
"CDScriptComponentTable.cpp"
|
"CDScriptComponentTable.cpp"
|
||||||
"CDSkillBehaviorTable.cpp"
|
"CDSkillBehaviorTable.cpp"
|
||||||
|
"CDTamingBuildPuzzleTable.cpp"
|
||||||
"CDVendorComponentTable.cpp"
|
"CDVendorComponentTable.cpp"
|
||||||
"CDZoneTableTable.cpp" PARENT_SCOPE)
|
"CDZoneTableTable.cpp" PARENT_SCOPE)
|
||||||
|
|||||||
@@ -254,7 +254,7 @@ void Entity::Initialize() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MINI_GAME_CONTROL) > 0) {
|
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::MINI_GAME_CONTROL) > 0) {
|
||||||
AddComponent<MiniGameControlComponent>(m_TemplateID);
|
AddComponent<MiniGameControlComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t possessableComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::POSSESSABLE);
|
uint32_t possessableComponentId = compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::POSSESSABLE);
|
||||||
@@ -666,7 +666,7 @@ void Entity::Initialize() {
|
|||||||
|
|
||||||
// Shooting gallery component
|
// Shooting gallery component
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SHOOTING_GALLERY) > 0) {
|
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::SHOOTING_GALLERY) > 0) {
|
||||||
AddComponent<ShootingGalleryComponent>(m_TemplateID);
|
AddComponent<ShootingGalleryComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY, -1) != -1) {
|
if (compRegistryTable->GetByIDAndType(m_TemplateID, eReplicaComponentType::PROPERTY, -1) != -1) {
|
||||||
|
|||||||
@@ -536,13 +536,13 @@ 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 {
|
||||||
auto stmt = CDClientDatabase::CreatePreppedStmt(
|
auto stmt = CDClientDatabase::CreatePreppedStmt(
|
||||||
"select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ? AND icc.decal == ?"
|
"select obj.id as objectId from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ? AND icc.decal == ?"
|
||||||
);
|
);
|
||||||
stmt.bind(1, "character create shirt");
|
stmt.bind(1, "character create shirt");
|
||||||
stmt.bind(2, static_cast<int>(shirtColor));
|
stmt.bind(2, static_cast<int>(shirtColor));
|
||||||
stmt.bind(3, static_cast<int>(shirtStyle));
|
stmt.bind(3, static_cast<int>(shirtStyle));
|
||||||
auto tableData = stmt.execQuery();
|
auto tableData = stmt.execQuery();
|
||||||
auto shirtLOT = tableData.getIntField(0, 4069);
|
auto shirtLOT = tableData.getIntField("objectId", 4069);
|
||||||
tableData.finalize();
|
tableData.finalize();
|
||||||
return shirtLOT;
|
return shirtLOT;
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
@@ -555,12 +555,12 @@ uint32_t FindCharShirtID(uint32_t shirtColor, uint32_t shirtStyle) {
|
|||||||
uint32_t FindCharPantsID(uint32_t pantsColor) {
|
uint32_t FindCharPantsID(uint32_t pantsColor) {
|
||||||
try {
|
try {
|
||||||
auto stmt = CDClientDatabase::CreatePreppedStmt(
|
auto stmt = CDClientDatabase::CreatePreppedStmt(
|
||||||
"select obj.id from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ?"
|
"select obj.id as objectId from Objects as obj JOIN (select * from ComponentsRegistry as cr JOIN ItemComponent as ic on ic.id = cr.component_id where cr.component_type == 11) as icc on icc.id = obj.id where lower(obj._internalNotes) == ? AND icc.color1 == ?"
|
||||||
);
|
);
|
||||||
stmt.bind(1, "cc pants");
|
stmt.bind(1, "cc pants");
|
||||||
stmt.bind(2, static_cast<int>(pantsColor));
|
stmt.bind(2, static_cast<int>(pantsColor));
|
||||||
auto tableData = stmt.execQuery();
|
auto tableData = stmt.execQuery();
|
||||||
auto pantsLOT = tableData.getIntField(0, 2508);
|
auto pantsLOT = tableData.getIntField("objectId", 2508);
|
||||||
tableData.finalize();
|
tableData.finalize();
|
||||||
return pantsLOT;
|
return pantsLOT;
|
||||||
} catch (const std::exception& ex) {
|
} catch (const std::exception& ex) {
|
||||||
|
|||||||
@@ -377,10 +377,10 @@ void Behavior::PlayFx(std::u16string type, const LWOOBJID target, const LWOOBJID
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto name = std::string(result.getStringField(0));
|
const auto name = std::string(result.getStringField("effectName"));
|
||||||
|
|
||||||
if (type.empty()) {
|
if (type.empty()) {
|
||||||
const auto typeResult = result.getStringField(1);
|
const auto typeResult = result.getStringField("effectType");
|
||||||
|
|
||||||
type = GeneralUtils::ASCIIToUTF16(typeResult);
|
type = GeneralUtils::ASCIIToUTF16(typeResult);
|
||||||
|
|
||||||
|
|||||||
@@ -47,11 +47,11 @@ void SwitchMultipleBehavior::Load() {
|
|||||||
auto result = query.execQuery();
|
auto result = query.execQuery();
|
||||||
|
|
||||||
while (!result.eof()) {
|
while (!result.eof()) {
|
||||||
const auto behavior_id = static_cast<uint32_t>(result.getFloatField(1));
|
const auto behavior_id = static_cast<uint32_t>(result.getFloatField("behavior"));
|
||||||
|
|
||||||
auto* behavior = CreateBehavior(behavior_id);
|
auto* behavior = CreateBehavior(behavior_id);
|
||||||
|
|
||||||
auto value = result.getFloatField(2);
|
auto value = result.getFloatField("value");
|
||||||
|
|
||||||
this->m_behaviors.emplace_back(value, behavior);
|
this->m_behaviors.emplace_back(value, behavior);
|
||||||
|
|
||||||
|
|||||||
@@ -45,20 +45,20 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id):
|
|||||||
auto componentResult = componentQuery.execQuery();
|
auto componentResult = componentQuery.execQuery();
|
||||||
|
|
||||||
if (!componentResult.eof()) {
|
if (!componentResult.eof()) {
|
||||||
if (!componentResult.fieldIsNull(0))
|
if (!componentResult.fieldIsNull("aggroRadius"))
|
||||||
m_AggroRadius = componentResult.getFloatField(0);
|
m_AggroRadius = componentResult.getFloatField("aggroRadius");
|
||||||
|
|
||||||
if (!componentResult.fieldIsNull(1))
|
if (!componentResult.fieldIsNull("tetherSpeed"))
|
||||||
m_TetherSpeed = componentResult.getFloatField(1);
|
m_TetherSpeed = componentResult.getFloatField("tetherSpeed");
|
||||||
|
|
||||||
if (!componentResult.fieldIsNull(2))
|
if (!componentResult.fieldIsNull("pursuitSpeed"))
|
||||||
m_PursuitSpeed = componentResult.getFloatField(2);
|
m_PursuitSpeed = componentResult.getFloatField("pursuitSpeed");
|
||||||
|
|
||||||
if (!componentResult.fieldIsNull(3))
|
if (!componentResult.fieldIsNull("softTetherRadius"))
|
||||||
m_SoftTetherRadius = componentResult.getFloatField(3);
|
m_SoftTetherRadius = componentResult.getFloatField("softTetherRadius");
|
||||||
|
|
||||||
if (!componentResult.fieldIsNull(4))
|
if (!componentResult.fieldIsNull("hardTetherRadius"))
|
||||||
m_HardTetherRadius = componentResult.getFloatField(4);
|
m_HardTetherRadius = componentResult.getFloatField("hardTetherRadius");
|
||||||
}
|
}
|
||||||
|
|
||||||
componentResult.finalize();
|
componentResult.finalize();
|
||||||
@@ -82,11 +82,11 @@ BaseCombatAIComponent::BaseCombatAIComponent(Entity* parent, const uint32_t id):
|
|||||||
auto result = skillQuery.execQuery();
|
auto result = skillQuery.execQuery();
|
||||||
|
|
||||||
while (!result.eof()) {
|
while (!result.eof()) {
|
||||||
const auto skillId = static_cast<uint32_t>(result.getIntField(0));
|
const auto skillId = static_cast<uint32_t>(result.getIntField("skillID"));
|
||||||
|
|
||||||
const auto abilityCooldown = static_cast<float>(result.getFloatField(1));
|
const auto abilityCooldown = static_cast<float>(result.getFloatField("cooldown"));
|
||||||
|
|
||||||
const auto behaviorId = static_cast<uint32_t>(result.getIntField(2));
|
const auto behaviorId = static_cast<uint32_t>(result.getIntField("behaviorID"));
|
||||||
|
|
||||||
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
auto* behavior = Behavior::CreateBehavior(behaviorId);
|
||||||
|
|
||||||
|
|||||||
@@ -450,7 +450,7 @@ const std::vector<BuffParameter>& BuffComponent::GetBuffParameters(int32_t buffI
|
|||||||
param.value = result.getFloatField("NumberValue");
|
param.value = result.getFloatField("NumberValue");
|
||||||
param.effectId = result.getIntField("EffectID");
|
param.effectId = result.getIntField("EffectID");
|
||||||
|
|
||||||
if (!result.fieldIsNull(3)) {
|
if (!result.fieldIsNull("StringValue")) {
|
||||||
std::istringstream stream(result.getStringField("StringValue"));
|
std::istringstream stream(result.getStringField("StringValue"));
|
||||||
std::string token;
|
std::string token;
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ set(DGAME_DCOMPONENTS_SOURCES
|
|||||||
"TriggerComponent.cpp"
|
"TriggerComponent.cpp"
|
||||||
"HavokVehiclePhysicsComponent.cpp"
|
"HavokVehiclePhysicsComponent.cpp"
|
||||||
"VendorComponent.cpp"
|
"VendorComponent.cpp"
|
||||||
|
"MiniGameControlComponent.cpp"
|
||||||
"ScriptComponent.cpp"
|
"ScriptComponent.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -389,9 +389,9 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore
|
|||||||
|
|
||||||
if (result.eof()) return;
|
if (result.eof()) return;
|
||||||
|
|
||||||
if (result.fieldIsNull(0)) return;
|
if (result.fieldIsNull("enemyList")) return;
|
||||||
|
|
||||||
const auto* list_string = result.getStringField(0);
|
const auto* list_string = result.getStringField("enemyList");
|
||||||
|
|
||||||
std::stringstream ss(list_string);
|
std::stringstream ss(list_string);
|
||||||
std::string token;
|
std::string token;
|
||||||
|
|||||||
@@ -696,20 +696,22 @@ void InventoryComponent::UpdateXml(tinyxml2::XMLDocument& document) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InventoryComponent::Serialize(RakNet::BitStream& outBitStream, const bool bIsInitialUpdate) {
|
void InventoryComponent::Serialize(RakNet::BitStream& outBitStream, const bool bIsInitialUpdate) {
|
||||||
// LWOInventoryComponent_EquippedItem
|
|
||||||
outBitStream.Write(bIsInitialUpdate || m_Dirty);
|
|
||||||
if (bIsInitialUpdate || m_Dirty) {
|
if (bIsInitialUpdate || m_Dirty) {
|
||||||
|
outBitStream.Write(true);
|
||||||
|
|
||||||
outBitStream.Write<uint32_t>(m_Equipped.size());
|
outBitStream.Write<uint32_t>(m_Equipped.size());
|
||||||
|
|
||||||
for (const auto& pair : m_Equipped) {
|
for (const auto& pair : m_Equipped) {
|
||||||
const auto item = pair.second;
|
const auto item = pair.second;
|
||||||
|
|
||||||
if (bIsInitialUpdate) AddItemSkills(item.lot);
|
if (bIsInitialUpdate) {
|
||||||
|
AddItemSkills(item.lot);
|
||||||
|
}
|
||||||
|
|
||||||
outBitStream.Write(item.id);
|
outBitStream.Write(item.id);
|
||||||
outBitStream.Write(item.lot);
|
outBitStream.Write(item.lot);
|
||||||
|
|
||||||
outBitStream.Write0(); // subkey
|
outBitStream.Write0();
|
||||||
|
|
||||||
outBitStream.Write(item.count > 0);
|
outBitStream.Write(item.count > 0);
|
||||||
if (item.count > 0) outBitStream.Write(item.count);
|
if (item.count > 0) outBitStream.Write(item.count);
|
||||||
@@ -717,7 +719,7 @@ void InventoryComponent::Serialize(RakNet::BitStream& outBitStream, const bool b
|
|||||||
outBitStream.Write(item.slot != 0);
|
outBitStream.Write(item.slot != 0);
|
||||||
if (item.slot != 0) outBitStream.Write<uint16_t>(item.slot);
|
if (item.slot != 0) outBitStream.Write<uint16_t>(item.slot);
|
||||||
|
|
||||||
outBitStream.Write0(); // inventory type
|
outBitStream.Write0();
|
||||||
|
|
||||||
bool flag = !item.config.empty();
|
bool flag = !item.config.empty();
|
||||||
outBitStream.Write(flag);
|
outBitStream.Write(flag);
|
||||||
@@ -744,21 +746,11 @@ void InventoryComponent::Serialize(RakNet::BitStream& outBitStream, const bool b
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_Dirty = false;
|
m_Dirty = false;
|
||||||
|
} else {
|
||||||
|
outBitStream.Write(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// EquippedModelTransform
|
|
||||||
outBitStream.Write(false);
|
outBitStream.Write(false);
|
||||||
/*
|
|
||||||
outBitStream.Write(bIsInitialUpdate || m_Dirty); // Same dirty or different?
|
|
||||||
if (bIsInitialUpdate || m_Dirty) {
|
|
||||||
outBitStream.Write<uint32_t>(m_Equipped.size()); // Equiped models?
|
|
||||||
for (const auto& [location, item] : m_Equipped) {
|
|
||||||
outBitStream.Write(item.id);
|
|
||||||
outBitStream.Write(item.pos);
|
|
||||||
outBitStream.Write(item.rot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryComponent::Update(float deltaTime) {
|
void InventoryComponent::Update(float deltaTime) {
|
||||||
@@ -1102,7 +1094,7 @@ void InventoryComponent::CheckItemSet(const LOT lot) {
|
|||||||
auto result = query.execQuery();
|
auto result = query.execQuery();
|
||||||
|
|
||||||
while (!result.eof()) {
|
while (!result.eof()) {
|
||||||
const auto id = result.getIntField(0);
|
const auto id = result.getIntField("setID");
|
||||||
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
|
|||||||
@@ -2,16 +2,4 @@
|
|||||||
|
|
||||||
void ItemComponent::Serialize(RakNet::BitStream& outBitStream, bool isConstruction) {
|
void ItemComponent::Serialize(RakNet::BitStream& outBitStream, bool isConstruction) {
|
||||||
outBitStream.Write0();
|
outBitStream.Write0();
|
||||||
/*
|
|
||||||
outBitStream.Write(isConstruction || m_Dirty); // Same dirty or different?
|
|
||||||
if (isConstruction || m_Dirty) {
|
|
||||||
outBitStream.Write(m_parent->GetObjectID());
|
|
||||||
outBitStream.Write(moderationStatus);
|
|
||||||
outBitStream.Write(!description.empty());
|
|
||||||
if (!description.empty()) {
|
|
||||||
outBitStream.Write<uint32_t>(description.size());
|
|
||||||
outBitStream.Write(description) // u16string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|||||||
5
dGame/dComponents/MiniGameControlComponent.cpp
Normal file
5
dGame/dComponents/MiniGameControlComponent.cpp
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#include "MiniGameControlComponent.h"
|
||||||
|
|
||||||
|
void MiniGameControlComponent::Serialize(RakNet::BitStream& outBitStream, bool isConstruction) {
|
||||||
|
outBitStream.Write<uint32_t>(0x40000000);
|
||||||
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
#ifndef __MINIGAMECONTROLCOMPONENT__H__
|
#ifndef __MINIGAMECONTROLCOMPONENT__H__
|
||||||
#define __MINIGAMECONTROLCOMPONENT__H__
|
#define __MINIGAMECONTROLCOMPONENT__H__
|
||||||
|
|
||||||
#include "ActivityComponent.h"
|
#include "Component.h"
|
||||||
#include "eReplicaComponentType.h"
|
#include "eReplicaComponentType.h"
|
||||||
|
|
||||||
class MiniGameControlComponent final : public ActivityComponent {
|
class MiniGameControlComponent final : public Component {
|
||||||
public:
|
public:
|
||||||
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::MINI_GAME_CONTROL;
|
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::MINI_GAME_CONTROL;
|
||||||
MiniGameControlComponent(Entity* parent, LOT lot) : ActivityComponent(parent, lot) {}
|
|
||||||
|
MiniGameControlComponent(Entity* parent) : Component(parent) {}
|
||||||
|
void Serialize(RakNet::BitStream& outBitStream, bool isConstruction);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //!__MINIGAMECONTROLCOMPONENT__H__
|
#endif //!__MINIGAMECONTROLCOMPONENT__H__
|
||||||
|
|||||||
@@ -466,8 +466,8 @@ bool MissionComponent::RequiresItem(const LOT lot) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!result.fieldIsNull(0)) {
|
if (!result.fieldIsNull("type")) {
|
||||||
const auto type = std::string(result.getStringField(0));
|
const auto type = std::string(result.getStringField("type"));
|
||||||
|
|
||||||
result.finalize();
|
result.finalize();
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "GameMessages.h"
|
#include "GameMessages.h"
|
||||||
#include "BrickDatabase.h"
|
#include "BrickDatabase.h"
|
||||||
#include "CDClientDatabase.h"
|
#include "CDClientDatabase.h"
|
||||||
|
#include "CDTamingBuildPuzzleTable.h"
|
||||||
#include "ChatPackets.h"
|
#include "ChatPackets.h"
|
||||||
#include "EntityManager.h"
|
#include "EntityManager.h"
|
||||||
#include "Character.h"
|
#include "Character.h"
|
||||||
@@ -32,7 +33,6 @@
|
|||||||
#include "eMissionState.h"
|
#include "eMissionState.h"
|
||||||
#include "dNavMesh.h"
|
#include "dNavMesh.h"
|
||||||
|
|
||||||
std::unordered_map<LOT, PetComponent::PetPuzzleData> PetComponent::buildCache{};
|
|
||||||
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::currentActivities{};
|
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::currentActivities{};
|
||||||
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::activePets{};
|
std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::activePets{};
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ std::unordered_map<LWOOBJID, LWOOBJID> PetComponent::activePets{};
|
|||||||
* Maps all the pet lots to a flag indicating that the player has caught it. All basic pets have been guessed by ObjID
|
* Maps all the pet lots to a flag indicating that the player has caught it. All basic pets have been guessed by ObjID
|
||||||
* while the faction ones could be checked using their respective missions.
|
* while the faction ones could be checked using their respective missions.
|
||||||
*/
|
*/
|
||||||
std::map<LOT, int32_t> PetComponent::petFlags = {
|
const std::map<LOT, int32_t> PetComponent::petFlags{
|
||||||
{ 3050, 801 }, // Elephant
|
{ 3050, 801 }, // Elephant
|
||||||
{ 3054, 803 }, // Cat
|
{ 3054, 803 }, // Cat
|
||||||
{ 3195, 806 }, // Triceratops
|
{ 3195, 806 }, // Triceratops
|
||||||
@@ -87,7 +87,6 @@ PetComponent::PetComponent(Entity* parentEntity, uint32_t componentId) : Compone
|
|||||||
m_StartPosition = NiPoint3Constant::ZERO;
|
m_StartPosition = NiPoint3Constant::ZERO;
|
||||||
m_MovementAI = nullptr;
|
m_MovementAI = nullptr;
|
||||||
m_TresureTime = 0;
|
m_TresureTime = 0;
|
||||||
m_Preconditions = nullptr;
|
|
||||||
|
|
||||||
std::string checkPreconditions = GeneralUtils::UTF16ToWTF8(parentEntity->GetVar<std::u16string>(u"CheckPrecondition"));
|
std::string checkPreconditions = GeneralUtils::UTF16ToWTF8(parentEntity->GetVar<std::u16string>(u"CheckPrecondition"));
|
||||||
|
|
||||||
@@ -152,96 +151,53 @@ void PetComponent::OnUse(Entity* originator) {
|
|||||||
m_Tamer = LWOOBJID_EMPTY;
|
m_Tamer = LWOOBJID_EMPTY;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* inventoryComponent = originator->GetComponent<InventoryComponent>();
|
auto* const inventoryComponent = originator->GetComponent<InventoryComponent>();
|
||||||
|
|
||||||
if (inventoryComponent == nullptr) {
|
if (inventoryComponent == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_Preconditions != nullptr && !m_Preconditions->Check(originator, true)) {
|
if (m_Preconditions.has_value() && !m_Preconditions->Check(originator, true)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* movementAIComponent = m_Parent->GetComponent<MovementAIComponent>();
|
auto* const movementAIComponent = m_Parent->GetComponent<MovementAIComponent>();
|
||||||
|
|
||||||
if (movementAIComponent != nullptr) {
|
if (movementAIComponent != nullptr) {
|
||||||
movementAIComponent->Stop();
|
movementAIComponent->Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
inventoryComponent->DespawnPet();
|
inventoryComponent->DespawnPet();
|
||||||
|
|
||||||
const auto& cached = buildCache.find(m_Parent->GetLOT());
|
const auto* const entry = CDClientManager::GetTable<CDTamingBuildPuzzleTable>()->GetByLOT(m_Parent->GetLOT());
|
||||||
int32_t imaginationCost = 0;
|
if (!entry) {
|
||||||
|
ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to find the puzzle minigame for this pet.");
|
||||||
std::string buildFile;
|
return;
|
||||||
|
|
||||||
if (cached == buildCache.end()) {
|
|
||||||
auto query = CDClientDatabase::CreatePreppedStmt(
|
|
||||||
"SELECT ValidPiecesLXF, PuzzleModelLot, Timelimit, NumValidPieces, imagCostPerBuild FROM TamingBuildPuzzles WHERE NPCLot = ?;");
|
|
||||||
query.bind(1, static_cast<int>(m_Parent->GetLOT()));
|
|
||||||
|
|
||||||
auto result = query.execQuery();
|
|
||||||
|
|
||||||
if (result.eof()) {
|
|
||||||
ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to find the puzzle minigame for this pet.");
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.fieldIsNull(0)) {
|
|
||||||
result.finalize();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
buildFile = std::string(result.getStringField(0));
|
|
||||||
|
|
||||||
PetPuzzleData data;
|
|
||||||
data.buildFile = buildFile;
|
|
||||||
data.puzzleModelLot = result.getIntField(1);
|
|
||||||
data.timeLimit = result.getFloatField(2);
|
|
||||||
data.numValidPieces = result.getIntField(3);
|
|
||||||
data.imaginationCost = result.getIntField(4);
|
|
||||||
if (data.timeLimit <= 0) data.timeLimit = 60;
|
|
||||||
imaginationCost = data.imaginationCost;
|
|
||||||
|
|
||||||
buildCache[m_Parent->GetLOT()] = data;
|
|
||||||
|
|
||||||
result.finalize();
|
|
||||||
} else {
|
|
||||||
buildFile = cached->second.buildFile;
|
|
||||||
imaginationCost = cached->second.imaginationCost;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* destroyableComponent = originator->GetComponent<DestroyableComponent>();
|
const auto* const destroyableComponent = originator->GetComponent<DestroyableComponent>();
|
||||||
|
|
||||||
if (destroyableComponent == nullptr) {
|
if (destroyableComponent == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto imagination = destroyableComponent->GetImagination();
|
const auto imagination = destroyableComponent->GetImagination();
|
||||||
|
if (imagination < entry->imaginationCost) {
|
||||||
if (imagination < imaginationCost) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& bricks = BrickDatabase::GetBricks(buildFile);
|
const auto& bricks = BrickDatabase::GetBricks(entry->validPieces);
|
||||||
|
|
||||||
if (bricks.empty()) {
|
if (bricks.empty()) {
|
||||||
ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to load the puzzle minigame for this pet.");
|
ChatPackets::SendSystemMessage(originator->GetSystemAddress(), u"Failed to load the puzzle minigame for this pet.");
|
||||||
LOG("Couldn't find %s for minigame!", buildFile.c_str());
|
LOG("Couldn't find %s for minigame!", entry->validPieces.c_str());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto petPosition = m_Parent->GetPosition();
|
const auto petPosition = m_Parent->GetPosition();
|
||||||
|
|
||||||
auto originatorPosition = originator->GetPosition();
|
const auto originatorPosition = originator->GetPosition();
|
||||||
|
|
||||||
m_Parent->SetRotation(NiQuaternion::LookAt(petPosition, originatorPosition));
|
m_Parent->SetRotation(NiQuaternion::LookAt(petPosition, originatorPosition));
|
||||||
|
|
||||||
float interactionDistance = m_Parent->GetVar<float>(u"interaction_distance");
|
float interactionDistance = m_Parent->GetVar<float>(u"interaction_distance");
|
||||||
|
|
||||||
if (interactionDistance <= 0) {
|
if (interactionDistance <= 0) {
|
||||||
interactionDistance = 15;
|
interactionDistance = 15;
|
||||||
}
|
}
|
||||||
@@ -477,9 +433,8 @@ void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& cached = buildCache.find(m_Parent->GetLOT());
|
const auto* const entry = CDClientManager::GetTable<CDTamingBuildPuzzleTable>()->GetByLOT(m_Parent->GetLOT());
|
||||||
|
if (!entry) return;
|
||||||
if (cached == buildCache.end()) return;
|
|
||||||
|
|
||||||
auto* destroyableComponent = tamer->GetComponent<DestroyableComponent>();
|
auto* destroyableComponent = tamer->GetComponent<DestroyableComponent>();
|
||||||
|
|
||||||
@@ -487,14 +442,14 @@ void PetComponent::TryBuild(uint32_t numBricks, bool clientFailed) {
|
|||||||
|
|
||||||
auto imagination = destroyableComponent->GetImagination();
|
auto imagination = destroyableComponent->GetImagination();
|
||||||
|
|
||||||
imagination -= cached->second.imaginationCost;
|
imagination -= entry->imaginationCost;
|
||||||
|
|
||||||
destroyableComponent->SetImagination(imagination);
|
destroyableComponent->SetImagination(imagination);
|
||||||
|
|
||||||
Game::entityManager->SerializeEntity(tamer);
|
Game::entityManager->SerializeEntity(tamer);
|
||||||
|
|
||||||
if (clientFailed) {
|
if (clientFailed) {
|
||||||
if (imagination < cached->second.imaginationCost) {
|
if (imagination < entry->imaginationCost) {
|
||||||
ClientFailTamingMinigame();
|
ClientFailTamingMinigame();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -517,17 +472,14 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& cached = buildCache.find(m_Parent->GetLOT());
|
const auto* const entry = CDClientManager::GetTable<CDTamingBuildPuzzleTable>()->GetByLOT(m_Parent->GetLOT());
|
||||||
|
if (!entry) return;
|
||||||
if (cached == buildCache.end()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GameMessages::SendPlayFXEffect(tamer, -1, u"petceleb", "", LWOOBJID_EMPTY, 1, 1, true);
|
GameMessages::SendPlayFXEffect(tamer, -1, u"petceleb", "", LWOOBJID_EMPTY, 1, 1, true);
|
||||||
RenderComponent::PlayAnimation(tamer, u"rebuild-celebrate");
|
RenderComponent::PlayAnimation(tamer, u"rebuild-celebrate");
|
||||||
|
|
||||||
EntityInfo info{};
|
EntityInfo info{};
|
||||||
info.lot = cached->second.puzzleModelLot;
|
info.lot = entry->puzzleModelLot;
|
||||||
info.pos = position;
|
info.pos = position;
|
||||||
info.rot = NiQuaternionConstant::IDENTITY;
|
info.rot = NiQuaternionConstant::IDENTITY;
|
||||||
info.spawnerID = tamer->GetObjectID();
|
info.spawnerID = tamer->GetObjectID();
|
||||||
@@ -731,13 +683,10 @@ void PetComponent::ClientExitTamingMinigame(bool voluntaryExit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PetComponent::StartTimer() {
|
void PetComponent::StartTimer() {
|
||||||
const auto& cached = buildCache.find(m_Parent->GetLOT());
|
const auto* const entry = CDClientManager::GetTable<CDTamingBuildPuzzleTable>()->GetByLOT(m_Parent->GetLOT());
|
||||||
|
if (!entry) return;
|
||||||
|
|
||||||
if (cached == buildCache.end()) {
|
m_Timer = entry->timeLimit;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Timer = cached->second.timeLimit;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PetComponent::ClientFailTamingMinigame() {
|
void PetComponent::ClientFailTamingMinigame() {
|
||||||
@@ -1086,6 +1035,6 @@ void PetComponent::LoadPetNameFromModeration() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PetComponent::SetPreconditions(std::string& preconditions) {
|
void PetComponent::SetPreconditions(const std::string& preconditions) {
|
||||||
m_Preconditions = new PreconditionExpression(preconditions);
|
m_Preconditions = std::make_optional<PreconditionExpression>(preconditions);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ public:
|
|||||||
* Sets preconditions for the pet that need to be met before it can be tamed
|
* Sets preconditions for the pet that need to be met before it can be tamed
|
||||||
* @param conditions the preconditions to set
|
* @param conditions the preconditions to set
|
||||||
*/
|
*/
|
||||||
void SetPreconditions(std::string& conditions);
|
void SetPreconditions(const std::string& conditions);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the entity that this component belongs to
|
* Returns the entity that this component belongs to
|
||||||
@@ -250,15 +250,10 @@ private:
|
|||||||
*/
|
*/
|
||||||
static std::unordered_map<LWOOBJID, LWOOBJID> currentActivities;
|
static std::unordered_map<LWOOBJID, LWOOBJID> currentActivities;
|
||||||
|
|
||||||
/**
|
|
||||||
* Cache of all the minigames and their information from the database
|
|
||||||
*/
|
|
||||||
static std::unordered_map<LOT, PetComponent::PetPuzzleData> buildCache;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flags that indicate that a player has tamed a pet, indexed by the LOT of the pet
|
* Flags that indicate that a player has tamed a pet, indexed by the LOT of the pet
|
||||||
*/
|
*/
|
||||||
static std::map<LOT, int32_t> petFlags;
|
static const std::map<LOT, int32_t> petFlags;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ID of the component in the pet component table
|
* The ID of the component in the pet component table
|
||||||
@@ -349,7 +344,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Preconditions that need to be met before an entity can tame this pet
|
* Preconditions that need to be met before an entity can tame this pet
|
||||||
*/
|
*/
|
||||||
PreconditionExpression* m_Preconditions;
|
std::optional<PreconditionExpression> m_Preconditions{};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pet information loaded from the CDClientDatabase
|
* Pet information loaded from the CDClientDatabase
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ PossessableComponent::PossessableComponent(Entity* parent, uint32_t componentId)
|
|||||||
|
|
||||||
// Should a result not exist for this default to attached visible
|
// Should a result not exist for this default to attached visible
|
||||||
if (!result.eof()) {
|
if (!result.eof()) {
|
||||||
m_PossessionType = static_cast<ePossessionType>(result.getIntField(0, 1)); // Default to Attached Visible
|
m_PossessionType = static_cast<ePossessionType>(result.getIntField("possessionType", 1)); // Default to Attached Visible
|
||||||
m_DepossessOnHit = static_cast<bool>(result.getIntField(1, 0));
|
m_DepossessOnHit = static_cast<bool>(result.getIntField("depossessOnHit", 0));
|
||||||
} else {
|
} else {
|
||||||
m_PossessionType = ePossessionType::ATTACHED_VISIBLE;
|
m_PossessionType = ePossessionType::ATTACHED_VISIBLE;
|
||||||
m_DepossessOnHit = false;
|
m_DepossessOnHit = false;
|
||||||
|
|||||||
@@ -49,11 +49,11 @@ PropertyManagementComponent::PropertyManagementComponent(Entity* parent) : Compo
|
|||||||
|
|
||||||
auto result = query.execQuery();
|
auto result = query.execQuery();
|
||||||
|
|
||||||
if (result.eof() || result.fieldIsNull(0)) {
|
if (result.eof() || result.fieldIsNull("id")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
templateId = result.getIntField(0);
|
templateId = result.getIntField("id");
|
||||||
|
|
||||||
auto propertyInfo = Database::Get()->GetPropertyInfo(zoneId, cloneId);
|
auto propertyInfo = Database::Get()->GetPropertyInfo(zoneId, cloneId);
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ std::vector<NiPoint3> PropertyManagementComponent::GetPaths() const {
|
|||||||
|
|
||||||
std::vector<float> points;
|
std::vector<float> points;
|
||||||
|
|
||||||
std::istringstream stream(result.getStringField(0));
|
std::istringstream stream(result.getStringField("path"));
|
||||||
std::string token;
|
std::string token;
|
||||||
|
|
||||||
while (std::getline(stream, token, ' ')) {
|
while (std::getline(stream, token, ' ')) {
|
||||||
|
|||||||
@@ -117,7 +117,7 @@ void RenderComponent::PlayEffect(const int32_t effectId, const std::u16string& e
|
|||||||
|
|
||||||
auto result = query.execQuery();
|
auto result = query.execQuery();
|
||||||
|
|
||||||
if (result.eof() || result.fieldIsNull(0)) {
|
if (result.eof() || result.fieldIsNull("animation_length")) {
|
||||||
result.finalize();
|
result.finalize();
|
||||||
|
|
||||||
m_DurationCache[effectId] = 0;
|
m_DurationCache[effectId] = 0;
|
||||||
@@ -127,7 +127,7 @@ void RenderComponent::PlayEffect(const int32_t effectId, const std::u16string& e
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
effect.time = static_cast<float>(result.getFloatField(0));
|
effect.time = static_cast<float>(result.getFloatField("animation_length"));
|
||||||
|
|
||||||
result.finalize();
|
result.finalize();
|
||||||
|
|
||||||
|
|||||||
@@ -27,12 +27,12 @@ RocketLaunchpadControlComponent::RocketLaunchpadControlComponent(Entity* parent,
|
|||||||
|
|
||||||
auto result = query.execQuery();
|
auto result = query.execQuery();
|
||||||
|
|
||||||
if (!result.eof() && !result.fieldIsNull(0)) {
|
if (!result.eof() && !result.fieldIsNull("targetZone")) {
|
||||||
m_TargetZone = result.getIntField(0);
|
m_TargetZone = result.getIntField("targetZone");
|
||||||
m_DefaultZone = result.getIntField(1);
|
m_DefaultZone = result.getIntField("defaultZoneID");
|
||||||
m_TargetScene = result.getStringField(2);
|
m_TargetScene = result.getStringField("targetScene");
|
||||||
m_AltPrecondition = new PreconditionExpression(result.getStringField(3));
|
m_AltPrecondition = new PreconditionExpression(result.getStringField("altLandingPrecondition"));
|
||||||
m_AltLandingScene = result.getStringField(4);
|
m_AltLandingScene = result.getStringField("altLandingSpawnPointName");
|
||||||
}
|
}
|
||||||
|
|
||||||
result.finalize();
|
result.finalize();
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
#include "EntityManager.h"
|
#include "EntityManager.h"
|
||||||
#include "ScriptedActivityComponent.h"
|
#include "ScriptedActivityComponent.h"
|
||||||
|
|
||||||
|
ShootingGalleryComponent::ShootingGalleryComponent(Entity* parent) : Component(parent) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ShootingGalleryComponent::~ShootingGalleryComponent() = default;
|
||||||
|
|
||||||
void ShootingGalleryComponent::SetStaticParams(const StaticShootingGalleryParams& params) {
|
void ShootingGalleryComponent::SetStaticParams(const StaticShootingGalleryParams& params) {
|
||||||
m_StaticParams = params;
|
m_StaticParams = params;
|
||||||
}
|
}
|
||||||
@@ -12,15 +17,20 @@ void ShootingGalleryComponent::SetDynamicParams(const DynamicShootingGalleryPara
|
|||||||
Game::entityManager->SerializeEntity(m_Parent);
|
Game::entityManager->SerializeEntity(m_Parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShootingGalleryComponent::SetCurrentPlayerID(LWOOBJID playerID) {
|
|
||||||
m_CurrentPlayerID = playerID;
|
|
||||||
m_Dirty = true;
|
|
||||||
AddActivityPlayerData(playerID);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void ShootingGalleryComponent::Serialize(RakNet::BitStream& outBitStream, bool isInitialUpdate) {
|
void ShootingGalleryComponent::Serialize(RakNet::BitStream& outBitStream, bool isInitialUpdate) {
|
||||||
ActivityComponent::Serialize(outBitStream, isInitialUpdate);
|
// Start ScriptedActivityComponent
|
||||||
|
outBitStream.Write<bool>(true);
|
||||||
|
if (m_CurrentPlayerID == LWOOBJID_EMPTY) {
|
||||||
|
outBitStream.Write<uint32_t>(0);
|
||||||
|
} else {
|
||||||
|
outBitStream.Write<uint32_t>(1);
|
||||||
|
outBitStream.Write<LWOOBJID>(m_CurrentPlayerID);
|
||||||
|
for (size_t i = 0; i < 10; i++) {
|
||||||
|
outBitStream.Write<float_t>(0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// End ScriptedActivityComponent
|
||||||
|
|
||||||
if (isInitialUpdate) {
|
if (isInitialUpdate) {
|
||||||
outBitStream.Write<float_t>(m_StaticParams.cameraPosition.GetX());
|
outBitStream.Write<float_t>(m_StaticParams.cameraPosition.GetX());
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
#include "dCommonVars.h"
|
#include "dCommonVars.h"
|
||||||
#include "NiPoint3.h"
|
#include "NiPoint3.h"
|
||||||
#include "Entity.h"
|
#include "Entity.h"
|
||||||
#include "ActivityComponent.h"
|
#include "Component.h"
|
||||||
#include "eReplicaComponentType.h"
|
#include "eReplicaComponentType.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -71,11 +71,12 @@ struct StaticShootingGalleryParams {
|
|||||||
* A very ancient component that was used to guide shooting galleries, it's still kind of used but a lot of logic is
|
* A very ancient component that was used to guide shooting galleries, it's still kind of used but a lot of logic is
|
||||||
* also in the related scripts.
|
* also in the related scripts.
|
||||||
*/
|
*/
|
||||||
class ShootingGalleryComponent final : public ActivityComponent {
|
class ShootingGalleryComponent final : public Component {
|
||||||
public:
|
public:
|
||||||
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::SHOOTING_GALLERY;
|
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::SHOOTING_GALLERY;
|
||||||
|
|
||||||
explicit ShootingGalleryComponent(Entity* parent, LOT lot) : ActivityComponent(parent, lot) {}
|
explicit ShootingGalleryComponent(Entity* parent);
|
||||||
|
~ShootingGalleryComponent();
|
||||||
void Serialize(RakNet::BitStream& outBitStream, bool isInitialUpdate) override;
|
void Serialize(RakNet::BitStream& outBitStream, bool isInitialUpdate) override;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,8 +107,13 @@ public:
|
|||||||
* Sets the entity that's currently playing the shooting gallery
|
* Sets the entity that's currently playing the shooting gallery
|
||||||
* @param playerID the entity to set
|
* @param playerID the entity to set
|
||||||
*/
|
*/
|
||||||
void SetCurrentPlayerID(LWOOBJID playerID);
|
void SetCurrentPlayerID(LWOOBJID playerID) { m_CurrentPlayerID = playerID; m_Dirty = true; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the player that's currently playing the shooting gallery
|
||||||
|
* @return the player that's currently playing the shooting gallery
|
||||||
|
*/
|
||||||
|
LWOOBJID GetCurrentPlayerID() const { return m_CurrentPlayerID; };
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::B
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto behavior_id = static_cast<uint32_t>(result.getIntField(0));
|
const auto behavior_id = static_cast<uint32_t>(result.getIntField("behaviorID"));
|
||||||
|
|
||||||
result.finalize();
|
result.finalize();
|
||||||
|
|
||||||
@@ -425,7 +425,7 @@ void SkillComponent::SyncProjectileCalculation(const ProjectileSyncEntry& entry)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto behaviorId = static_cast<uint32_t>(result.getIntField(0));
|
const auto behaviorId = static_cast<uint32_t>(result.getIntField("behaviorID"));
|
||||||
|
|
||||||
result.finalize();
|
result.finalize();
|
||||||
|
|
||||||
@@ -486,32 +486,6 @@ SkillComponent::~SkillComponent() {
|
|||||||
|
|
||||||
void SkillComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) {
|
void SkillComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsInitialUpdate) {
|
||||||
if (bIsInitialUpdate) outBitStream.Write0();
|
if (bIsInitialUpdate) outBitStream.Write0();
|
||||||
/*
|
|
||||||
outBitStream.Write(bIsInitialUpdate && !m_managedBehaviors.empty());
|
|
||||||
if (bIsInitialUpdate && !m_managedBehaviors.empty()) {
|
|
||||||
outBitStream.Write<uint32_t>(m_managedBehaviors.size());
|
|
||||||
for (const auto& [id, skill] : m_managedBehaviors) {
|
|
||||||
outBitStream.Write(skill.skillUID);
|
|
||||||
outBitStream.Write(skill.skillID);
|
|
||||||
outBitStream.Write(skill.cast_type);
|
|
||||||
outBitStream.Write(skill.cancel_type);
|
|
||||||
outBitStream.Write(skill.behavior_count);
|
|
||||||
for (auto& index : skill.behavior_count) {
|
|
||||||
outBitStream.Write<uint32_t>(behaviorUID); // Maybe
|
|
||||||
outBitStream.Write<uint32_t>(action);
|
|
||||||
outBitStream.Write<uint32_t>(wait_time_ms);
|
|
||||||
outBitStream.Write<uint32_t>(template_id);
|
|
||||||
outBitStream.Write(casterObjId);
|
|
||||||
outBitStream.Write(originatorObjId);
|
|
||||||
outBitStream.Write(targetObjId);
|
|
||||||
outBitStream.Write<bool>(usedMouse);
|
|
||||||
outBitStream.Write(cooldown);
|
|
||||||
outBitStream.Write(charge_time);
|
|
||||||
outBitStream.Write(imagination_cost);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -405,18 +405,18 @@ void Item::DisassembleModel(uint32_t numToDismantle) {
|
|||||||
|
|
||||||
auto result = query.execQuery();
|
auto result = query.execQuery();
|
||||||
|
|
||||||
if (result.eof() || result.fieldIsNull(0)) {
|
if (result.eof() || result.fieldIsNull("render_asset")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string renderAsset = std::string(result.getStringField(0));
|
std::string renderAsset = std::string(result.getStringField("render_asset"));
|
||||||
|
|
||||||
// normalize path slashes
|
// normalize path slashes
|
||||||
for (auto& c : renderAsset) {
|
for (auto& c : renderAsset) {
|
||||||
if (c == '\\') c = '/';
|
if (c == '\\') c = '/';
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string lxfmlFolderName = std::string(result.getStringField(1));
|
std::string lxfmlFolderName = std::string(result.getStringField("LXFMLFolder"));
|
||||||
if (!lxfmlFolderName.empty()) lxfmlFolderName.insert(0, "/");
|
if (!lxfmlFolderName.empty()) lxfmlFolderName.insert(0, "/");
|
||||||
|
|
||||||
std::vector<std::string> renderAssetSplit = GeneralUtils::SplitString(renderAsset, '/');
|
std::vector<std::string> renderAssetSplit = GeneralUtils::SplitString(renderAsset, '/');
|
||||||
|
|||||||
@@ -8,10 +8,13 @@
|
|||||||
#include "MissionComponent.h"
|
#include "MissionComponent.h"
|
||||||
#include "eMissionTaskType.h"
|
#include "eMissionTaskType.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include "CDSkillBehaviorTable.h"
|
#include "CDSkillBehaviorTable.h"
|
||||||
|
|
||||||
ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) {
|
ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) {
|
||||||
|
using namespace std::string_view_literals;
|
||||||
|
|
||||||
this->m_ID = id;
|
this->m_ID = id;
|
||||||
this->m_InventoryComponent = inventoryComponent;
|
this->m_InventoryComponent = inventoryComponent;
|
||||||
|
|
||||||
@@ -27,14 +30,16 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i = 0; i < 5; ++i) {
|
constexpr std::array rowNames = { "skillSetWith2"sv, "skillSetWith3"sv, "skillSetWith4"sv, "skillSetWith5"sv, "skillSetWith6"sv };
|
||||||
if (result.fieldIsNull(i)) {
|
for (auto i = 0; i < rowNames.size(); ++i) {
|
||||||
|
const auto rowName = rowNames[i];
|
||||||
|
if (result.fieldIsNull(rowName.data())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto skillQuery = CDClientDatabase::CreatePreppedStmt(
|
auto skillQuery = CDClientDatabase::CreatePreppedStmt(
|
||||||
"SELECT SkillID FROM ItemSetSkills WHERE SkillSetID = ?;");
|
"SELECT SkillID FROM ItemSetSkills WHERE SkillSetID = ?;");
|
||||||
skillQuery.bind(1, result.getIntField(i));
|
skillQuery.bind(1, result.getIntField(rowName.data()));
|
||||||
|
|
||||||
auto skillResult = skillQuery.execQuery();
|
auto skillResult = skillQuery.execQuery();
|
||||||
|
|
||||||
@@ -43,13 +48,13 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (!skillResult.eof()) {
|
while (!skillResult.eof()) {
|
||||||
if (skillResult.fieldIsNull(0)) {
|
if (skillResult.fieldIsNull("SkillID")) {
|
||||||
skillResult.nextRow();
|
skillResult.nextRow();
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto skillId = skillResult.getIntField(0);
|
const auto skillId = skillResult.getIntField("SkillID");
|
||||||
|
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0:
|
case 0:
|
||||||
@@ -75,7 +80,7 @@ ItemSet::ItemSet(const uint32_t id, InventoryComponent* inventoryComponent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ids = result.getStringField(5);
|
std::string ids = result.getStringField("itemIDs");
|
||||||
|
|
||||||
ids.erase(std::remove_if(ids.begin(), ids.end(), ::isspace), ids.end());
|
ids.erase(std::remove_if(ids.begin(), ids.end(), ::isspace), ids.end());
|
||||||
|
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ Precondition::Precondition(const uint32_t condition) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->type = static_cast<PreconditionType>(result.fieldIsNull(0) ? 0 : result.getIntField(0));
|
this->type = static_cast<PreconditionType>(result.fieldIsNull("type") ? 0 : result.getIntField("type"));
|
||||||
|
|
||||||
if (!result.fieldIsNull(1)) {
|
if (!result.fieldIsNull("targetLOT")) {
|
||||||
std::istringstream stream(result.getStringField(1));
|
std::istringstream stream(result.getStringField("targetLOT"));
|
||||||
std::string token;
|
std::string token;
|
||||||
|
|
||||||
while (std::getline(stream, token, ',')) {
|
while (std::getline(stream, token, ',')) {
|
||||||
@@ -45,7 +45,7 @@ Precondition::Precondition(const uint32_t condition) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->count = result.fieldIsNull(2) ? 1 : result.getIntField(2);
|
this->count = result.fieldIsNull("targetCount") ? 1 : result.getIntField("targetCount");
|
||||||
|
|
||||||
result.finalize();
|
result.finalize();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -878,8 +878,26 @@ void SlashCommandHandler::Startup() {
|
|||||||
};
|
};
|
||||||
RegisterCommand(TitleCommand);
|
RegisterCommand(TitleCommand);
|
||||||
|
|
||||||
|
Command ShowAllCommand{
|
||||||
|
.help = "Show all online players across World Servers",
|
||||||
|
.info = "Usage: /showall (displayZoneData: Default 1) (displayIndividualPlayers: Default 1)",
|
||||||
|
.aliases = { "showall" },
|
||||||
|
.handle = GMGreaterThanZeroCommands::ShowAll,
|
||||||
|
.requiredLevel = eGameMasterLevel::JUNIOR_MODERATOR
|
||||||
|
};
|
||||||
|
RegisterCommand(ShowAllCommand);
|
||||||
|
|
||||||
|
Command FindPlayerCommand{
|
||||||
|
.help = "Find the World Server a player is in if they are online",
|
||||||
|
.info = "Find the World Server a player is in if they are online",
|
||||||
|
.aliases = { "findplayer" },
|
||||||
|
.handle = GMGreaterThanZeroCommands::FindPlayer,
|
||||||
|
.requiredLevel = eGameMasterLevel::JUNIOR_MODERATOR
|
||||||
|
};
|
||||||
|
RegisterCommand(FindPlayerCommand);
|
||||||
|
|
||||||
// Register GM Zero Commands
|
// Register GM Zero Commands
|
||||||
|
|
||||||
Command HelpCommand{
|
Command HelpCommand{
|
||||||
.help = "Display command info",
|
.help = "Display command info",
|
||||||
.info = "If a command is given, display detailed info on that command. Otherwise display a list of commands with short desctiptions.",
|
.info = "If a command is given, display detailed info on that command. Otherwise display a list of commands with short desctiptions.",
|
||||||
|
|||||||
@@ -704,7 +704,7 @@ namespace DEVGMCommands {
|
|||||||
auto tables = query.execQuery();
|
auto tables = query.execQuery();
|
||||||
|
|
||||||
while (!tables.eof()) {
|
while (!tables.eof()) {
|
||||||
std::string message = std::to_string(tables.getIntField(0)) + " - " + tables.getStringField(1);
|
std::string message = std::to_string(tables.getIntField("id")) + " - " + tables.getStringField("name");
|
||||||
ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(message, message.size()));
|
ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::UTF8ToUTF16(message, message.size()));
|
||||||
tables.nextRow();
|
tables.nextRow();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,4 +70,4 @@ namespace DEVGMCommands {
|
|||||||
void RollLoot(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
void RollLoot(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
void CastSkill(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
void CastSkill(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
void DeleteInven(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
void DeleteInven(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,4 +287,39 @@ namespace GMGreaterThanZeroCommands {
|
|||||||
std::string name = entity->GetCharacter()->GetName() + " - " + args;
|
std::string name = entity->GetCharacter()->GetName() + " - " + args;
|
||||||
GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS);
|
GameMessages::SendSetName(entity->GetObjectID(), GeneralUtils::UTF8ToUTF16(name), UNASSIGNED_SYSTEM_ADDRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShowAll(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
||||||
|
bool displayZoneData = true;
|
||||||
|
bool displayIndividualPlayers = true;
|
||||||
|
const auto splitArgs = GeneralUtils::SplitString(args, ' ');
|
||||||
|
|
||||||
|
if (!splitArgs.empty() && !splitArgs.at(0).empty()) displayZoneData = splitArgs.at(0) == "1";
|
||||||
|
if (splitArgs.size() > 1) displayIndividualPlayers = splitArgs.at(1) == "1";
|
||||||
|
|
||||||
|
ShowAllRequest request {
|
||||||
|
.requestor = entity->GetObjectID(),
|
||||||
|
.displayZoneData = displayZoneData,
|
||||||
|
.displayIndividualPlayers = displayIndividualPlayers
|
||||||
|
};
|
||||||
|
|
||||||
|
CBITSTREAM;
|
||||||
|
request.Serialize(bitStream);
|
||||||
|
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindPlayer(Entity* entity, const SystemAddress& sysAddr, const std::string args) {
|
||||||
|
if (args.empty()) {
|
||||||
|
GameMessages::SendSlashCommandFeedbackText(entity, u"No player Given");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FindPlayerRequest request {
|
||||||
|
.requestor = entity->GetObjectID(),
|
||||||
|
.playerName = LUWString(args)
|
||||||
|
};
|
||||||
|
|
||||||
|
CBITSTREAM;
|
||||||
|
request.Serialize(bitStream);
|
||||||
|
Game::chatServer->Send(&bitStream, SYSTEM_PRIORITY, RELIABLE, 0, Game::chatSysAddr, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,4 +10,6 @@ namespace GMGreaterThanZeroCommands {
|
|||||||
void GmInvis(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
void GmInvis(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
void SetName(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
void SetName(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
void Title(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
void Title(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
}
|
void ShowAll(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
|
void FindPlayer(Entity* entity, const SystemAddress& sysAddr, const std::string args);
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,30 @@
|
|||||||
#include "eConnectionType.h"
|
#include "eConnectionType.h"
|
||||||
#include "eChatMessageType.h"
|
#include "eChatMessageType.h"
|
||||||
|
|
||||||
|
void ShowAllRequest::Serialize(RakNet::BitStream& bitStream) {
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::SHOW_ALL);
|
||||||
|
bitStream.Write(this->requestor);
|
||||||
|
bitStream.Write(this->displayZoneData);
|
||||||
|
bitStream.Write(this->displayIndividualPlayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowAllRequest::Deserialize(RakNet::BitStream& inStream) {
|
||||||
|
inStream.Read(this->requestor);
|
||||||
|
inStream.Read(this->displayZoneData);
|
||||||
|
inStream.Read(this->displayIndividualPlayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindPlayerRequest::Serialize(RakNet::BitStream& bitStream) {
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::WHO);
|
||||||
|
bitStream.Write(this->requestor);
|
||||||
|
bitStream.Write(this->playerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindPlayerRequest::Deserialize(RakNet::BitStream& inStream) {
|
||||||
|
inStream.Read(this->requestor);
|
||||||
|
inStream.Read(this->playerName);
|
||||||
|
}
|
||||||
|
|
||||||
void ChatPackets::SendChatMessage(const SystemAddress& sysAddr, char chatChannel, const std::string& senderName, LWOOBJID playerObjectID, bool senderMythran, const std::u16string& message) {
|
void ChatPackets::SendChatMessage(const SystemAddress& sysAddr, char chatChannel, const std::string& senderName, LWOOBJID playerObjectID, bool senderMythran, const std::u16string& message) {
|
||||||
CBITSTREAM;
|
CBITSTREAM;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GENERAL_CHAT_MESSAGE);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CHAT, eChatMessageType::GENERAL_CHAT_MESSAGE);
|
||||||
|
|||||||
@@ -11,6 +11,21 @@ struct SystemAddress;
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include "dCommonVars.h"
|
#include "dCommonVars.h"
|
||||||
|
|
||||||
|
struct ShowAllRequest{
|
||||||
|
LWOOBJID requestor = LWOOBJID_EMPTY;
|
||||||
|
bool displayZoneData = true;
|
||||||
|
bool displayIndividualPlayers = true;
|
||||||
|
void Serialize(RakNet::BitStream& bitStream);
|
||||||
|
void Deserialize(RakNet::BitStream& inStream);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FindPlayerRequest{
|
||||||
|
LWOOBJID requestor = LWOOBJID_EMPTY;
|
||||||
|
LUWString playerName;
|
||||||
|
void Serialize(RakNet::BitStream& bitStream);
|
||||||
|
void Deserialize(RakNet::BitStream& inStream);
|
||||||
|
};
|
||||||
|
|
||||||
namespace ChatPackets {
|
namespace ChatPackets {
|
||||||
void SendChatMessage(const SystemAddress& sysAddr, char chatChannel, const std::string& senderName, LWOOBJID playerObjectID, bool senderMythran, const std::u16string& message);
|
void SendChatMessage(const SystemAddress& sysAddr, char chatChannel, const std::string& senderName, LWOOBJID playerObjectID, bool senderMythran, const std::u16string& message);
|
||||||
void SendSystemMessage(const SystemAddress& sysAddr, const std::u16string& message, bool broadcast = false);
|
void SendSystemMessage(const SystemAddress& sysAddr, const std::u16string& message, bool broadcast = false);
|
||||||
|
|||||||
@@ -12,6 +12,15 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
void HTTPMonitorInfo::Serialize(RakNet::BitStream &bitStream) const {
|
||||||
|
bitStream.Write(port);
|
||||||
|
bitStream.Write<uint8_t>(openWeb);
|
||||||
|
bitStream.Write<uint8_t>(supportsSum);
|
||||||
|
bitStream.Write<uint8_t>(supportsDetail);
|
||||||
|
bitStream.Write<uint8_t>(supportsWho);
|
||||||
|
bitStream.Write<uint8_t>(supportsObjects);
|
||||||
|
}
|
||||||
|
|
||||||
void WorldPackets::SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum, LWOZONEID zone) {
|
void WorldPackets::SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum, LWOZONEID zone) {
|
||||||
RakNet::BitStream bitStream;
|
RakNet::BitStream bitStream;
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::LOAD_STATIC_ZONE);
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::LOAD_STATIC_ZONE);
|
||||||
@@ -160,3 +169,18 @@ void WorldPackets::SendGMLevelChange(const SystemAddress& sysAddr, bool success,
|
|||||||
|
|
||||||
SEND_PACKET;
|
SEND_PACKET;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WorldPackets::SendHTTPMonitorInfo(const SystemAddress& sysAddr, const HTTPMonitorInfo& info) {
|
||||||
|
CBITSTREAM;
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::HTTP_MONITOR_INFO_RESPONSE);
|
||||||
|
info.Serialize(bitStream);
|
||||||
|
SEND_PACKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldPackets::SendDebugOuput(const SystemAddress& sysAddr, const std::string& data){
|
||||||
|
CBITSTREAM;
|
||||||
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::DEBUG_OUTPUT);
|
||||||
|
bitStream.Write<uint32_t>(data.size());
|
||||||
|
bitStream.Write(data);
|
||||||
|
SEND_PACKET;
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,6 +10,19 @@ struct SystemAddress;
|
|||||||
enum class eGameMasterLevel : uint8_t;
|
enum class eGameMasterLevel : uint8_t;
|
||||||
enum class eCharacterCreationResponse : uint8_t;
|
enum class eCharacterCreationResponse : uint8_t;
|
||||||
enum class eRenameResponse : uint8_t;
|
enum class eRenameResponse : uint8_t;
|
||||||
|
namespace RakNet {
|
||||||
|
class BitStream;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HTTPMonitorInfo {
|
||||||
|
uint16_t port = 80;
|
||||||
|
bool openWeb = false;
|
||||||
|
bool supportsSum = false;
|
||||||
|
bool supportsDetail = false;
|
||||||
|
bool supportsWho = false;
|
||||||
|
bool supportsObjects = false;
|
||||||
|
void Serialize(RakNet::BitStream &bitstream) const;
|
||||||
|
};
|
||||||
|
|
||||||
namespace WorldPackets {
|
namespace WorldPackets {
|
||||||
void SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum, LWOZONEID zone);
|
void SendLoadStaticZone(const SystemAddress& sysAddr, float x, float y, float z, uint32_t checksum, LWOZONEID zone);
|
||||||
@@ -21,6 +34,8 @@ namespace WorldPackets {
|
|||||||
void SendCreateCharacter(const SystemAddress& sysAddr, int64_t reputation, LWOOBJID player, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm);
|
void SendCreateCharacter(const SystemAddress& sysAddr, int64_t reputation, LWOOBJID player, const std::string& xmlData, const std::u16string& username, eGameMasterLevel gm);
|
||||||
void SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::vector<std::pair<uint8_t, uint8_t>> unacceptedItems);
|
void SendChatModerationResponse(const SystemAddress& sysAddr, bool requestAccepted, uint32_t requestID, const std::string& receiver, std::vector<std::pair<uint8_t, uint8_t>> unacceptedItems);
|
||||||
void SendGMLevelChange(const SystemAddress& sysAddr, bool success, eGameMasterLevel highestLevel, eGameMasterLevel prevLevel, eGameMasterLevel newLevel);
|
void SendGMLevelChange(const SystemAddress& sysAddr, bool success, eGameMasterLevel highestLevel, eGameMasterLevel prevLevel, eGameMasterLevel newLevel);
|
||||||
|
void SendHTTPMonitorInfo(const SystemAddress& sysAddr, const HTTPMonitorInfo& info);
|
||||||
|
void SendDebugOuput(const SystemAddress& sysAddr, const std::string& data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // WORLDPACKETS_H
|
#endif // WORLDPACKETS_H
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int
|
|||||||
auto* shootingGalleryComponent = self->GetComponent<ShootingGalleryComponent>();
|
auto* shootingGalleryComponent = self->GetComponent<ShootingGalleryComponent>();
|
||||||
|
|
||||||
if (shootingGalleryComponent != nullptr) {
|
if (shootingGalleryComponent != nullptr) {
|
||||||
shootingGalleryComponent->AddActivityPlayerData(player->GetObjectID());
|
shootingGalleryComponent->SetCurrentPlayerID(player->GetObjectID());
|
||||||
|
|
||||||
LOG("Setting player ID");
|
LOG("Setting player ID");
|
||||||
|
|
||||||
|
|||||||
151
docs/ChatWebAPI.yaml
Normal file
151
docs/ChatWebAPI.yaml
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
openapi: 3.0.3
|
||||||
|
info:
|
||||||
|
title: DLU Chat Server API
|
||||||
|
description: |-
|
||||||
|
This documents the available api endpoints for the DLU Chat Server Web API
|
||||||
|
|
||||||
|
contact:
|
||||||
|
name: DarkflameUniverse Github
|
||||||
|
url: https://github.com/DarkflameUniverse/DarkflameServer/issues
|
||||||
|
license:
|
||||||
|
name: GNU AGPL v3.0
|
||||||
|
url: https://github.com/DarkflameUniverse/DarkflameServer/blob/main/LICENSE
|
||||||
|
version: 1.0.0
|
||||||
|
|
||||||
|
externalDocs:
|
||||||
|
description: Find out more about Swagger
|
||||||
|
url: http://swagger.io
|
||||||
|
|
||||||
|
servers:
|
||||||
|
- url: http://localhost:2005/
|
||||||
|
description: localhost
|
||||||
|
|
||||||
|
tags:
|
||||||
|
- name: management
|
||||||
|
description: Server Management Utilities
|
||||||
|
- name: user
|
||||||
|
description: User Data Utilities
|
||||||
|
|
||||||
|
paths:
|
||||||
|
/announce:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- management
|
||||||
|
summary: Send an announcement to the game server
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/Announce"
|
||||||
|
required: true
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful operation
|
||||||
|
"400":
|
||||||
|
description: Missing Parameter
|
||||||
|
|
||||||
|
/players:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
summary: Get all online Players
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/Player"
|
||||||
|
"204":
|
||||||
|
description: No Data
|
||||||
|
|
||||||
|
/teams:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- user
|
||||||
|
summary: Get all active Teams
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/Team"
|
||||||
|
"204":
|
||||||
|
description: No Data
|
||||||
|
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
Player:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
example: 1152921508901824000
|
||||||
|
gm_level:
|
||||||
|
type: integer
|
||||||
|
format: uint8
|
||||||
|
example: 0
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
example: thisisatestname
|
||||||
|
muted:
|
||||||
|
type: boolean
|
||||||
|
example: false
|
||||||
|
zone_id:
|
||||||
|
$ref: "#/components/schemas/ZoneID"
|
||||||
|
|
||||||
|
ZoneID:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
map_id:
|
||||||
|
type: integer
|
||||||
|
format: uint16
|
||||||
|
example: 1200
|
||||||
|
instance_id:
|
||||||
|
type: integer
|
||||||
|
format: uint16
|
||||||
|
example: 2
|
||||||
|
clone_id:
|
||||||
|
type: integer
|
||||||
|
format: uint32
|
||||||
|
example: 0
|
||||||
|
|
||||||
|
Team:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: integer
|
||||||
|
format: int64
|
||||||
|
example: 1152921508901824000
|
||||||
|
loot_flag:
|
||||||
|
type: integer
|
||||||
|
format: uint8
|
||||||
|
example: 1
|
||||||
|
local:
|
||||||
|
type: boolean
|
||||||
|
example: false
|
||||||
|
leader:
|
||||||
|
$ref: "#/components/schemas/Player"
|
||||||
|
members:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/components/schemas/Player"
|
||||||
|
|
||||||
|
Announce:
|
||||||
|
required:
|
||||||
|
- title
|
||||||
|
- message
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
example: A Mythran has taken Action against you!
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
example: Check your mailbox for details!
|
||||||
@@ -6,3 +6,11 @@ max_number_of_best_friends=5
|
|||||||
# Change the value below to what you would like this to be (50 is live accurate)
|
# Change the value below to what you would like this to be (50 is live accurate)
|
||||||
# going over 50 will be allowed in some secnarios, but proper handling will require client modding
|
# going over 50 will be allowed in some secnarios, but proper handling will require client modding
|
||||||
max_number_of_friends=50
|
max_number_of_friends=50
|
||||||
|
|
||||||
|
# Enable or disable the chat web API, disabled by default
|
||||||
|
# It will run on the same port the chat server is running on, defined in shardconfig.ini
|
||||||
|
enable_chat_web_api=0
|
||||||
|
|
||||||
|
# If that chat web api is enabled, it will only listen for connections on this ip address
|
||||||
|
# 127.0.0.1 is localhost
|
||||||
|
chat_web_api_listen_address=127.0.0.1
|
||||||
|
|||||||
@@ -15,12 +15,12 @@ TEST_F(EncodingTest, TestEncodingHello) {
|
|||||||
originalWord = "Hello World!";
|
originalWord = "Hello World!";
|
||||||
originalWordSv = originalWord;
|
originalWordSv = originalWord;
|
||||||
|
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'H');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'H');
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'e');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'e');
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'l');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'l');
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'l');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'l');
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'o');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 'o');
|
||||||
EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), true);
|
EXPECT_EQ(GeneralUtils::details::_NextUTF8Char(originalWordSv, out), true);
|
||||||
|
|
||||||
EXPECT_EQ(GeneralUtils::UTF8ToUTF16("Hello World!"), u"Hello World!");
|
EXPECT_EQ(GeneralUtils::UTF8ToUTF16("Hello World!"), u"Hello World!");
|
||||||
};
|
};
|
||||||
@@ -29,15 +29,15 @@ TEST_F(EncodingTest, TestEncodingUmlaut) {
|
|||||||
originalWord = reinterpret_cast<const char*>(u8"Frühling");
|
originalWord = reinterpret_cast<const char*>(u8"Frühling");
|
||||||
originalWordSv = originalWord;
|
originalWordSv = originalWord;
|
||||||
|
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'F');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'F');
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'r');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'r');
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'ü');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'ü');
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'h');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'h');
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'l');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'l');
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'i');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'i');
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'n');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'n');
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'g');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'g');
|
||||||
EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), false);
|
EXPECT_EQ(GeneralUtils::details::_NextUTF8Char(originalWordSv, out), false);
|
||||||
|
|
||||||
EXPECT_EQ(GeneralUtils::UTF8ToUTF16("Frühling"), u"Frühling");
|
EXPECT_EQ(GeneralUtils::UTF8ToUTF16("Frühling"), u"Frühling");
|
||||||
};
|
};
|
||||||
@@ -46,10 +46,10 @@ TEST_F(EncodingTest, TestEncodingChinese) {
|
|||||||
originalWord = "中文字";
|
originalWord = "中文字";
|
||||||
originalWordSv = originalWord;
|
originalWordSv = originalWord;
|
||||||
|
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'中');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'中');
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'文');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'文');
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'字');
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, U'字');
|
||||||
EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), false);
|
EXPECT_EQ(GeneralUtils::details::_NextUTF8Char(originalWordSv, out), false);
|
||||||
|
|
||||||
EXPECT_EQ(GeneralUtils::UTF8ToUTF16("中文字"), u"中文字");
|
EXPECT_EQ(GeneralUtils::UTF8ToUTF16("中文字"), u"中文字");
|
||||||
};
|
};
|
||||||
@@ -58,11 +58,11 @@ TEST_F(EncodingTest, TestEncodingEmoji) {
|
|||||||
originalWord = "👨⚖️";
|
originalWord = "👨⚖️";
|
||||||
originalWordSv = originalWord;
|
originalWordSv = originalWord;
|
||||||
|
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x1F468);
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x1F468);
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x200D);
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x200D);
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x2696);
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0x2696);
|
||||||
GeneralUtils::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0xFE0F);
|
GeneralUtils::details::_NextUTF8Char(originalWordSv, out); EXPECT_EQ(out, 0xFE0F);
|
||||||
EXPECT_EQ(GeneralUtils::_NextUTF8Char(originalWordSv, out), false);
|
EXPECT_EQ(GeneralUtils::details::_NextUTF8Char(originalWordSv, out), false);
|
||||||
|
|
||||||
EXPECT_EQ(GeneralUtils::UTF8ToUTF16("👨⚖️"), u"👨⚖️");
|
EXPECT_EQ(GeneralUtils::UTF8ToUTF16("👨⚖️"), u"👨⚖️");
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user