feat(Core): Add clustering support (#16832)
Co-authored-by: 3kynox <thierry.prost@gmail.com> Co-authored-by: nox <nox@noxen.net> Co-authored-by: Ludwig <sudlud@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
f23ac046ab
commit
6f0ba8e896
Vendored
+1
@@ -107,6 +107,7 @@ option(WITH_STRICT_DATABASE_TYPE_CHECKS "Enable strict checking of database fiel
|
|||||||
option(WITHOUT_METRICS "Disable metrics reporting (i.e. InfluxDB and Grafana)" 0)
|
option(WITHOUT_METRICS "Disable metrics reporting (i.e. InfluxDB and Grafana)" 0)
|
||||||
option(WITH_DETAILED_METRICS "Enable detailed metrics reporting (i.e. time each session takes to update)" 0)
|
option(WITH_DETAILED_METRICS "Enable detailed metrics reporting (i.e. time each session takes to update)" 0)
|
||||||
option(TOOL_CONFIG_MERGER "Install the Python config merger tool alongside config files" 0)
|
option(TOOL_CONFIG_MERGER "Install the Python config merger tool alongside config files" 0)
|
||||||
|
option(USE_REAL_LIBSIDECAR "Use real libsidecar and expect that compiled shared lib is in deps/libsidecar folder." 0)
|
||||||
|
|
||||||
CheckApplicationsBuildList()
|
CheckApplicationsBuildList()
|
||||||
CheckToolsBuildList()
|
CheckToolsBuildList()
|
||||||
|
|||||||
Vendored
+2
@@ -47,3 +47,5 @@ if (BUILD_TOOLS_MAPS)
|
|||||||
add_subdirectory(libmpq)
|
add_subdirectory(libmpq)
|
||||||
add_subdirectory(fkYAML)
|
add_subdirectory(fkYAML)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(libsidecar)
|
||||||
|
|||||||
Vendored
+4
@@ -85,3 +85,7 @@ recastnavigation (Recast is state of the art navigation mesh construction toolse
|
|||||||
fkYAML (A C++ header-only YAML library)
|
fkYAML (A C++ header-only YAML library)
|
||||||
https://github.com/fktn-k/fkYAML
|
https://github.com/fktn-k/fkYAML
|
||||||
Version: 721edb3e1a817e527fd9e1e18a3bea300822522e
|
Version: 721edb3e1a817e527fd9e1e18a3bea300822522e
|
||||||
|
|
||||||
|
libsidecar (enables interaction with other components when the worldserver is running in cluster mode. It requires building a shared library first and putting it in the corresponding folder.)
|
||||||
|
https://github.com/walkline/ToCloud9/tree/master/game-server/libsidecar
|
||||||
|
Version: master
|
||||||
|
|||||||
Vendored
+66
@@ -0,0 +1,66 @@
|
|||||||
|
#
|
||||||
|
# This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
#
|
||||||
|
# This file is free software; as a special exception the author gives
|
||||||
|
# unlimited permission to copy and/or distribute it, with or without
|
||||||
|
# modifications, as long as this notice is preserved.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful, but
|
||||||
|
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||||
|
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
#
|
||||||
|
|
||||||
|
# Use stub implementation only when the real libsidecar is disabled.
|
||||||
|
if (NOT USE_REAL_LIBSIDECAR)
|
||||||
|
|
||||||
|
file(GLOB sources stub/*.c stub/*.h)
|
||||||
|
|
||||||
|
add_library(libsidecar STATIC ${sources})
|
||||||
|
|
||||||
|
set_target_properties(libsidecar
|
||||||
|
PROPERTIES
|
||||||
|
LINKER_LANGUAGE
|
||||||
|
CXX
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/stub)
|
||||||
|
|
||||||
|
else()
|
||||||
|
add_library(libsidecar SHARED IMPORTED GLOBAL)
|
||||||
|
|
||||||
|
# Determine the correct library extension based on platform
|
||||||
|
if(WIN32)
|
||||||
|
set(LIBSIDECAR_EXTENSION "dll")
|
||||||
|
set(LIBSIDECAR_IMPORT_LIB "libsidecar.lib")
|
||||||
|
elseif(APPLE)
|
||||||
|
set(LIBSIDECAR_EXTENSION "dylib")
|
||||||
|
else()
|
||||||
|
set(LIBSIDECAR_EXTENSION "so")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set_target_properties(libsidecar
|
||||||
|
PROPERTIES
|
||||||
|
IMPORTED_LOCATION
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libsidecar.${LIBSIDECAR_EXTENSION}
|
||||||
|
IMPORTED_IMPLIB
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/${LIBSIDECAR_IMPORT_LIB}
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||||
|
else()
|
||||||
|
set_target_properties(libsidecar
|
||||||
|
PROPERTIES
|
||||||
|
IMPORTED_LOCATION
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/libsidecar.${LIBSIDECAR_EXTENSION}
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||||
|
IMPORTED_NO_SONAME
|
||||||
|
true)
|
||||||
|
|
||||||
|
set_target_properties(libsidecar PROPERTIES
|
||||||
|
IMPORTED_LOCATION_NOCONFIG
|
||||||
|
"${CMAKE_INSTALL_RPATH}/libsidecar.${LIBSIDECAR_EXTENSION}"
|
||||||
|
IMPORTED_SONAME_NOCONFIG
|
||||||
|
"libsidecar.${LIBSIDECAR_EXTENSION}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
endif()
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
#ifndef __BATTLEGROUND_API__
|
||||||
|
#define __BATTLEGROUND_API__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum BattlegroundErrorCode {
|
||||||
|
BattlegroundErrorCodeNoError = 0,
|
||||||
|
BattlegroundErrorCodeNoHandler = 1,
|
||||||
|
BattlegroundErrorFailedToCreateBG = 2,
|
||||||
|
BattlegroundErrorBattlegroundNotFound = 3,
|
||||||
|
} BattlegroundErrorCode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t battlegroundTypeID;
|
||||||
|
uint32_t arenaType;
|
||||||
|
bool isRated;
|
||||||
|
uint32_t mapID;
|
||||||
|
uint8_t bracketLvl;
|
||||||
|
uint64_t *hordePlayersToAdd;
|
||||||
|
int hordePlayersToAddSize;
|
||||||
|
uint64_t *alliancePlayersToAdd;
|
||||||
|
int alliancePlayersToAddSize;
|
||||||
|
uint64_t *randomBGPlayers;
|
||||||
|
int randomBGPlayersSize;
|
||||||
|
} BattlegroundStartRequest;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
uint64_t instanceID;
|
||||||
|
uint64_t instanceClientID;
|
||||||
|
} BattlegroundStartResponse;
|
||||||
|
|
||||||
|
typedef BattlegroundStartResponse (*BattlegroundStartHandler) (BattlegroundStartRequest* request);
|
||||||
|
void SetBattlegroundStartHandler(BattlegroundStartHandler h);
|
||||||
|
BattlegroundStartResponse CallBattlegroundStartHandler(BattlegroundStartRequest* request);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t battlegroundTypeID;
|
||||||
|
uint64_t instanceID;
|
||||||
|
uint64_t *hordePlayersToAdd;
|
||||||
|
int hordePlayersToAddSize;
|
||||||
|
uint64_t *alliancePlayersToAdd;
|
||||||
|
int alliancePlayersToAddSize;
|
||||||
|
uint64_t *randomBGPlayers;
|
||||||
|
int randomBGPlayersSize;
|
||||||
|
} BattlegroundAddPlayersRequest;
|
||||||
|
|
||||||
|
typedef BattlegroundErrorCode (*BattlegroundAddPlayersHandler) (BattlegroundAddPlayersRequest* request);
|
||||||
|
void SetBattlegroundAddPlayersHandler(BattlegroundAddPlayersHandler h);
|
||||||
|
BattlegroundErrorCode CallBattlegroundAddPlayersHandler(BattlegroundAddPlayersRequest* request);
|
||||||
|
|
||||||
|
typedef enum BattlegroundJoinCheckErrorCode {
|
||||||
|
BattlegroundJoinCheckErrorCodeOK = 0,
|
||||||
|
BattlegroundJoinCheckErrorCodeNoHook = 1,
|
||||||
|
BattlegroundJoinCheckErrorCodeResponseIsFalse = 2,
|
||||||
|
BattlegroundJoinCheckErrorCodePlayerNotFound = 3,
|
||||||
|
} BattlegroundJoinCheckErrorCode;
|
||||||
|
|
||||||
|
typedef BattlegroundJoinCheckErrorCode (*CanPlayerJoinBattlegroundQueueHandler)(uint64_t playerGuid);
|
||||||
|
void SetCanPlayerJoinBattlegroundQueueHandler(CanPlayerJoinBattlegroundQueueHandler h);
|
||||||
|
BattlegroundJoinCheckErrorCode CallCanPlayerJoinBattlegroundQueueHandler(uint64_t playerGuid);
|
||||||
|
|
||||||
|
typedef BattlegroundJoinCheckErrorCode (*CanPlayerTeleportToBattlegroundHandler)(uint64_t playerGuid);
|
||||||
|
void SetCanPlayerTeleportToBattlegroundHandler(CanPlayerTeleportToBattlegroundHandler h);
|
||||||
|
BattlegroundJoinCheckErrorCode CallCanPlayerTeleportToBattlegroundHandler(uint64_t playerGuid);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
+66
@@ -0,0 +1,66 @@
|
|||||||
|
#ifndef __EVENT_GROUP__
|
||||||
|
#define __EVENT_GROUP__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum GroupStatus {
|
||||||
|
GroupHookStatusOK = 0,
|
||||||
|
GroupHookStatusNoHook = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t guid;
|
||||||
|
uint64_t leader;
|
||||||
|
uint8_t lootMethod;
|
||||||
|
uint64_t looterGuid;
|
||||||
|
uint8_t lootThreshold;
|
||||||
|
uint8_t groupType;
|
||||||
|
uint8_t difficulty;
|
||||||
|
uint8_t raidDifficulty;
|
||||||
|
uint64_t masterLooterGuid;
|
||||||
|
uint64_t *members;
|
||||||
|
uint8_t membersSize;
|
||||||
|
} EventObjectGroup;
|
||||||
|
|
||||||
|
typedef void (*OnGroupCreatedHook) (EventObjectGroup *group);
|
||||||
|
void SetOnGroupCreatedHook(OnGroupCreatedHook h);
|
||||||
|
int CallOnGroupCreatedHook(EventObjectGroup *group);
|
||||||
|
|
||||||
|
typedef void (*OnGroupMemberAddedHook) (uint32_t guid, uint64_t newMemberGuid);
|
||||||
|
void SetOnGroupMemberAddedHook(OnGroupMemberAddedHook h);
|
||||||
|
int CallOnGroupMemberAddedHook(uint32_t guid, uint64_t newMemberGuid);
|
||||||
|
|
||||||
|
typedef void (*OnGroupMemberRemovedHook) (uint32_t guid, uint64_t removedMemberGuid, uint64_t newLeaderGuid);
|
||||||
|
void SetOnGroupMemberRemovedHook(OnGroupMemberRemovedHook h);
|
||||||
|
int CallOnGroupMemberRemovedHook(uint32_t guid, uint64_t removedMemberGuid, uint64_t newLeaderGuid);
|
||||||
|
|
||||||
|
typedef void (*OnGroupDisbandedHook) (uint32_t guid);
|
||||||
|
void SetOnGroupDisbandedHook(OnGroupDisbandedHook h);
|
||||||
|
int CallOnGroupDisbandedHook(uint32_t guid);
|
||||||
|
|
||||||
|
typedef void (*OnGroupLootTypeChangedHook) (uint32_t guid, uint8_t lootMethod, uint64_t looter, uint8_t lootThreshold);
|
||||||
|
void SetOnGroupLootTypeChangedHook(OnGroupLootTypeChangedHook h);
|
||||||
|
int CallOnGroupLootTypeChangedHook(uint32_t guid, uint8_t lootMethod, uint64_t looter, uint8_t lootThreshold);
|
||||||
|
|
||||||
|
typedef void (*OnGroupDungeonDifficultyChangedHook) (uint32_t guid, uint8_t difficulty);
|
||||||
|
void SetOnGroupDungeonDifficultyChangedHook(OnGroupDungeonDifficultyChangedHook h);
|
||||||
|
int CallOnGroupDungeonDifficultyChangedHook(uint32_t guid, uint8_t difficulty);
|
||||||
|
|
||||||
|
typedef void (*OnGroupRaidDifficultyChangedHook) (uint32_t guid, uint8_t difficulty);
|
||||||
|
void SetOnGroupRaidDifficultyChangedHook(OnGroupRaidDifficultyChangedHook h);
|
||||||
|
int CallOnGroupRaidDifficultyChangedHook(uint32_t guid, uint8_t difficulty);
|
||||||
|
|
||||||
|
typedef void (*OnGroupConvertedToRaidHook) (uint32_t guid);
|
||||||
|
void SetOnGroupConvertedToRaidHook(OnGroupConvertedToRaidHook h);
|
||||||
|
int CallOnGroupConvertedToRaidHook(uint32_t guid);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
#ifndef __EVENT_GUILD__
|
||||||
|
#define __EVENT_GUILD__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum GuildHookStatus {
|
||||||
|
GuildHookStatusOK = 0,
|
||||||
|
GuildHookStatusNoHook = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*OnGuildMemberAddedHook) (uint64_t /*guild_id*/, uint64_t /*player_guid*/);
|
||||||
|
void SetOnGuildMemberAddedHook(OnGuildMemberAddedHook h);
|
||||||
|
int CallOnGuildMemberAddedHook(uint64_t guild_id, uint64_t player_guid);
|
||||||
|
|
||||||
|
typedef void (*OnGuildMemberLeftHook) (uint64_t /*guild_id*/, uint64_t /*player_guid*/);
|
||||||
|
void SetOnGuildMemberLeftHook(OnGuildMemberLeftHook h);
|
||||||
|
int CallOnGuildMemberLeftHook(uint64_t guild_id, uint64_t player_guid);
|
||||||
|
|
||||||
|
typedef void (*OnGuildMemberRemovedHook) (uint64_t /*guild_id*/, uint64_t /*player_guid*/);
|
||||||
|
void SetOnGuildMemberRemovedHook(OnGuildMemberRemovedHook h);
|
||||||
|
int CallOnGuildMemberRemovedHook(uint64_t guild_id, uint64_t player_guid);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef __EVENT_SERVERS_REGISTRY__
|
||||||
|
#define __EVENT_SERVERS_REGISTRY__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum ServersRegistryStatus {
|
||||||
|
ServersRegistryHookStatusOK = 0,
|
||||||
|
ServersRegistryHookStatusNoHook = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*OnMapsReassignedHook) (uint32_t* /*maps_added*/, int /*maps_added_size*/, uint32_t* /*maps_removed*/, int /*maps_removed_size*/);
|
||||||
|
void SetOnMapsReassignedHook(OnMapsReassignedHook h);
|
||||||
|
int CallOnMapsReassignedHook(uint32_t* maps_added, int maps_added_size, uint32_t* maps_removed, int maps_removed_size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
Vendored
+116
@@ -0,0 +1,116 @@
|
|||||||
|
#ifndef __LIBSIDECAR_H__
|
||||||
|
#define __LIBSIDECAR_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/* Export/import decoration for Windows DLL */
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifdef TC9_BUILDING_DLL
|
||||||
|
#define TC9_API __declspec(dllexport)
|
||||||
|
#else
|
||||||
|
#define TC9_API __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#ifdef TC9_BUILDING_DLL
|
||||||
|
#define TC9_API __attribute__((visibility("default")))
|
||||||
|
#else
|
||||||
|
#define TC9_API
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Include all API headers */
|
||||||
|
#include "battleground-api.h"
|
||||||
|
#include "events-group.h"
|
||||||
|
#include "events-guild.h"
|
||||||
|
#include "events-servers-registry.h"
|
||||||
|
#include "monitoring.h"
|
||||||
|
#include "player-interactions-api.h"
|
||||||
|
#include "player-items-api.h"
|
||||||
|
#include "player-money-api.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Main library functions */
|
||||||
|
TC9_API void TC9InitLib(uint16_t port, uint32_t realmID, uint8_t isCrossRealm, char* availableMaps, uint32_t** assignedMaps, int* assignedMapsSize);
|
||||||
|
TC9_API void TC9GracefulShutdown();
|
||||||
|
TC9_API void TC9ProcessGRPCOrHTTPRequests();
|
||||||
|
TC9_API void TC9ProcessEventsHooks();
|
||||||
|
|
||||||
|
/* GUID generation */
|
||||||
|
TC9_API uint64_t TC9GetNextAvailableCharacterGuid(int realmID);
|
||||||
|
TC9_API uint64_t TC9GetNextAvailableItemGuid(int realmID);
|
||||||
|
TC9_API uint64_t TC9GetNextAvailableInstanceGuid(int realmID);
|
||||||
|
|
||||||
|
/* Map loading notification */
|
||||||
|
TC9_API void TC9ReadyToAcceptPlayersFromMaps(uint32_t* maps, int mapsLen);
|
||||||
|
|
||||||
|
/* Generic NATS pub/sub. Payloads are opaque bytes, subjects are arbitrary.
|
||||||
|
* Subscription callbacks run on the thread draining TC9ProcessEventsHooks
|
||||||
|
* (the world update thread), not on the NATS delivery thread. Both return
|
||||||
|
* 0 on success, -1 on failure.
|
||||||
|
*
|
||||||
|
* Example — a mod broadcasting and consuming its own events:
|
||||||
|
*
|
||||||
|
* // Publish (any thread):
|
||||||
|
* const char msg[] = "{\"zone\":1519,\"boss\":466}";
|
||||||
|
* TC9NatsPublish("mymod.boss.spawned", msg, sizeof(msg) - 1);
|
||||||
|
*
|
||||||
|
* // Subscribe once at startup; the handler runs on the world update
|
||||||
|
* // thread, so it is safe to touch game state from it:
|
||||||
|
* void OnBossSpawned(const char* subject, const char* payload, int payloadLen)
|
||||||
|
* {
|
||||||
|
* std::string data(payload, payloadLen); // payload is not NUL-terminated
|
||||||
|
* // ... react to the event ...
|
||||||
|
* }
|
||||||
|
* TC9NatsSubscribe("mymod.boss.spawned", &OnBossSpawned);
|
||||||
|
*/
|
||||||
|
typedef void (*TC9NatsMessageHandler)(const char* subject, const char* payload, int payloadLen);
|
||||||
|
TC9_API int TC9NatsPublish(const char* subject, const char* payload, int payloadLen);
|
||||||
|
TC9_API int TC9NatsSubscribe(const char* subject, TC9NatsMessageHandler handler);
|
||||||
|
|
||||||
|
/* Matchmaking notifications */
|
||||||
|
TC9_API void TC9PlayerLeftBattleground(uint64_t playerGUID, uint32_t realmID, uint32_t instanceID);
|
||||||
|
TC9_API void TC9BattlegroundStatusChanged(uint32_t instanceID, uint8_t status);
|
||||||
|
|
||||||
|
/* Event hooks registration */
|
||||||
|
TC9_API void TC9SetOnGroupCreatedHook(OnGroupCreatedHook h);
|
||||||
|
TC9_API void TC9SetOnGroupMemberAddedHook(OnGroupMemberAddedHook h);
|
||||||
|
TC9_API void TC9SetOnGroupMemberRemovedHook(OnGroupMemberRemovedHook h);
|
||||||
|
TC9_API void TC9SetOnGroupDisbandedHook(OnGroupDisbandedHook h);
|
||||||
|
TC9_API void TC9SetOnGroupLootTypeChangedHook(OnGroupLootTypeChangedHook h);
|
||||||
|
TC9_API void TC9SetOnGroupDungeonDifficultyChangedHook(OnGroupDungeonDifficultyChangedHook h);
|
||||||
|
TC9_API void TC9SetOnGroupRaidDifficultyChangedHook(OnGroupRaidDifficultyChangedHook h);
|
||||||
|
TC9_API void TC9SetOnGroupConvertedToRaidHook(OnGroupConvertedToRaidHook h);
|
||||||
|
|
||||||
|
TC9_API void TC9SetOnGuildMemberAddedHook(OnGuildMemberAddedHook h);
|
||||||
|
TC9_API void TC9SetOnGuildMemberRemovedHook(OnGuildMemberRemovedHook h);
|
||||||
|
TC9_API void TC9SetOnGuildMemberLeftHook(OnGuildMemberLeftHook h);
|
||||||
|
|
||||||
|
TC9_API void TC9SetOnMapsReassignedHook(OnMapsReassignedHook h);
|
||||||
|
|
||||||
|
/* Handler registration for gRPC requests */
|
||||||
|
TC9_API void TC9SetBattlegroundStartHandler(BattlegroundStartHandler h);
|
||||||
|
TC9_API void TC9SetBattlegroundAddPlayersHandler(BattlegroundAddPlayersHandler h);
|
||||||
|
TC9_API void TC9SetCanPlayerJoinBattlegroundQueueHandler(CanPlayerJoinBattlegroundQueueHandler h);
|
||||||
|
TC9_API void TC9SetCanPlayerTeleportToBattlegroundHandler(CanPlayerTeleportToBattlegroundHandler h);
|
||||||
|
|
||||||
|
TC9_API void TC9SetMonitoringDataCollectorHandler(MonitoringDataCollectorHandler h);
|
||||||
|
|
||||||
|
TC9_API void TC9SetCanPlayerInteractWithNPCAndFlagsHandler(CanPlayerInteractWithNPCAndFlagsHandler h);
|
||||||
|
TC9_API void TC9SetCanPlayerInteractWithGOAndTypeHandler(CanPlayerInteractWithGOAndTypeHandler h);
|
||||||
|
|
||||||
|
TC9_API void TC9SetGetPlayerItemsByGuidsHandler(GetPlayerItemsByGuidsHandler h);
|
||||||
|
TC9_API void TC9SetRemoveItemsWithGuidsFromPlayerHandler(RemoveItemsWithGuidsFromPlayerHandler h);
|
||||||
|
TC9_API void TC9SetAddExistingItemToPlayerHandler(AddExistingItemToPlayerHandler h);
|
||||||
|
|
||||||
|
TC9_API void TC9SetGetMoneyForPlayerHandler(GetMoneyForPlayerHandler h);
|
||||||
|
TC9_API void TC9SetModifyMoneyForPlayerHandler(ModifyMoneyForPlayerHandler h);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __LIBSIDECAR_H__ */
|
||||||
Vendored
+36
@@ -0,0 +1,36 @@
|
|||||||
|
#ifndef __MONITORING__
|
||||||
|
#define __MONITORING__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum MonitoringErrorCode {
|
||||||
|
MonitoringErrorCodeNoError = 0,
|
||||||
|
MonitoringErrorCodeNoHandler = 1,
|
||||||
|
} MonitoringErrorCode;
|
||||||
|
|
||||||
|
// MonitoringDataCollectorResponse request.
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
uint32_t connectedPlayers;
|
||||||
|
uint32_t diffMean;
|
||||||
|
uint32_t diffMedian;
|
||||||
|
uint32_t diff95Percentile;
|
||||||
|
uint32_t diff99Percentile;
|
||||||
|
uint32_t diffMaxPercentile;
|
||||||
|
} MonitoringDataCollectorResponse;
|
||||||
|
|
||||||
|
typedef MonitoringDataCollectorResponse (*MonitoringDataCollectorHandler)();
|
||||||
|
void SetMonitoringDataCollectorHandler(MonitoringDataCollectorHandler h);
|
||||||
|
MonitoringDataCollectorResponse CallMonitoringDataCollectorHandler();
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
#ifndef __PLAYER_INTERACTIONS_API__
|
||||||
|
#define __PLAYER_INTERACTIONS_API__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum PlayerInteractionErrorCode {
|
||||||
|
PlayerInteractionErrorCodeNoError = 0,
|
||||||
|
PlayerInteractionErrorCodeNoHandler = 1,
|
||||||
|
PlayerInteractionErrorCodeCodePlayerNotFound = 2,
|
||||||
|
} PlayerInteractionErrorCode;
|
||||||
|
|
||||||
|
// CanPlayerInteractWithNPCAndFlags request.
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
bool canInteract;
|
||||||
|
} CanPlayerInteractWithNPCAndFlagsResponse;
|
||||||
|
|
||||||
|
typedef CanPlayerInteractWithNPCAndFlagsResponse (*CanPlayerInteractWithNPCAndFlagsHandler) (uint64_t /*playerGUID*/, uint64_t /*npcGUID*/, uint32_t /*npcFlags*/);
|
||||||
|
void SetCanPlayerInteractWithNPCAndFlagsHandler(CanPlayerInteractWithNPCAndFlagsHandler h);
|
||||||
|
CanPlayerInteractWithNPCAndFlagsResponse CallCanPlayerInteractWithNPCAndFlagsHandler(uint64_t player_guid, uint64_t npc_guid, uint32_t npc_flags);
|
||||||
|
|
||||||
|
// CanPlayerInteractWithGOAndType request.
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
bool canInteract;
|
||||||
|
} CanPlayerInteractWithGOAndTypeResponse;
|
||||||
|
|
||||||
|
typedef CanPlayerInteractWithGOAndTypeResponse (*CanPlayerInteractWithGOAndTypeHandler) (uint64_t /*playerGUID*/, uint64_t /*goGUID*/, uint8_t /*goType*/);
|
||||||
|
void SetCanPlayerInteractWithGOAndTypeHandler(CanPlayerInteractWithGOAndTypeHandler h);
|
||||||
|
CanPlayerInteractWithGOAndTypeResponse CallCanPlayerInteractWithGOAndTypeHandler(uint64_t player_guid, uint64_t go_guid, uint8_t go_type);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
+76
@@ -0,0 +1,76 @@
|
|||||||
|
#ifndef __PLAYER_ITEMS_API__
|
||||||
|
#define __PLAYER_ITEMS_API__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum PlayerItemErrorCode {
|
||||||
|
PlayerItemErrorCodeNoError = 0,
|
||||||
|
PlayerItemErrorCodeNoHandler = 1,
|
||||||
|
PlayerItemErrorCodePlayerNotFound = 2,
|
||||||
|
PlayerItemErrorNoInventorySpace = 3,
|
||||||
|
PlayerItemErrorUnknownTemplate = 4,
|
||||||
|
PlayerItemErrorFailedToCreateItem = 5
|
||||||
|
} PlayerItemErrorCode;
|
||||||
|
|
||||||
|
// GetPlayerItemsByGuids request.
|
||||||
|
typedef struct {
|
||||||
|
uint64_t guid;
|
||||||
|
uint32_t entry;
|
||||||
|
uint64_t owner;
|
||||||
|
uint8_t bagSlot;
|
||||||
|
uint8_t slot;
|
||||||
|
bool isTradable;
|
||||||
|
uint32_t count;
|
||||||
|
uint16_t flags;
|
||||||
|
uint8_t durability;
|
||||||
|
int8_t randomPropertyID;
|
||||||
|
const char* text;
|
||||||
|
} PlayerItem;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
PlayerItem* items;
|
||||||
|
int itemsSize;
|
||||||
|
} GetPlayerItemsByGuidsResponse;
|
||||||
|
|
||||||
|
typedef GetPlayerItemsByGuidsResponse (*GetPlayerItemsByGuidsHandler) (uint64_t /*player_guid*/, uint64_t* /*items_guids*/, int /*items_guids_size*/);
|
||||||
|
void SetGetPlayerItemsByGuidsHandler(GetPlayerItemsByGuidsHandler h);
|
||||||
|
GetPlayerItemsByGuidsResponse CallGetPlayerItemsByGuidsHandler(uint64_t player_guid, uint64_t* items_guids, int items_guids_size);
|
||||||
|
|
||||||
|
// RemoveItemsWithGuidsFromPlayer request.
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
uint64_t* updatedItems;
|
||||||
|
int updatedItemsSize;
|
||||||
|
} RemoveItemsWithGuidsFromPlayerResponse;
|
||||||
|
|
||||||
|
typedef RemoveItemsWithGuidsFromPlayerResponse (*RemoveItemsWithGuidsFromPlayerHandler) (uint64_t /*player_guid*/, uint64_t* /*items_guids*/, int /*items_guids_size*/, uint64_t /*assign_player_guid*/);
|
||||||
|
void SetRemoveItemsWithGuidsFromPlayerHandler(RemoveItemsWithGuidsFromPlayerHandler h);
|
||||||
|
RemoveItemsWithGuidsFromPlayerResponse CallRemoveItemsWithGuidsFromPlayerHandler(uint64_t player_guid, uint64_t* items_guids, int items_guids_size, uint64_t assign_player_guid);
|
||||||
|
|
||||||
|
// AddExistingItemToPlayer request.
|
||||||
|
typedef struct {
|
||||||
|
uint64_t playerGuid;
|
||||||
|
uint64_t itemGuid;
|
||||||
|
uint32_t itemEntry;
|
||||||
|
uint32_t itemCount;
|
||||||
|
uint16_t itemFlags;
|
||||||
|
uint8_t itemDurability;
|
||||||
|
int8_t itemRandomPropertyID;
|
||||||
|
} AddExistingItemToPlayerRequest;
|
||||||
|
|
||||||
|
typedef PlayerItemErrorCode (*AddExistingItemToPlayerHandler) (AddExistingItemToPlayerRequest*);
|
||||||
|
void SetAddExistingItemToPlayerHandler(AddExistingItemToPlayerHandler h);
|
||||||
|
PlayerItemErrorCode CallAddExistingItemToPlayerHandler(AddExistingItemToPlayerRequest*);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
#ifndef __PLAYER_MONEY_API__
|
||||||
|
#define __PLAYER_MONEY_API__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum PlayerMoneyErrorCode {
|
||||||
|
PlayerMoneyErrorCodeNoError = 0,
|
||||||
|
PlayerMoneyErrorCodeNoHandler = 1,
|
||||||
|
PlayerMoneyErrorCodePlayerNotFound = 2,
|
||||||
|
PlayerMoneyErrorCodeTooMuchMoney = 3,
|
||||||
|
} PlayerMoneyErrorCode;
|
||||||
|
|
||||||
|
// GetMoneyForPlayer request.
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
uint32_t money;
|
||||||
|
} GetMoneyForPlayerResponse;
|
||||||
|
|
||||||
|
typedef GetMoneyForPlayerResponse (*GetMoneyForPlayerHandler) (uint64_t /*player_guid*/);
|
||||||
|
void SetGetMoneyForPlayerHandler(GetMoneyForPlayerHandler h);
|
||||||
|
GetMoneyForPlayerResponse CallGetMoneyForPlayerHandler(uint64_t player_guid);
|
||||||
|
|
||||||
|
// ModifyMoneyForPlayer request.
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
uint32_t newMoneyValue;
|
||||||
|
} ModifyMoneyForPlayerResponse;
|
||||||
|
|
||||||
|
typedef ModifyMoneyForPlayerResponse (*ModifyMoneyForPlayerHandler) (uint64_t /*player_guid*/, int32_t /*amount*/);
|
||||||
|
void SetModifyMoneyForPlayerHandler(ModifyMoneyForPlayerHandler h);
|
||||||
|
ModifyMoneyForPlayerResponse CallModifyMoneyForPlayerHandler(uint64_t player_guid, int32_t amount);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
+55
@@ -0,0 +1,55 @@
|
|||||||
|
#include "battleground-api.h"
|
||||||
|
|
||||||
|
static BattlegroundStartHandler battlegroundStartHandler;
|
||||||
|
void SetBattlegroundStartHandler(BattlegroundStartHandler h) {
|
||||||
|
battlegroundStartHandler = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
BattlegroundStartResponse CallBattlegroundStartHandler(BattlegroundStartRequest* request) {
|
||||||
|
if (battlegroundStartHandler == 0) {
|
||||||
|
BattlegroundStartResponse resp;
|
||||||
|
resp.errorCode = BattlegroundErrorCodeNoHandler;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return battlegroundStartHandler(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
static BattlegroundAddPlayersHandler battlegroundAddPlayersHandler;
|
||||||
|
void SetBattlegroundAddPlayersHandler(BattlegroundAddPlayersHandler h) {
|
||||||
|
battlegroundAddPlayersHandler = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
BattlegroundErrorCode CallBattlegroundAddPlayersHandler(BattlegroundAddPlayersRequest* request) {
|
||||||
|
if (battlegroundAddPlayersHandler == 0) {
|
||||||
|
return BattlegroundErrorCodeNoHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
return battlegroundAddPlayersHandler(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CanPlayerJoinBattlegroundQueueHandler canPlayerJoinBattlegroundQueueHandler = 0;
|
||||||
|
|
||||||
|
void SetCanPlayerJoinBattlegroundQueueHandler(CanPlayerJoinBattlegroundQueueHandler h) {
|
||||||
|
canPlayerJoinBattlegroundQueueHandler = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
BattlegroundJoinCheckErrorCode CallCanPlayerJoinBattlegroundQueueHandler(uint64_t playerGuid) {
|
||||||
|
if (canPlayerJoinBattlegroundQueueHandler == 0) {
|
||||||
|
return BattlegroundJoinCheckErrorCodeNoHook;
|
||||||
|
}
|
||||||
|
return canPlayerJoinBattlegroundQueueHandler(playerGuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CanPlayerTeleportToBattlegroundHandler canPlayerTeleportToBattlegroundHandler = 0;
|
||||||
|
|
||||||
|
void SetCanPlayerTeleportToBattlegroundHandler(CanPlayerTeleportToBattlegroundHandler h) {
|
||||||
|
canPlayerTeleportToBattlegroundHandler = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
BattlegroundJoinCheckErrorCode CallCanPlayerTeleportToBattlegroundHandler(uint64_t playerGuid) {
|
||||||
|
if (canPlayerTeleportToBattlegroundHandler == 0) {
|
||||||
|
return BattlegroundJoinCheckErrorCodeNoHook;
|
||||||
|
}
|
||||||
|
return canPlayerTeleportToBattlegroundHandler(playerGuid);
|
||||||
|
}
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
#ifndef __BATTLEGROUND_API__
|
||||||
|
#define __BATTLEGROUND_API__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef enum BattlegroundErrorCode {
|
||||||
|
BattlegroundErrorCodeNoError = 0,
|
||||||
|
BattlegroundErrorCodeNoHandler = 1,
|
||||||
|
BattlegroundErrorFailedToCreateBG = 2,
|
||||||
|
BattlegroundErrorBattlegroundNotFound = 3,
|
||||||
|
} BattlegroundErrorCode;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t battlegroundTypeID;
|
||||||
|
uint32_t arenaType;
|
||||||
|
bool isRated;
|
||||||
|
uint32_t mapID;
|
||||||
|
uint8_t bracketLvl;
|
||||||
|
uint64_t *hordePlayersToAdd;
|
||||||
|
int hordePlayersToAddSize;
|
||||||
|
uint64_t *alliancePlayersToAdd;
|
||||||
|
int alliancePlayersToAddSize;
|
||||||
|
uint64_t *randomBGPlayers;
|
||||||
|
int randomBGPlayersSize;
|
||||||
|
} BattlegroundStartRequest;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
uint64_t instanceID;
|
||||||
|
uint64_t instanceClientID;
|
||||||
|
} BattlegroundStartResponse;
|
||||||
|
|
||||||
|
typedef BattlegroundStartResponse (*BattlegroundStartHandler) (BattlegroundStartRequest* request);
|
||||||
|
void SetBattlegroundStartHandler(BattlegroundStartHandler h);
|
||||||
|
BattlegroundStartResponse CallBattlegroundStartHandler(BattlegroundStartRequest* request);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t battlegroundTypeID;
|
||||||
|
uint64_t instanceID;
|
||||||
|
uint64_t *hordePlayersToAdd;
|
||||||
|
int hordePlayersToAddSize;
|
||||||
|
uint64_t *alliancePlayersToAdd;
|
||||||
|
int alliancePlayersToAddSize;
|
||||||
|
uint64_t *randomBGPlayers;
|
||||||
|
int randomBGPlayersSize;
|
||||||
|
} BattlegroundAddPlayersRequest;
|
||||||
|
|
||||||
|
typedef BattlegroundErrorCode (*BattlegroundAddPlayersHandler) (BattlegroundAddPlayersRequest* request);
|
||||||
|
void SetBattlegroundAddPlayersHandler(BattlegroundAddPlayersHandler h);
|
||||||
|
BattlegroundErrorCode CallBattlegroundAddPlayersHandler(BattlegroundAddPlayersRequest* request);
|
||||||
|
|
||||||
|
typedef enum BattlegroundJoinCheckErrorCode {
|
||||||
|
BattlegroundJoinCheckErrorCodeOK = 0,
|
||||||
|
BattlegroundJoinCheckErrorCodeNoHook = 1,
|
||||||
|
BattlegroundJoinCheckErrorCodeResponseIsFalse = 2,
|
||||||
|
BattlegroundJoinCheckErrorCodePlayerNotFound = 3,
|
||||||
|
} BattlegroundJoinCheckErrorCode;
|
||||||
|
|
||||||
|
typedef BattlegroundJoinCheckErrorCode (*CanPlayerJoinBattlegroundQueueHandler)(uint64_t playerGuid);
|
||||||
|
void SetCanPlayerJoinBattlegroundQueueHandler(CanPlayerJoinBattlegroundQueueHandler h);
|
||||||
|
BattlegroundJoinCheckErrorCode CallCanPlayerJoinBattlegroundQueueHandler(uint64_t playerGuid);
|
||||||
|
|
||||||
|
typedef BattlegroundJoinCheckErrorCode (*CanPlayerTeleportToBattlegroundHandler)(uint64_t playerGuid);
|
||||||
|
void SetCanPlayerTeleportToBattlegroundHandler(CanPlayerTeleportToBattlegroundHandler h);
|
||||||
|
BattlegroundJoinCheckErrorCode CallCanPlayerTeleportToBattlegroundHandler(uint64_t playerGuid);
|
||||||
|
|
||||||
|
#endif
|
||||||
Vendored
+117
@@ -0,0 +1,117 @@
|
|||||||
|
#include "events-group.h"
|
||||||
|
|
||||||
|
// OnGroupCreatedHook
|
||||||
|
OnGroupCreatedHook groupCreatedHook;
|
||||||
|
void SetOnGroupCreatedHook(OnGroupCreatedHook h) {
|
||||||
|
groupCreatedHook = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallOnGroupCreatedHook(EventObjectGroup *group) {
|
||||||
|
if (groupCreatedHook == 0) {
|
||||||
|
return GroupHookStatusNoHook;
|
||||||
|
}
|
||||||
|
groupCreatedHook(group);
|
||||||
|
return GroupHookStatusOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupMemberAdded
|
||||||
|
static OnGroupMemberAddedHook groupMemberAddedHook;
|
||||||
|
void SetOnGroupMemberAddedHook(OnGroupMemberAddedHook h) {
|
||||||
|
groupMemberAddedHook = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallOnGroupMemberAddedHook(uint32_t guid, uint64_t newMemberGuid) {
|
||||||
|
if (groupMemberAddedHook == 0) {
|
||||||
|
return GroupHookStatusNoHook;
|
||||||
|
}
|
||||||
|
groupMemberAddedHook(guid, newMemberGuid);
|
||||||
|
return GroupHookStatusOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GroupMemberRemoved
|
||||||
|
static OnGroupMemberRemovedHook groupMemberRemovedHook;
|
||||||
|
void SetOnGroupMemberRemovedHook(OnGroupMemberRemovedHook h) {
|
||||||
|
groupMemberRemovedHook = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallOnGroupMemberRemovedHook(uint32_t guid, uint64_t removedMemberGuid, uint64_t newLeaderGuid) {
|
||||||
|
if (groupMemberRemovedHook == 0) {
|
||||||
|
return GroupHookStatusNoHook;
|
||||||
|
}
|
||||||
|
groupMemberRemovedHook(guid, removedMemberGuid, newLeaderGuid);
|
||||||
|
return GroupHookStatusOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (*OnGroupDisbandedHook) (uint32_t guid);
|
||||||
|
void SetOnGroupDisbandedHook(OnGroupDisbandedHook h);
|
||||||
|
int CallOnGroupDisbandedHook(uint32_t guid);
|
||||||
|
|
||||||
|
static OnGroupDisbandedHook groupDisbandedHook;
|
||||||
|
void SetOnGroupDisbandedHook(OnGroupDisbandedHook h) {
|
||||||
|
groupDisbandedHook = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallOnGroupDisbandedHook(uint32_t guid) {
|
||||||
|
if (groupDisbandedHook == 0) {
|
||||||
|
return GroupHookStatusNoHook;
|
||||||
|
}
|
||||||
|
groupDisbandedHook(guid);
|
||||||
|
return GroupHookStatusOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OnGroupLootTypeChangedHook groupLootTypeChanged;
|
||||||
|
void SetOnGroupLootTypeChangedHook(OnGroupLootTypeChangedHook h) {
|
||||||
|
groupLootTypeChanged = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallOnGroupLootTypeChangedHook(uint32_t guid, uint8_t lootMethod, uint64_t looter, uint8_t lootThreshold) {
|
||||||
|
if (groupLootTypeChanged == 0) {
|
||||||
|
return GroupHookStatusNoHook;
|
||||||
|
}
|
||||||
|
groupLootTypeChanged(guid, lootMethod, looter, lootThreshold);
|
||||||
|
return GroupHookStatusOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OnGroupDungeonDifficultyChangedHook groupDungeonDifficultyChanged;
|
||||||
|
void SetOnGroupDungeonDifficultyChangedHook(OnGroupDungeonDifficultyChangedHook h) {
|
||||||
|
groupDungeonDifficultyChanged = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallOnGroupDungeonDifficultyChangedHook(uint32_t guid, uint8_t difficulty) {
|
||||||
|
if (groupDungeonDifficultyChanged == 0) {
|
||||||
|
return GroupHookStatusNoHook;
|
||||||
|
}
|
||||||
|
groupDungeonDifficultyChanged(guid, difficulty);
|
||||||
|
return GroupHookStatusOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static OnGroupRaidDifficultyChangedHook groupRaidDifficultyChanged;
|
||||||
|
void SetOnGroupRaidDifficultyChangedHook(OnGroupRaidDifficultyChangedHook h) {
|
||||||
|
groupRaidDifficultyChanged = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallOnGroupRaidDifficultyChangedHook(uint32_t guid, uint8_t difficulty) {
|
||||||
|
if (groupRaidDifficultyChanged == 0) {
|
||||||
|
return GroupHookStatusNoHook;
|
||||||
|
}
|
||||||
|
groupRaidDifficultyChanged(guid, difficulty);
|
||||||
|
return GroupHookStatusOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*OnGroupConvertedToRaidHook) (uint32_t guid);
|
||||||
|
void SetOnGroupConvertedToRaidHook(OnGroupConvertedToRaidHook h);
|
||||||
|
int CallOnGroupConvertedToRaidHook(uint32_t guid);
|
||||||
|
|
||||||
|
static OnGroupConvertedToRaidHook groupConvertedToRaid;
|
||||||
|
void SetOnGroupConvertedToRaidHook(OnGroupConvertedToRaidHook h) {
|
||||||
|
groupConvertedToRaid = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallOnGroupConvertedToRaidHook(uint32_t guid) {
|
||||||
|
if (groupConvertedToRaid == 0) {
|
||||||
|
return GroupHookStatusNoHook;
|
||||||
|
}
|
||||||
|
groupConvertedToRaid(guid);
|
||||||
|
return GroupHookStatusOK;
|
||||||
|
}
|
||||||
Vendored
+58
@@ -0,0 +1,58 @@
|
|||||||
|
#ifndef __EVENT_GROUP__
|
||||||
|
#define __EVENT_GROUP__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
enum GroupStatus {
|
||||||
|
GroupHookStatusOK = 0,
|
||||||
|
GroupHookStatusNoHook = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t guid;
|
||||||
|
uint64_t leader;
|
||||||
|
uint8_t lootMethod;
|
||||||
|
uint64_t looterGuid;
|
||||||
|
uint8_t lootThreshold;
|
||||||
|
uint8_t groupType;
|
||||||
|
uint8_t difficulty;
|
||||||
|
uint8_t raidDifficulty;
|
||||||
|
uint64_t masterLooterGuid;
|
||||||
|
uint64_t *members;
|
||||||
|
uint8_t membersSize;
|
||||||
|
} EventObjectGroup;
|
||||||
|
|
||||||
|
typedef void (*OnGroupCreatedHook) (EventObjectGroup *group);
|
||||||
|
void SetOnGroupCreatedHook(OnGroupCreatedHook h);
|
||||||
|
int CallOnGroupCreatedHook(EventObjectGroup *group);
|
||||||
|
|
||||||
|
typedef void (*OnGroupMemberAddedHook) (uint32_t guid, uint64_t newMemberGuid);
|
||||||
|
void SetOnGroupMemberAddedHook(OnGroupMemberAddedHook h);
|
||||||
|
int CallOnGroupMemberAddedHook(uint32_t guid, uint64_t newMemberGuid);
|
||||||
|
|
||||||
|
typedef void (*OnGroupMemberRemovedHook) (uint32_t guid, uint64_t removedMemberGuid, uint64_t newLeaderGuid);
|
||||||
|
void SetOnGroupMemberRemovedHook(OnGroupMemberRemovedHook h);
|
||||||
|
int CallOnGroupMemberRemovedHook(uint32_t guid, uint64_t removedMemberGuid, uint64_t newLeaderGuid);
|
||||||
|
|
||||||
|
typedef void (*OnGroupDisbandedHook) (uint32_t guid);
|
||||||
|
void SetOnGroupDisbandedHook(OnGroupDisbandedHook h);
|
||||||
|
int CallOnGroupDisbandedHook(uint32_t guid);
|
||||||
|
|
||||||
|
typedef void (*OnGroupLootTypeChangedHook) (uint32_t guid, uint8_t lootMethod, uint64_t looter, uint8_t lootThreshold);
|
||||||
|
void SetOnGroupLootTypeChangedHook(OnGroupLootTypeChangedHook h);
|
||||||
|
int CallOnGroupLootTypeChangedHook(uint32_t guid, uint8_t lootMethod, uint64_t looter, uint8_t lootThreshold);
|
||||||
|
|
||||||
|
typedef void (*OnGroupDungeonDifficultyChangedHook) (uint32_t guid, uint8_t difficulty);
|
||||||
|
void SetOnGroupDungeonDifficultyChangedHook(OnGroupDungeonDifficultyChangedHook h);
|
||||||
|
int CallOnGroupDungeonDifficultyChangedHook(uint32_t guid, uint8_t difficulty);
|
||||||
|
|
||||||
|
typedef void (*OnGroupRaidDifficultyChangedHook) (uint32_t guid, uint8_t difficulty);
|
||||||
|
void SetOnGroupRaidDifficultyChangedHook(OnGroupRaidDifficultyChangedHook h);
|
||||||
|
int CallOnGroupRaidDifficultyChangedHook(uint32_t guid, uint8_t difficulty);
|
||||||
|
|
||||||
|
typedef void (*OnGroupConvertedToRaidHook) (uint32_t guid);
|
||||||
|
void SetOnGroupConvertedToRaidHook(OnGroupConvertedToRaidHook h);
|
||||||
|
int CallOnGroupConvertedToRaidHook(uint32_t guid);
|
||||||
|
|
||||||
|
#endif
|
||||||
Vendored
+43
@@ -0,0 +1,43 @@
|
|||||||
|
#include "events-guild.h"
|
||||||
|
|
||||||
|
// GuildMemberAddedHook
|
||||||
|
OnGuildMemberAddedHook guildMemberAddedHook;
|
||||||
|
void SetOnGuildMemberAddedHook(OnGuildMemberAddedHook h) {
|
||||||
|
guildMemberAddedHook = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallOnGuildMemberAddedHook(uint64_t guild_id, uint64_t player_guid) {
|
||||||
|
if (guildMemberAddedHook == 0) {
|
||||||
|
return GuildHookStatusNoHook;
|
||||||
|
}
|
||||||
|
guildMemberAddedHook(guild_id, player_guid);
|
||||||
|
return GuildHookStatusOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GuildMemberLeft
|
||||||
|
static OnGuildMemberLeftHook guildMemberLeftHook;
|
||||||
|
void SetOnGuildMemberLeftHook(OnGuildMemberLeftHook h) {
|
||||||
|
guildMemberLeftHook = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallOnGuildMemberLeftHook(uint64_t guild_id, uint64_t player_guid) {
|
||||||
|
if (guildMemberLeftHook == 0) {
|
||||||
|
return GuildHookStatusNoHook;
|
||||||
|
}
|
||||||
|
guildMemberLeftHook(guild_id, player_guid);
|
||||||
|
return GuildHookStatusOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GuildMemberRemoved
|
||||||
|
static OnGuildMemberRemovedHook guildMemberRemovedHook;
|
||||||
|
void SetOnGuildMemberRemovedHook(OnGuildMemberRemovedHook h) {
|
||||||
|
guildMemberRemovedHook = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallOnGuildMemberRemovedHook(uint64_t guild_id, uint64_t player_guid) {
|
||||||
|
if (guildMemberRemovedHook == 0) {
|
||||||
|
return GuildHookStatusNoHook;
|
||||||
|
}
|
||||||
|
guildMemberRemovedHook(guild_id, player_guid);
|
||||||
|
return GuildHookStatusOK;
|
||||||
|
}
|
||||||
Vendored
+23
@@ -0,0 +1,23 @@
|
|||||||
|
#ifndef __EVENT_GUILD__
|
||||||
|
#define __EVENT_GUILD__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum GuildHookStatus {
|
||||||
|
GuildHookStatusOK = 0,
|
||||||
|
GuildHookStatusNoHook = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*OnGuildMemberAddedHook) (uint64_t /*guild_id*/, uint64_t /*player_guid*/);
|
||||||
|
void SetOnGuildMemberAddedHook(OnGuildMemberAddedHook h);
|
||||||
|
int CallOnGuildMemberAddedHook(uint64_t guild_id, uint64_t player_guid);
|
||||||
|
|
||||||
|
typedef void (*OnGuildMemberLeftHook) (uint64_t /*guild_id*/, uint64_t /*player_guid*/);
|
||||||
|
void SetOnGuildMemberLeftHook(OnGuildMemberLeftHook h);
|
||||||
|
int CallOnGuildMemberLeftHook(uint64_t guild_id, uint64_t player_guid);
|
||||||
|
|
||||||
|
typedef void (*OnGuildMemberRemovedHook) (uint64_t /*guild_id*/, uint64_t /*player_guid*/);
|
||||||
|
void SetOnGuildMemberRemovedHook(OnGuildMemberRemovedHook h);
|
||||||
|
int CallOnGuildMemberRemovedHook(uint64_t guild_id, uint64_t player_guid);
|
||||||
|
|
||||||
|
#endif
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#include "events-servers-registry.h"
|
||||||
|
|
||||||
|
// MapsReassignedHook
|
||||||
|
OnMapsReassignedHook mapsReassignedHook;
|
||||||
|
void SetOnMapsReassignedHook(OnMapsReassignedHook h) {
|
||||||
|
mapsReassignedHook = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CallOnMapsReassignedHook(uint32_t* maps_added, int maps_added_size, uint32_t* maps_removed, int maps_removed_size) {
|
||||||
|
if (mapsReassignedHook == 0) {
|
||||||
|
return ServersRegistryHookStatusNoHook;
|
||||||
|
}
|
||||||
|
mapsReassignedHook(maps_added, maps_added_size, maps_removed, maps_removed_size);
|
||||||
|
return ServersRegistryHookStatusOK;
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __EVENT_SERVERS_REGISTRY__
|
||||||
|
#define __EVENT_SERVERS_REGISTRY__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
enum ServersRegistryStatus {
|
||||||
|
ServersRegistryHookStatusOK = 0,
|
||||||
|
ServersRegistryHookStatusNoHook = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*OnMapsReassignedHook) (uint32_t* /*maps_added*/, int /*maps_added_size*/, uint32_t* /*maps_removed*/, int /*maps_removed_size*/);
|
||||||
|
void SetOnMapsReassignedHook(OnMapsReassignedHook h);
|
||||||
|
int CallOnMapsReassignedHook(uint32_t* maps_added, int maps_added_size, uint32_t* maps_removed, int maps_removed_size);
|
||||||
|
|
||||||
|
#endif
|
||||||
Vendored
+138
@@ -0,0 +1,138 @@
|
|||||||
|
#include "libsidecar.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void panicWithTC9Unavailable(const char* message) {
|
||||||
|
fprintf(stderr, "Tried to call '%s', but using stub for libsidecar. Use -DUSE_REAL_LIBSIDECAR=ON in cmake to use the real one.\n", message);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TC9SetBattlegroundStartHandler sets handler for starting battleground.
|
||||||
|
//
|
||||||
|
extern void TC9SetBattlegroundStartHandler(BattlegroundStartHandler h) { panicWithTC9Unavailable("TC9SetBattlegroundStartHandler"); }
|
||||||
|
|
||||||
|
// TC9SetBattlegroundAddPlayersHandler sets handler for adding players to battleground.
|
||||||
|
//
|
||||||
|
extern void TC9SetBattlegroundAddPlayersHandler(BattlegroundAddPlayersHandler h) { panicWithTC9Unavailable("TC9SetBattlegroundAddPlayersHandler"); }
|
||||||
|
|
||||||
|
void TC9SetOnGroupCreatedHook(OnGroupCreatedHook h) { panicWithTC9Unavailable("TC9SetOnGroupCreatedHook"); }
|
||||||
|
|
||||||
|
// TC9SetOnGroupMemberAddedHook sets hook for member added event.
|
||||||
|
//
|
||||||
|
void TC9SetOnGroupMemberAddedHook(OnGroupMemberAddedHook h) { panicWithTC9Unavailable("TC9SetOnGroupMemberAddedHook"); }
|
||||||
|
|
||||||
|
// TC9SetOnGroupMemberRemovedHook sets hook for member left/kicked event.
|
||||||
|
//
|
||||||
|
void TC9SetOnGroupMemberRemovedHook(OnGroupMemberRemovedHook h) { panicWithTC9Unavailable("TC9SetOnGroupMemberRemovedHook"); }
|
||||||
|
|
||||||
|
// TC9SetOnGroupDisbandedHook sets hook for group disbanded event.
|
||||||
|
//
|
||||||
|
void TC9SetOnGroupDisbandedHook(OnGroupDisbandedHook h) { panicWithTC9Unavailable("TC9SetOnGroupDisbandedHook"); }
|
||||||
|
|
||||||
|
// TC9SetOnGroupLootTypeChangedHook sets hook for group loot type changed event.
|
||||||
|
//
|
||||||
|
void TC9SetOnGroupLootTypeChangedHook(OnGroupLootTypeChangedHook h) { panicWithTC9Unavailable("TC9SetOnGroupLootTypeChangedHook"); }
|
||||||
|
|
||||||
|
// TC9SetOnGroupDungeonDifficultyChangedHook sets hook for group dungeon difficulty changed event.
|
||||||
|
//
|
||||||
|
void TC9SetOnGroupDungeonDifficultyChangedHook(OnGroupDungeonDifficultyChangedHook h) { panicWithTC9Unavailable("TC9SetOnGroupDungeonDifficultyChangedHook"); }
|
||||||
|
|
||||||
|
// TC9SetOnGroupRaidDifficultyChangedHook sets hook for group raid difficulty changed event.
|
||||||
|
//
|
||||||
|
void TC9SetOnGroupRaidDifficultyChangedHook(OnGroupRaidDifficultyChangedHook h) { panicWithTC9Unavailable("TC9SetOnGroupRaidDifficultyChangedHook"); }
|
||||||
|
|
||||||
|
// TC9SetOnGroupConvertedToRaidHook sets hook for group converted to raid event.
|
||||||
|
//
|
||||||
|
void TC9SetOnGroupConvertedToRaidHook(OnGroupConvertedToRaidHook h) { panicWithTC9Unavailable("TC9SetOnGroupConvertedToRaidHook"); }
|
||||||
|
|
||||||
|
void TC9SetOnGuildMemberAddedHook(OnGuildMemberAddedHook h) { panicWithTC9Unavailable("TC9SetOnGuildMemberAddedHook"); }
|
||||||
|
|
||||||
|
// TC9SetOnGuildMemberRemovedHook sets hook for guild member removed (kicked) event.
|
||||||
|
void TC9SetOnGuildMemberRemovedHook(OnGuildMemberRemovedHook h) { panicWithTC9Unavailable("TC9SetOnGuildMemberRemovedHook"); }
|
||||||
|
|
||||||
|
// TC9SetOnGuildMemberLeftHook sets hook for guild member left event.
|
||||||
|
void TC9SetOnGuildMemberLeftHook(OnGuildMemberLeftHook h) { panicWithTC9Unavailable("TC9SetOnGuildMemberLeftHook"); }
|
||||||
|
|
||||||
|
// TC9ProcessEventsHooks calls all events hooks.
|
||||||
|
void TC9ProcessEventsHooks() { panicWithTC9Unavailable("TC9ProcessEventsHooks"); }
|
||||||
|
|
||||||
|
// TC9ProcessGRPCOrHTTPRequests calls all grpc or http handlers in queue.
|
||||||
|
//
|
||||||
|
void TC9ProcessGRPCOrHTTPRequests() { panicWithTC9Unavailable("TC9ProcessGRPCOrHTTPRequests"); }
|
||||||
|
|
||||||
|
// TC9GetNextAvailableCharacterGuid returns next available characters GUID. Thread unsafe.
|
||||||
|
uint64_t TC9GetNextAvailableCharacterGuid(int realmID) { panicWithTC9Unavailable("TC9GetNextAvailableCharacterGuid"); return 0; }
|
||||||
|
|
||||||
|
// TC9GetNextAvailableItemGuid returns next available item GUID. Thread unsafe.
|
||||||
|
uint64_t TC9GetNextAvailableItemGuid(int realmID) { panicWithTC9Unavailable("TC9GetNextAvailableItemGuid"); return 0; }
|
||||||
|
|
||||||
|
// TC9GetNextAvailableInstanceGuid returns next available dungeon/raid instance GUID. Thread unsafe.
|
||||||
|
uint64_t TC9GetNextAvailableInstanceGuid(int realmID) { panicWithTC9Unavailable("TC9GetNextAvailableInstanceGuid"); return 0; }
|
||||||
|
|
||||||
|
// TC9InitLib inits lib by starting services like grpc and healthcheck.
|
||||||
|
// Adds game server to the servers registry that will make this server visible for game load balancer.
|
||||||
|
//
|
||||||
|
void TC9InitLib(uint16_t port, uint32_t realmID, uint8_t isCrossRealm, char* availableMaps, uint32_t** assignedMaps, int* assignedMapsSize) { panicWithTC9Unavailable("TC9InitLib"); }
|
||||||
|
|
||||||
|
// TC9GracefulShutdown gracefully stops all running services.
|
||||||
|
//
|
||||||
|
void TC9GracefulShutdown() { panicWithTC9Unavailable("TC9GracefulShutdown"); }
|
||||||
|
|
||||||
|
// TC9ReadyToAcceptPlayersFromMaps notifies servers registry that this server
|
||||||
|
// loaded maps related data and ready to accept players from those maps.
|
||||||
|
//
|
||||||
|
void TC9ReadyToAcceptPlayersFromMaps(uint32_t* maps, int mapsLen) { panicWithTC9Unavailable("TC9ReadyToAcceptPlayersFromMaps"); }
|
||||||
|
|
||||||
|
// TC9SetCanPlayerInteractWithNPCAndFlagsHandler sets handler for can player interact with NPC and with given NPC flags request.
|
||||||
|
//
|
||||||
|
void TC9SetCanPlayerInteractWithNPCAndFlagsHandler(CanPlayerInteractWithNPCAndFlagsHandler h) { panicWithTC9Unavailable("TC9SetCanPlayerInteractWithNPCAndFlagsHandler"); }
|
||||||
|
|
||||||
|
// TC9SetCanPlayerInteractWithGOAndTypeHandler sets handler for can player interact with GameObject and with given object type request.
|
||||||
|
//
|
||||||
|
void TC9SetCanPlayerInteractWithGOAndTypeHandler(CanPlayerInteractWithGOAndTypeHandler h) { panicWithTC9Unavailable("TC9SetCanPlayerInteractWithGOAndTypeHandler"); }
|
||||||
|
|
||||||
|
// TC9SetGetPlayerItemsByGuidsHandler sets handler for getting players item by guids request.
|
||||||
|
void TC9SetGetPlayerItemsByGuidsHandler(GetPlayerItemsByGuidsHandler h) { panicWithTC9Unavailable("TC9SetGetPlayerItemsByGuidsHandler"); }
|
||||||
|
|
||||||
|
// TC9SetRemoveItemsWithGuidsFromPlayerHandler sets handler for removing items by guids from player request.
|
||||||
|
void TC9SetRemoveItemsWithGuidsFromPlayerHandler(RemoveItemsWithGuidsFromPlayerHandler h) { panicWithTC9Unavailable("TC9SetRemoveItemsWithGuidsFromPlayerHandler"); }
|
||||||
|
|
||||||
|
// TC9SetAddExistingItemToPlayerHandler sets handler for adding item to player request.
|
||||||
|
void TC9SetAddExistingItemToPlayerHandler(AddExistingItemToPlayerHandler h) { panicWithTC9Unavailable("TC9SetAddExistingItemToPlayerHandler"); }
|
||||||
|
|
||||||
|
// TC9SetGetMoneyForPlayerHandler sets handler for getting money for player request.
|
||||||
|
//
|
||||||
|
void TC9SetGetMoneyForPlayerHandler(GetMoneyForPlayerHandler h) { panicWithTC9Unavailable("TC9SetGetMoneyForPlayerHandler"); }
|
||||||
|
|
||||||
|
// TC9SetModifyMoneyForPlayerHandler sets handler for modify money for given player request.
|
||||||
|
//
|
||||||
|
void TC9SetModifyMoneyForPlayerHandler(ModifyMoneyForPlayerHandler h) { panicWithTC9Unavailable("TC9SetModifyMoneyForPlayerHandler"); }
|
||||||
|
|
||||||
|
|
||||||
|
// TC9SetOnMapsReassignedHook sets hook for maps reassigning by servers registry event.
|
||||||
|
//
|
||||||
|
void TC9SetOnMapsReassignedHook(OnMapsReassignedHook h) { panicWithTC9Unavailable("TC9SetOnMapsReassignedHook"); }
|
||||||
|
|
||||||
|
// TC9SetMonitoringDataCollectorHandler sets handler for getting data to handle monitoring request.
|
||||||
|
//
|
||||||
|
void TC9SetMonitoringDataCollectorHandler(MonitoringDataCollectorHandler h) { panicWithTC9Unavailable("TC9SetMonitoringDataCollectorHandler"); }
|
||||||
|
|
||||||
|
// TC9NatsPublish/Subscribe generic NATS pub/sub for in-process extensions
|
||||||
|
int TC9NatsPublish(const char* subject, const char* payload, int payloadLen) { panicWithTC9Unavailable("TC9NatsPublish"); return -1; }
|
||||||
|
int TC9NatsSubscribe(const char* subject, TC9NatsMessageHandler handler) { panicWithTC9Unavailable("TC9NatsSubscribe"); return -1; }
|
||||||
|
|
||||||
|
// TC9PlayerLeftBattleground notifies matchmaking server that player left battleground
|
||||||
|
//
|
||||||
|
void TC9PlayerLeftBattleground(uint64_t playerGUID, uint32_t realmID, uint32_t instanceID) { panicWithTC9Unavailable("TC9PlayerLeftBattleground"); }
|
||||||
|
|
||||||
|
// TC9BattlegroundStatusChanged notifies matchmaking server that battleground status changed
|
||||||
|
//
|
||||||
|
void TC9BattlegroundStatusChanged(uint32_t instanceID, uint8_t status) { panicWithTC9Unavailable("TC9BattlegroundStatusChanged"); }
|
||||||
|
|
||||||
|
// TC9SetCanPlayerJoinBattlegroundQueueHandler sets handler for checking if player can join to battleground queue.
|
||||||
|
//
|
||||||
|
void TC9SetCanPlayerJoinBattlegroundQueueHandler(CanPlayerJoinBattlegroundQueueHandler h) { panicWithTC9Unavailable("TC9SetCanPlayerJoinBattlegroundQueueHandler"); }
|
||||||
|
|
||||||
|
// TC9SetCanPlayerTeleportToBattlegroundHandler sets handler for checking if player can teleport to battleground.
|
||||||
|
//
|
||||||
|
void TC9SetCanPlayerTeleportToBattlegroundHandler(CanPlayerTeleportToBattlegroundHandler h) { panicWithTC9Unavailable("TC9SetCanPlayerTeleportToBattlegroundHandler"); }
|
||||||
Vendored
+84
@@ -0,0 +1,84 @@
|
|||||||
|
#ifndef __LIBSIDECAR_H__
|
||||||
|
#define __LIBSIDECAR_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/* Include all API headers */
|
||||||
|
#include "battleground-api.h"
|
||||||
|
#include "events-group.h"
|
||||||
|
#include "events-guild.h"
|
||||||
|
#include "events-servers-registry.h"
|
||||||
|
#include "monitoring.h"
|
||||||
|
#include "player-interactions-api.h"
|
||||||
|
#include "player-items-api.h"
|
||||||
|
#include "player-money-api.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Main library functions */
|
||||||
|
void TC9InitLib(uint16_t port, uint32_t realmID, uint8_t isCrossRealm, char* availableMaps, uint32_t** assignedMaps, int* assignedMapsSize);
|
||||||
|
void TC9GracefulShutdown();
|
||||||
|
void TC9ProcessGRPCOrHTTPRequests();
|
||||||
|
void TC9ProcessEventsHooks();
|
||||||
|
|
||||||
|
/* GUID generation */
|
||||||
|
uint64_t TC9GetNextAvailableCharacterGuid(int realmID);
|
||||||
|
uint64_t TC9GetNextAvailableItemGuid(int realmID);
|
||||||
|
uint64_t TC9GetNextAvailableInstanceGuid(int realmID);
|
||||||
|
|
||||||
|
/* Map loading notification */
|
||||||
|
void TC9ReadyToAcceptPlayersFromMaps(uint32_t* maps, int mapsLen);
|
||||||
|
|
||||||
|
/* Generic NATS pub/sub for in-process extensions. Subscribe callbacks run
|
||||||
|
* on the thread that calls TC9ProcessEventsHooks. Call after TC9InitLib.
|
||||||
|
* Both return 0 on success, -1 on error. */
|
||||||
|
typedef void (*TC9NatsMessageHandler)(const char* subject, const char* payload, int payloadLen);
|
||||||
|
int TC9NatsPublish(const char* subject, const char* payload, int payloadLen);
|
||||||
|
int TC9NatsSubscribe(const char* subject, TC9NatsMessageHandler handler);
|
||||||
|
|
||||||
|
/* Matchmaking notifications */
|
||||||
|
void TC9PlayerLeftBattleground(uint64_t playerGUID, uint32_t realmID, uint32_t instanceID);
|
||||||
|
void TC9BattlegroundStatusChanged(uint32_t instanceID, uint8_t status);
|
||||||
|
|
||||||
|
/* Event hooks registration */
|
||||||
|
void TC9SetOnGroupCreatedHook(OnGroupCreatedHook h);
|
||||||
|
void TC9SetOnGroupMemberAddedHook(OnGroupMemberAddedHook h);
|
||||||
|
void TC9SetOnGroupMemberRemovedHook(OnGroupMemberRemovedHook h);
|
||||||
|
void TC9SetOnGroupDisbandedHook(OnGroupDisbandedHook h);
|
||||||
|
void TC9SetOnGroupLootTypeChangedHook(OnGroupLootTypeChangedHook h);
|
||||||
|
void TC9SetOnGroupDungeonDifficultyChangedHook(OnGroupDungeonDifficultyChangedHook h);
|
||||||
|
void TC9SetOnGroupRaidDifficultyChangedHook(OnGroupRaidDifficultyChangedHook h);
|
||||||
|
void TC9SetOnGroupConvertedToRaidHook(OnGroupConvertedToRaidHook h);
|
||||||
|
|
||||||
|
void TC9SetOnGuildMemberAddedHook(OnGuildMemberAddedHook h);
|
||||||
|
void TC9SetOnGuildMemberRemovedHook(OnGuildMemberRemovedHook h);
|
||||||
|
void TC9SetOnGuildMemberLeftHook(OnGuildMemberLeftHook h);
|
||||||
|
|
||||||
|
void TC9SetOnMapsReassignedHook(OnMapsReassignedHook h);
|
||||||
|
|
||||||
|
/* Handler registration for gRPC requests */
|
||||||
|
void TC9SetBattlegroundStartHandler(BattlegroundStartHandler h);
|
||||||
|
void TC9SetBattlegroundAddPlayersHandler(BattlegroundAddPlayersHandler h);
|
||||||
|
void TC9SetCanPlayerJoinBattlegroundQueueHandler(CanPlayerJoinBattlegroundQueueHandler h);
|
||||||
|
void TC9SetCanPlayerTeleportToBattlegroundHandler(CanPlayerTeleportToBattlegroundHandler h);
|
||||||
|
|
||||||
|
void TC9SetMonitoringDataCollectorHandler(MonitoringDataCollectorHandler h);
|
||||||
|
|
||||||
|
void TC9SetCanPlayerInteractWithNPCAndFlagsHandler(CanPlayerInteractWithNPCAndFlagsHandler h);
|
||||||
|
void TC9SetCanPlayerInteractWithGOAndTypeHandler(CanPlayerInteractWithGOAndTypeHandler h);
|
||||||
|
|
||||||
|
void TC9SetGetPlayerItemsByGuidsHandler(GetPlayerItemsByGuidsHandler h);
|
||||||
|
void TC9SetRemoveItemsWithGuidsFromPlayerHandler(RemoveItemsWithGuidsFromPlayerHandler h);
|
||||||
|
void TC9SetAddExistingItemToPlayerHandler(AddExistingItemToPlayerHandler h);
|
||||||
|
|
||||||
|
void TC9SetGetMoneyForPlayerHandler(GetMoneyForPlayerHandler h);
|
||||||
|
void TC9SetModifyMoneyForPlayerHandler(ModifyMoneyForPlayerHandler h);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __LIBSIDECAR_H__ */
|
||||||
Vendored
+16
@@ -0,0 +1,16 @@
|
|||||||
|
#include "monitoring.h"
|
||||||
|
|
||||||
|
static MonitoringDataCollectorHandler monitoringDataCollectorHandler;
|
||||||
|
void SetMonitoringDataCollectorHandler(MonitoringDataCollectorHandler h) {
|
||||||
|
monitoringDataCollectorHandler = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
MonitoringDataCollectorResponse CallMonitoringDataCollectorHandler() {
|
||||||
|
if (monitoringDataCollectorHandler == 0) {
|
||||||
|
MonitoringDataCollectorResponse resp;
|
||||||
|
resp.errorCode = MonitoringErrorCodeNoHandler;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return monitoringDataCollectorHandler();
|
||||||
|
}
|
||||||
Vendored
+28
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef __MONITORING__
|
||||||
|
#define __MONITORING__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef enum MonitoringErrorCode {
|
||||||
|
MonitoringErrorCodeNoError = 0,
|
||||||
|
MonitoringErrorCodeNoHandler = 1,
|
||||||
|
} MonitoringErrorCode;
|
||||||
|
|
||||||
|
// MonitoringDataCollectorResponse request.
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
uint32_t connectedPlayers;
|
||||||
|
uint32_t diffMean;
|
||||||
|
uint32_t diffMedian;
|
||||||
|
uint32_t diff95Percentile;
|
||||||
|
uint32_t diff99Percentile;
|
||||||
|
uint32_t diffMaxPercentile;
|
||||||
|
} MonitoringDataCollectorResponse;
|
||||||
|
|
||||||
|
typedef MonitoringDataCollectorResponse (*MonitoringDataCollectorHandler)();
|
||||||
|
void SetMonitoringDataCollectorHandler(MonitoringDataCollectorHandler h);
|
||||||
|
MonitoringDataCollectorResponse CallMonitoringDataCollectorHandler();
|
||||||
|
|
||||||
|
#endif
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
#include "player-interactions-api.h"
|
||||||
|
|
||||||
|
static CanPlayerInteractWithNPCAndFlagsHandler canPlayerInteractWithNPCAndFlagsHandler;
|
||||||
|
void SetCanPlayerInteractWithNPCAndFlagsHandler(CanPlayerInteractWithNPCAndFlagsHandler h) {
|
||||||
|
canPlayerInteractWithNPCAndFlagsHandler = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
CanPlayerInteractWithNPCAndFlagsResponse CallCanPlayerInteractWithNPCAndFlagsHandler(uint64_t player_guid, uint64_t npc_guid, uint32_t npc_flags) {
|
||||||
|
if (canPlayerInteractWithNPCAndFlagsHandler == 0) {
|
||||||
|
CanPlayerInteractWithNPCAndFlagsResponse resp;
|
||||||
|
resp.errorCode = PlayerInteractionErrorCodeNoHandler;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return canPlayerInteractWithNPCAndFlagsHandler(player_guid, npc_guid, npc_flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static CanPlayerInteractWithGOAndTypeHandler canPlayerInteractWithGOAndTypeHandler;
|
||||||
|
void SetCanPlayerInteractWithGOAndTypeHandler(CanPlayerInteractWithGOAndTypeHandler h) {
|
||||||
|
canPlayerInteractWithGOAndTypeHandler = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
CanPlayerInteractWithGOAndTypeResponse CallCanPlayerInteractWithGOAndTypeHandler(uint64_t player_guid, uint64_t go_guid, uint8_t go_type) {
|
||||||
|
if (canPlayerInteractWithGOAndTypeHandler == 0) {
|
||||||
|
CanPlayerInteractWithGOAndTypeResponse resp;
|
||||||
|
resp.errorCode = PlayerInteractionErrorCodeNoHandler;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return canPlayerInteractWithGOAndTypeHandler(player_guid, go_guid, go_type);
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
#ifndef __PLAYER_INTERACTIONS_API__
|
||||||
|
#define __PLAYER_INTERACTIONS_API__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef enum PlayerInteractionErrorCode {
|
||||||
|
PlayerInteractionErrorCodeNoError = 0,
|
||||||
|
PlayerInteractionErrorCodeNoHandler = 1,
|
||||||
|
PlayerInteractionErrorCodeCodePlayerNotFound = 2,
|
||||||
|
} PlayerInteractionErrorCode;
|
||||||
|
|
||||||
|
// CanPlayerInteractWithNPCAndFlags request.
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
bool canInteract;
|
||||||
|
} CanPlayerInteractWithNPCAndFlagsResponse;
|
||||||
|
|
||||||
|
typedef CanPlayerInteractWithNPCAndFlagsResponse (*CanPlayerInteractWithNPCAndFlagsHandler) (uint64_t /*playerGUID*/, uint64_t /*npcGUID*/, uint32_t /*npcFlags*/);
|
||||||
|
void SetCanPlayerInteractWithNPCAndFlagsHandler(CanPlayerInteractWithNPCAndFlagsHandler h);
|
||||||
|
CanPlayerInteractWithNPCAndFlagsResponse CallCanPlayerInteractWithNPCAndFlagsHandler(uint64_t player_guid, uint64_t npc_guid, uint32_t npc_flags);
|
||||||
|
|
||||||
|
// CanPlayerInteractWithGOAndType request.
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
bool canInteract;
|
||||||
|
} CanPlayerInteractWithGOAndTypeResponse;
|
||||||
|
|
||||||
|
typedef CanPlayerInteractWithGOAndTypeResponse (*CanPlayerInteractWithGOAndTypeHandler) (uint64_t /*playerGUID*/, uint64_t /*goGUID*/, uint8_t /*goType*/);
|
||||||
|
void SetCanPlayerInteractWithGOAndTypeHandler(CanPlayerInteractWithGOAndTypeHandler h);
|
||||||
|
CanPlayerInteractWithGOAndTypeResponse CallCanPlayerInteractWithGOAndTypeHandler(uint64_t player_guid, uint64_t go_guid, uint8_t go_type);
|
||||||
|
|
||||||
|
#endif
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
#include "player-items-api.h"
|
||||||
|
|
||||||
|
static GetPlayerItemsByGuidsHandler getPlayerItemsByGuidsHandler;
|
||||||
|
void SetGetPlayerItemsByGuidsHandler(GetPlayerItemsByGuidsHandler h) {
|
||||||
|
getPlayerItemsByGuidsHandler = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetPlayerItemsByGuidsResponse CallGetPlayerItemsByGuidsHandler(uint64_t player_guid, uint64_t* items_guids, int items_guids_size) {
|
||||||
|
if (getPlayerItemsByGuidsHandler == 0) {
|
||||||
|
GetPlayerItemsByGuidsResponse resp;
|
||||||
|
resp.errorCode = PlayerItemErrorCodeNoHandler;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getPlayerItemsByGuidsHandler(player_guid, items_guids, items_guids_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static RemoveItemsWithGuidsFromPlayerHandler removeItemsWithGuidsFromPlayerHandler;
|
||||||
|
void SetRemoveItemsWithGuidsFromPlayerHandler(RemoveItemsWithGuidsFromPlayerHandler h) {
|
||||||
|
removeItemsWithGuidsFromPlayerHandler = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveItemsWithGuidsFromPlayerResponse CallRemoveItemsWithGuidsFromPlayerHandler(uint64_t player_guid, uint64_t* items_guids, int items_guids_size, uint64_t assign_player_guid) {
|
||||||
|
if (removeItemsWithGuidsFromPlayerHandler == 0) {
|
||||||
|
RemoveItemsWithGuidsFromPlayerResponse resp;
|
||||||
|
resp.errorCode = PlayerItemErrorCodeNoHandler;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return removeItemsWithGuidsFromPlayerHandler(player_guid, items_guids, items_guids_size, assign_player_guid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AddExistingItemToPlayerHandler addExistingItemToPlayerHandler;
|
||||||
|
void SetAddExistingItemToPlayerHandler(AddExistingItemToPlayerHandler h) {
|
||||||
|
addExistingItemToPlayerHandler = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerItemErrorCode CallAddExistingItemToPlayerHandler(AddExistingItemToPlayerRequest *r) {
|
||||||
|
if (addExistingItemToPlayerHandler == 0) {
|
||||||
|
return PlayerItemErrorCodeNoHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
return addExistingItemToPlayerHandler(r);
|
||||||
|
}
|
||||||
+68
@@ -0,0 +1,68 @@
|
|||||||
|
#ifndef __PLAYER_ITEMS_API__
|
||||||
|
#define __PLAYER_ITEMS_API__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef enum PlayerItemErrorCode {
|
||||||
|
PlayerItemErrorCodeNoError = 0,
|
||||||
|
PlayerItemErrorCodeNoHandler = 1,
|
||||||
|
PlayerItemErrorCodePlayerNotFound = 2,
|
||||||
|
PlayerItemErrorNoInventorySpace = 3,
|
||||||
|
PlayerItemErrorUnknownTemplate = 4,
|
||||||
|
PlayerItemErrorFailedToCreateItem = 5
|
||||||
|
} PlayerItemErrorCode;
|
||||||
|
|
||||||
|
// GetPlayerItemsByGuids request.
|
||||||
|
typedef struct {
|
||||||
|
uint64_t guid;
|
||||||
|
uint32_t entry;
|
||||||
|
uint64_t owner;
|
||||||
|
uint8_t bagSlot;
|
||||||
|
uint8_t slot;
|
||||||
|
bool isTradable;
|
||||||
|
uint32_t count;
|
||||||
|
uint16_t flags;
|
||||||
|
uint8_t durability;
|
||||||
|
int8_t randomPropertyID;
|
||||||
|
const char* text;
|
||||||
|
} PlayerItem;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
PlayerItem* items;
|
||||||
|
int itemsSize;
|
||||||
|
} GetPlayerItemsByGuidsResponse;
|
||||||
|
|
||||||
|
typedef GetPlayerItemsByGuidsResponse (*GetPlayerItemsByGuidsHandler) (uint64_t /*player_guid*/, uint64_t* /*items_guids*/, int /*items_guids_size*/);
|
||||||
|
void SetGetPlayerItemsByGuidsHandler(GetPlayerItemsByGuidsHandler h);
|
||||||
|
GetPlayerItemsByGuidsResponse CallGetPlayerItemsByGuidsHandler(uint64_t player_guid, uint64_t* items_guids, int items_guids_size);
|
||||||
|
|
||||||
|
// RemoveItemsWithGuidsFromPlayer request.
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
uint64_t* updatedItems;
|
||||||
|
int updatedItemsSize;
|
||||||
|
} RemoveItemsWithGuidsFromPlayerResponse;
|
||||||
|
|
||||||
|
typedef RemoveItemsWithGuidsFromPlayerResponse (*RemoveItemsWithGuidsFromPlayerHandler) (uint64_t /*player_guid*/, uint64_t* /*items_guids*/, int /*items_guids_size*/, uint64_t /*assign_player_guid*/);
|
||||||
|
void SetRemoveItemsWithGuidsFromPlayerHandler(RemoveItemsWithGuidsFromPlayerHandler h);
|
||||||
|
RemoveItemsWithGuidsFromPlayerResponse CallRemoveItemsWithGuidsFromPlayerHandler(uint64_t player_guid, uint64_t* items_guids, int items_guids_size, uint64_t assign_player_guid);
|
||||||
|
|
||||||
|
// AddExistingItemToPlayer request.
|
||||||
|
typedef struct {
|
||||||
|
uint64_t playerGuid;
|
||||||
|
uint64_t itemGuid;
|
||||||
|
uint32_t itemEntry;
|
||||||
|
uint32_t itemCount;
|
||||||
|
uint16_t itemFlags;
|
||||||
|
uint8_t itemDurability;
|
||||||
|
int8_t itemRandomPropertyID;
|
||||||
|
} AddExistingItemToPlayerRequest;
|
||||||
|
|
||||||
|
typedef PlayerItemErrorCode (*AddExistingItemToPlayerHandler) (AddExistingItemToPlayerRequest*);
|
||||||
|
void SetAddExistingItemToPlayerHandler(AddExistingItemToPlayerHandler h);
|
||||||
|
PlayerItemErrorCode CallAddExistingItemToPlayerHandler(AddExistingItemToPlayerRequest*);
|
||||||
|
|
||||||
|
#endif
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
#include "player-money-api.h"
|
||||||
|
|
||||||
|
static GetMoneyForPlayerHandler getMoneyForPlayerHandler;
|
||||||
|
void SetGetMoneyForPlayerHandler(GetMoneyForPlayerHandler h) {
|
||||||
|
getMoneyForPlayerHandler = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetMoneyForPlayerResponse CallGetMoneyForPlayerHandler(uint64_t player_guid) {
|
||||||
|
if (getMoneyForPlayerHandler == 0) {
|
||||||
|
GetMoneyForPlayerResponse resp;
|
||||||
|
resp.errorCode = PlayerMoneyErrorCodeNoHandler;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getMoneyForPlayerHandler(player_guid);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ModifyMoneyForPlayerHandler modifyMoneyForPlayerHandler;
|
||||||
|
void SetModifyMoneyForPlayerHandler(ModifyMoneyForPlayerHandler h) {
|
||||||
|
modifyMoneyForPlayerHandler = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModifyMoneyForPlayerResponse CallModifyMoneyForPlayerHandler(uint64_t player_guid, int32_t amount) {
|
||||||
|
if (modifyMoneyForPlayerHandler == 0) {
|
||||||
|
ModifyMoneyForPlayerResponse resp;
|
||||||
|
resp.errorCode = PlayerMoneyErrorCodeNoHandler;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return modifyMoneyForPlayerHandler(player_guid, amount);
|
||||||
|
}
|
||||||
+35
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef __PLAYER_MONEY_API__
|
||||||
|
#define __PLAYER_MONEY_API__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
typedef enum PlayerMoneyErrorCode {
|
||||||
|
PlayerMoneyErrorCodeNoError = 0,
|
||||||
|
PlayerMoneyErrorCodeNoHandler = 1,
|
||||||
|
PlayerMoneyErrorCodePlayerNotFound = 2,
|
||||||
|
PlayerMoneyErrorCodeTooMuchMoney = 3,
|
||||||
|
} PlayerMoneyErrorCode;
|
||||||
|
|
||||||
|
// GetMoneyForPlayer request.
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
uint32_t money;
|
||||||
|
} GetMoneyForPlayerResponse;
|
||||||
|
|
||||||
|
typedef GetMoneyForPlayerResponse (*GetMoneyForPlayerHandler) (uint64_t /*player_guid*/);
|
||||||
|
void SetGetMoneyForPlayerHandler(GetMoneyForPlayerHandler h);
|
||||||
|
GetMoneyForPlayerResponse CallGetMoneyForPlayerHandler(uint64_t player_guid);
|
||||||
|
|
||||||
|
// ModifyMoneyForPlayer request.
|
||||||
|
typedef struct {
|
||||||
|
int errorCode;
|
||||||
|
uint32_t newMoneyValue;
|
||||||
|
} ModifyMoneyForPlayerResponse;
|
||||||
|
|
||||||
|
typedef ModifyMoneyForPlayerResponse (*ModifyMoneyForPlayerHandler) (uint64_t /*player_guid*/, int32_t /*amount*/);
|
||||||
|
void SetModifyMoneyForPlayerHandler(ModifyMoneyForPlayerHandler h);
|
||||||
|
ModifyMoneyForPlayerResponse CallModifyMoneyForPlayerHandler(uint64_t player_guid, int32_t amount);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -121,6 +121,12 @@ else()
|
|||||||
message("* Use GIT revision hash : Yes (default)")
|
message("* Use GIT revision hash : Yes (default)")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if ( USE_REAL_LIBSIDECAR )
|
||||||
|
message("* Use stub for libsidecar : No")
|
||||||
|
else()
|
||||||
|
message("* Use stub for libsidecar : Yes")
|
||||||
|
endif()
|
||||||
|
|
||||||
if ( NOJEM )
|
if ( NOJEM )
|
||||||
message("")
|
message("")
|
||||||
message(" *** NOJEM - WARNING!")
|
message(" *** NOJEM - WARNING!")
|
||||||
|
|||||||
@@ -139,7 +139,8 @@ foreach(APPLICATION_NAME ${APPLICATIONS_BUILD_LIST})
|
|||||||
game
|
game
|
||||||
gsoap
|
gsoap
|
||||||
readline
|
readline
|
||||||
gperftools)
|
gperftools
|
||||||
|
libsidecar)
|
||||||
|
|
||||||
if (UNIX AND NOT NOJEM)
|
if (UNIX AND NOT NOJEM)
|
||||||
set(${APP_PROJECT_NAME}_LINK_FLAGS "-pthread -lncurses ${${APP_PROJECT_NAME}_LINK_FLAGS}")
|
set(${APP_PROJECT_NAME}_LINK_FLAGS "-pthread -lncurses ${${APP_PROJECT_NAME}_LINK_FLAGS}")
|
||||||
|
|||||||
@@ -49,10 +49,12 @@
|
|||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
#include "SteadyTimer.h"
|
#include "SteadyTimer.h"
|
||||||
#include "Systemd.h"
|
#include "Systemd.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
#include "WorldSessionMgr.h"
|
#include "WorldSessionMgr.h"
|
||||||
#include "WorldSocket.h"
|
#include "WorldSocket.h"
|
||||||
#include "WorldSocketMgr.h"
|
#include "WorldSocketMgr.h"
|
||||||
|
#include "libsidecar.h"
|
||||||
#include <boost/asio/signal_set.hpp>
|
#include <boost/asio/signal_set.hpp>
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
@@ -365,6 +367,7 @@ int main(int argc, char** argv)
|
|||||||
sWorldSocketMgr.StopNetwork();
|
sWorldSocketMgr.StopNetwork();
|
||||||
|
|
||||||
///- Clean database before leaving
|
///- Clean database before leaving
|
||||||
|
if (!sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
ClearOnlineAccounts();
|
ClearOnlineAccounts();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -397,11 +400,15 @@ int main(int argc, char** argv)
|
|||||||
cliThread.reset(new std::thread(CliThread), &ShutdownCLIThread);
|
cliThread.reset(new std::thread(CliThread), &ShutdownCLIThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sToCloud9Sidecar->Init(worldPort, realm.Id.Realm);
|
||||||
|
|
||||||
WorldUpdateLoop();
|
WorldUpdateLoop();
|
||||||
|
|
||||||
// Shutdown starts here
|
// Shutdown starts here
|
||||||
threadPool.reset();
|
threadPool.reset();
|
||||||
|
|
||||||
|
sToCloud9Sidecar->Deinit();
|
||||||
|
|
||||||
sLog->SetSynchronous();
|
sLog->SetSynchronous();
|
||||||
|
|
||||||
sScriptMgr->OnShutdown();
|
sScriptMgr->OnShutdown();
|
||||||
@@ -455,7 +462,10 @@ bool StartDB()
|
|||||||
LOG_INFO("server.loading", "Loading World Information...");
|
LOG_INFO("server.loading", "Loading World Information...");
|
||||||
LOG_INFO("server.loading", "> RealmID: {}", realm.Id.Realm);
|
LOG_INFO("server.loading", "> RealmID: {}", realm.Id.Realm);
|
||||||
|
|
||||||
///- Clean the database before starting
|
///- Clean the database before starting.
|
||||||
|
/// Cluster.Enabled is read from config here because sToCloud9Sidecar->Init()
|
||||||
|
/// has not run yet; ClusterModeEnabled() would still be the default false.
|
||||||
|
if (!sConfigMgr->GetOption<bool>("Cluster.Enabled", false))
|
||||||
ClearOnlineAccounts();
|
ClearOnlineAccounts();
|
||||||
|
|
||||||
///- Insert version info into DB
|
///- Insert version info into DB
|
||||||
|
|||||||
@@ -72,6 +72,8 @@
|
|||||||
# DEBUG
|
# DEBUG
|
||||||
# DYNAMIC RESPAWN SETTINGS
|
# DYNAMIC RESPAWN SETTINGS
|
||||||
#
|
#
|
||||||
|
# CLUSTER SETTINGS
|
||||||
|
#
|
||||||
###################################################################################################
|
###################################################################################################
|
||||||
|
|
||||||
###################################################################################################
|
###################################################################################################
|
||||||
@@ -4893,3 +4895,56 @@ Respawn.ForceCompatibilityMode = 0
|
|||||||
# GAME SETTINGS END #
|
# GAME SETTINGS END #
|
||||||
# #
|
# #
|
||||||
###################################################################################################
|
###################################################################################################
|
||||||
|
|
||||||
|
###################################################################################################
|
||||||
|
# #
|
||||||
|
# CLUSTER SETTINGS BEGIN #
|
||||||
|
# #
|
||||||
|
###################################################################################################
|
||||||
|
|
||||||
|
###################################################################################################
|
||||||
|
# CLUSTER SETTINGS
|
||||||
|
#
|
||||||
|
# This feature is experimental and still under development. It enables cluster mode, allowing multiple
|
||||||
|
# worldservers to run for a single realm, distributing the load between them. Alongside worldservers,
|
||||||
|
# additional services are required for proper functionality. If you encounter any issues, please report
|
||||||
|
# them to the ToCloud9 project: https://github.com/walkline/ToCloud9.
|
||||||
|
#
|
||||||
|
# Cluster.Enabled
|
||||||
|
# Description: Enables/disables cluster mode.
|
||||||
|
# SECURITY: in cluster mode the ToCloud9 gateway is the trusted
|
||||||
|
# authentication boundary. This worldserver then skips session-key
|
||||||
|
# digest verification, packet encryption, warden, IP/country locks,
|
||||||
|
# ban and minimum-security-level enforcement, and the
|
||||||
|
# character-ownership check on login. The worldserver port must
|
||||||
|
# only be reachable by the gateway, never directly by players.
|
||||||
|
# Default: 0 - (Disabled)
|
||||||
|
# 1 - (Enabled)
|
||||||
|
|
||||||
|
Cluster.Enabled=0
|
||||||
|
|
||||||
|
#
|
||||||
|
# Cluster.AvailableMaps
|
||||||
|
# Description: List of available maps id on this server.
|
||||||
|
# Examples: "" - (Can handle any map)
|
||||||
|
# "0,1,573"
|
||||||
|
|
||||||
|
Cluster.AvailableMaps=""
|
||||||
|
|
||||||
|
#
|
||||||
|
# Cluster.IsCrossrealm
|
||||||
|
# Description: Enables cross-realm functionality for a cross-realm setup.
|
||||||
|
# When enabled, a connection to a MySQL cross-realm reverse proxy is required.
|
||||||
|
# Default: 0 - (Disabled)
|
||||||
|
# 1 - (Enabled)
|
||||||
|
|
||||||
|
Cluster.IsCrossrealm=0
|
||||||
|
|
||||||
|
#
|
||||||
|
###################################################################################################
|
||||||
|
|
||||||
|
###################################################################################################
|
||||||
|
# #
|
||||||
|
# CLUSTER SETTINGS END #
|
||||||
|
# #
|
||||||
|
###################################################################################################
|
||||||
|
|||||||
@@ -634,6 +634,13 @@ void CharacterDatabaseConnection::DoPrepareStatements()
|
|||||||
// world_state
|
// world_state
|
||||||
PrepareStatement(CHAR_SEL_WORLD_STATE, "SELECT Id, Data FROM world_state", CONNECTION_SYNCH);
|
PrepareStatement(CHAR_SEL_WORLD_STATE, "SELECT Id, Data FROM world_state", CONNECTION_SYNCH);
|
||||||
PrepareStatement(CHAR_REP_WORLD_STATE, "REPLACE INTO world_state (Id, Data) VALUES(?, ?)", CONNECTION_ASYNC);
|
PrepareStatement(CHAR_REP_WORLD_STATE, "REPLACE INTO world_state (Id, Data) VALUES(?, ?)", CONNECTION_ASYNC);
|
||||||
|
|
||||||
|
// CHAR_NO_OP_PROVIDE_REALM_CONTEXT is a no-op query that accepts a single parameter: the realm ID.
|
||||||
|
// This query is used specifically in cross-realm scenarios when the database transaction
|
||||||
|
// lacks sufficient context to determine which realm's database the query should target.
|
||||||
|
// By providing the realm ID explicitly, this ensures that mysql reverse proxy will use
|
||||||
|
// correct realm database for the transaction.
|
||||||
|
PrepareStatement(CHAR_NO_OP_PROVIDE_REALM_CONTEXT, "SELECT ? AS no_op", CONNECTION_ASYNC);
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterDatabaseConnection::CharacterDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo)
|
CharacterDatabaseConnection::CharacterDatabaseConnection(MySQLConnectionInfo& connInfo) : MySQLConnection(connInfo)
|
||||||
|
|||||||
@@ -543,6 +543,8 @@ enum CharacterDatabaseStatements : uint32
|
|||||||
CHAR_SEL_WORLD_STATE,
|
CHAR_SEL_WORLD_STATE,
|
||||||
CHAR_REP_WORLD_STATE,
|
CHAR_REP_WORLD_STATE,
|
||||||
|
|
||||||
|
CHAR_NO_OP_PROVIDE_REALM_CONTEXT,
|
||||||
|
|
||||||
MAX_CHARACTERDATABASE_STATEMENTS
|
MAX_CHARACTERDATABASE_STATEMENTS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,12 @@
|
|||||||
#include "ObjectMgr.h"
|
#include "ObjectMgr.h"
|
||||||
#include "Pet.h"
|
#include "Pet.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
|
#include "Realm.h"
|
||||||
#include "RBAC.h"
|
#include "RBAC.h"
|
||||||
#include "ReputationMgr.h"
|
#include "ReputationMgr.h"
|
||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
#include "SpellAuras.h"
|
#include "SpellAuras.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "Transport.h"
|
#include "Transport.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
@@ -277,6 +279,12 @@ void Battleground::Update(uint32 diff)
|
|||||||
if (!GetInvitedCount(TEAM_HORDE) && !GetInvitedCount(TEAM_ALLIANCE))
|
if (!GetInvitedCount(TEAM_HORDE) && !GetInvitedCount(TEAM_ALLIANCE))
|
||||||
{
|
{
|
||||||
m_SetDeleteThis = true;
|
m_SetDeleteThis = true;
|
||||||
|
|
||||||
|
// Only needed for the sidecar notify inside SetStatus; queue and
|
||||||
|
// spectator code read the status within this manager pass, so do
|
||||||
|
// not change it on non-cluster servers.
|
||||||
|
if (sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
|
SetStatus(STATUS_WAIT_LEAVE);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -1071,6 +1079,11 @@ void Battleground::RemovePlayerAtLeave(Player* player)
|
|||||||
// if the player was a match participant
|
// if the player was a match participant
|
||||||
if (participant)
|
if (participant)
|
||||||
{
|
{
|
||||||
|
if (sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
|
sToCloud9Sidecar->OnPlayerLeftBattleground(player->GetGUID().GetCounter(),
|
||||||
|
player->GetGUID().GetRealmID(),
|
||||||
|
GetInstanceID());
|
||||||
|
|
||||||
player->ClearAfkReports();
|
player->ClearAfkReports();
|
||||||
|
|
||||||
WorldPacket data;
|
WorldPacket data;
|
||||||
@@ -1889,3 +1902,11 @@ uint8 Battleground::GetUniqueBracketId() const
|
|||||||
{
|
{
|
||||||
return GetMaxLevel() / 10;
|
return GetMaxLevel() / 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Battleground::SetStatus(BattlegroundStatus Status)
|
||||||
|
{
|
||||||
|
m_Status = Status;
|
||||||
|
|
||||||
|
if (sToCloud9Sidecar->ClusterModeEnabled() && GetInstanceID() != 0)
|
||||||
|
sToCloud9Sidecar->OnBattlegroundStatusChanged(GetInstanceID(), Status);
|
||||||
|
}
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ public:
|
|||||||
void SetRandomTypeID(BattlegroundTypeId TypeID) { m_RandomTypeID = TypeID; }
|
void SetRandomTypeID(BattlegroundTypeId TypeID) { m_RandomTypeID = TypeID; }
|
||||||
void SetBracket(PvPDifficultyEntry const* bracketEntry);
|
void SetBracket(PvPDifficultyEntry const* bracketEntry);
|
||||||
void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; }
|
void SetInstanceID(uint32 InstanceID) { m_InstanceID = InstanceID; }
|
||||||
void SetStatus(BattlegroundStatus Status) { m_Status = Status; }
|
void SetStatus(BattlegroundStatus Status);
|
||||||
void SetClientInstanceID(uint32 InstanceID) { m_ClientInstanceID = InstanceID; }
|
void SetClientInstanceID(uint32 InstanceID) { m_ClientInstanceID = InstanceID; }
|
||||||
void SetStartTime(uint32 Time) { m_StartTime = Time; }
|
void SetStartTime(uint32 Time) { m_StartTime = Time; }
|
||||||
void SetEndTime(uint32 Time) { m_EndTime = Time; }
|
void SetEndTime(uint32 Time) { m_EndTime = Time; }
|
||||||
|
|||||||
@@ -54,7 +54,8 @@ target_link_libraries(game
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
acore-core-interface
|
acore-core-interface
|
||||||
PUBLIC
|
PUBLIC
|
||||||
game-interface)
|
game-interface
|
||||||
|
libsidecar)
|
||||||
|
|
||||||
set_target_properties(game
|
set_target_properties(game
|
||||||
PROPERTIES
|
PROPERTIES
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "SpellInfo.h"
|
#include "SpellInfo.h"
|
||||||
#include "SpellMgr.h"
|
#include "SpellMgr.h"
|
||||||
#include "StringConvert.h"
|
#include "StringConvert.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "Tokenize.h"
|
#include "Tokenize.h"
|
||||||
#include "WorldPacket.h"
|
#include "WorldPacket.h"
|
||||||
|
|
||||||
@@ -348,7 +349,7 @@ void Item::SaveToDB(CharacterDatabaseTransaction trans)
|
|||||||
uint8 index = 0;
|
uint8 index = 0;
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(uState == ITEM_NEW ? CHAR_REP_ITEM_INSTANCE : CHAR_UPD_ITEM_INSTANCE);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(uState == ITEM_NEW ? CHAR_REP_ITEM_INSTANCE : CHAR_UPD_ITEM_INSTANCE);
|
||||||
stmt->SetData( index, GetEntry());
|
stmt->SetData( index, GetEntry());
|
||||||
stmt->SetData(++index, GetOwnerGUID().GetCounter());
|
stmt->SetData(++index, GetOwnerGUID().GetRawValue());
|
||||||
stmt->SetData(++index, GetGuidValue(ITEM_FIELD_CREATOR).GetCounter());
|
stmt->SetData(++index, GetGuidValue(ITEM_FIELD_CREATOR).GetCounter());
|
||||||
stmt->SetData(++index, GetGuidValue(ITEM_FIELD_GIFTCREATOR).GetCounter());
|
stmt->SetData(++index, GetGuidValue(ITEM_FIELD_GIFTCREATOR).GetCounter());
|
||||||
stmt->SetData(++index, GetCount());
|
stmt->SetData(++index, GetCount());
|
||||||
@@ -381,7 +382,7 @@ void Item::SaveToDB(CharacterDatabaseTransaction trans)
|
|||||||
if ((uState == ITEM_CHANGED) && IsWrapped())
|
if ((uState == ITEM_CHANGED) && IsWrapped())
|
||||||
{
|
{
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GIFT_OWNER);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GIFT_OWNER);
|
||||||
stmt->SetData(0, GetOwnerGUID().GetCounter());
|
stmt->SetData(0, GetOwnerGUID().GetRawValue());
|
||||||
stmt->SetData(1, guid);
|
stmt->SetData(1, guid);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
@@ -1096,29 +1097,32 @@ Item* Item::CreateItem(uint32 item, uint32 count, Player const* player, bool clo
|
|||||||
return nullptr; //don't create item at zero count
|
return nullptr; //don't create item at zero count
|
||||||
|
|
||||||
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item);
|
ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(item);
|
||||||
if (pProto)
|
if (!pProto)
|
||||||
{
|
ABORT();
|
||||||
|
|
||||||
if (count > pProto->GetMaxStackSize())
|
if (count > pProto->GetMaxStackSize())
|
||||||
count = pProto->GetMaxStackSize();
|
count = pProto->GetMaxStackSize();
|
||||||
|
|
||||||
ASSERT_NODEBUGINFO(count != 0 && "pProto->Stackable == 0 but checked at loading already");
|
ASSERT_NODEBUGINFO(count != 0 && "pProto->Stackable == 0 but checked at loading already");
|
||||||
|
|
||||||
|
uint16 realmId = DEFAULT_NON_CROSSREALM_REALM_ID;
|
||||||
|
if (sToCloud9Sidecar->IsCrossrealm() && player)
|
||||||
|
realmId = player->GetGUID().GetRealmID();
|
||||||
|
|
||||||
Item* pItem = NewItemOrBag(pProto);
|
Item* pItem = NewItemOrBag(pProto);
|
||||||
if (pItem->Create(sObjectMgr->GetGenerator<HighGuid::Item>().Generate(), item, player))
|
if (!pItem->Create(sObjectMgr->GetGenerator<HighGuid::Item>().Generate(realmId), item, player))
|
||||||
{
|
{
|
||||||
|
delete pItem;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
pItem->SetCount(count);
|
pItem->SetCount(count);
|
||||||
if (!clone)
|
if (!clone)
|
||||||
pItem->SetItemRandomProperties(randomPropertyId ? randomPropertyId : Item::GenerateItemRandomPropertyId(item));
|
pItem->SetItemRandomProperties(randomPropertyId ? randomPropertyId : Item::GenerateItemRandomPropertyId(item));
|
||||||
else if (randomPropertyId)
|
else if (randomPropertyId)
|
||||||
pItem->SetItemRandomProperties(randomPropertyId);
|
pItem->SetItemRandomProperties(randomPropertyId);
|
||||||
|
|
||||||
return pItem;
|
return pItem;
|
||||||
}
|
|
||||||
else
|
|
||||||
delete pItem;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ABORT();
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Item* Item::CloneItem(uint32 count, Player const* player) const
|
Item* Item::CloneItem(uint32 count, Player const* player) const
|
||||||
|
|||||||
@@ -121,10 +121,14 @@ void Object::_InitValues()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Object::_Create(ObjectGuid::LowType guidlow, uint32 entry, HighGuid guidhigh)
|
void Object::_Create(ObjectGuid::LowType guidlow, uint32 entry, HighGuid guidhigh)
|
||||||
|
{
|
||||||
|
_Create(ObjectGuid(guidhigh, entry, guidlow));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Object::_Create(ObjectGuid guid)
|
||||||
{
|
{
|
||||||
if (!m_uint32Values) _InitValues();
|
if (!m_uint32Values) _InitValues();
|
||||||
|
|
||||||
ObjectGuid guid(guidhigh, entry, guidlow);
|
|
||||||
SetGuidValue(OBJECT_FIELD_GUID, guid);
|
SetGuidValue(OBJECT_FIELD_GUID, guid);
|
||||||
SetUInt32Value(OBJECT_FIELD_TYPE, m_objectType);
|
SetUInt32Value(OBJECT_FIELD_TYPE, m_objectType);
|
||||||
m_PackGUID.Set(guid);
|
m_PackGUID.Set(guid);
|
||||||
|
|||||||
@@ -241,6 +241,7 @@ protected:
|
|||||||
|
|
||||||
void _InitValues();
|
void _InitValues();
|
||||||
void _Create(ObjectGuid::LowType guidlow, uint32 entry, HighGuid guidhigh);
|
void _Create(ObjectGuid::LowType guidlow, uint32 entry, HighGuid guidhigh);
|
||||||
|
void _Create(ObjectGuid guid);
|
||||||
[[nodiscard]] std::string _ConcatFields(uint16 startIndex, uint16 size) const;
|
[[nodiscard]] std::string _ConcatFields(uint16 startIndex, uint16 size) const;
|
||||||
bool _LoadIntoDataField(std::string const& data, uint32 startOffset, uint32 count);
|
bool _LoadIntoDataField(std::string const& data, uint32 startOffset, uint32 count);
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "ObjectGuid.h"
|
#include "ObjectGuid.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
@@ -96,6 +97,21 @@ void ObjectGuidGeneratorBase::HandleCounterOverflow(HighGuid high)
|
|||||||
World::StopNow(ERROR_EXIT_CODE);
|
World::StopNow(ERROR_EXIT_CODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ObjectGuidGeneratorBase::GetClusterGuid(HighGuid high, uint16 realmId, ObjectGuid::LowType& clusterGuid)
|
||||||
|
{
|
||||||
|
if (!sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (high == HighGuid::Player)
|
||||||
|
clusterGuid = ObjectGuid::LowType(sToCloud9Sidecar->GenerateCharacterGuid(realmId));
|
||||||
|
else if (high == HighGuid::Item)
|
||||||
|
clusterGuid = ObjectGuid::LowType(sToCloud9Sidecar->GenerateItemGuid(realmId));
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
#define GUID_TRAIT_INSTANTIATE_GUID( HIGH_GUID ) \
|
#define GUID_TRAIT_INSTANTIATE_GUID( HIGH_GUID ) \
|
||||||
template class ObjectGuidGenerator< HIGH_GUID >;
|
template class ObjectGuidGenerator< HIGH_GUID >;
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,9 @@
|
|||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
// Realm id packed into bits 32-47 of a player ObjectGuid; 0 means local / non-crossrealm.
|
||||||
|
constexpr uint16 DEFAULT_NON_CROSSREALM_REALM_ID = 0;
|
||||||
|
|
||||||
enum TypeID
|
enum TypeID
|
||||||
{
|
{
|
||||||
TYPEID_OBJECT = 0,
|
TYPEID_OBJECT = 0,
|
||||||
@@ -142,6 +145,7 @@ class ObjectGuid
|
|||||||
[[nodiscard]] uint64 GetRawValue() const { return _guid; }
|
[[nodiscard]] uint64 GetRawValue() const { return _guid; }
|
||||||
[[nodiscard]] HighGuid GetHigh() const { return HighGuid((_guid >> 48) & 0x0000FFFF); }
|
[[nodiscard]] HighGuid GetHigh() const { return HighGuid((_guid >> 48) & 0x0000FFFF); }
|
||||||
[[nodiscard]] uint32 GetEntry() const { return HasEntry() ? uint32((_guid >> 24) & UI64LIT(0x0000000000FFFFFF)) : 0; }
|
[[nodiscard]] uint32 GetEntry() const { return HasEntry() ? uint32((_guid >> 24) & UI64LIT(0x0000000000FFFFFF)) : 0; }
|
||||||
|
[[nodiscard]] uint16 GetRealmID() const { return IsPlayer() ? uint16((_guid >> 32) & UI64LIT(0xFFFF)) : 0; }
|
||||||
[[nodiscard]] LowType GetCounter() const
|
[[nodiscard]] LowType GetCounter() const
|
||||||
{
|
{
|
||||||
return HasEntry()
|
return HasEntry()
|
||||||
@@ -283,12 +287,13 @@ public:
|
|||||||
ObjectGuidGeneratorBase(ObjectGuid::LowType start = 1) : _nextGuid(start) { }
|
ObjectGuidGeneratorBase(ObjectGuid::LowType start = 1) : _nextGuid(start) { }
|
||||||
|
|
||||||
virtual void Set(ObjectGuid::LowType val) { _nextGuid = val; }
|
virtual void Set(ObjectGuid::LowType val) { _nextGuid = val; }
|
||||||
virtual ObjectGuid::LowType Generate() = 0;
|
virtual ObjectGuid::LowType Generate(uint16 realmId = DEFAULT_NON_CROSSREALM_REALM_ID) = 0;
|
||||||
[[nodiscard]] ObjectGuid::LowType GetNextAfterMaxUsed() const { return _nextGuid; }
|
[[nodiscard]] ObjectGuid::LowType GetNextAfterMaxUsed() const { return _nextGuid; }
|
||||||
virtual ~ObjectGuidGeneratorBase() = default;
|
virtual ~ObjectGuidGeneratorBase() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void HandleCounterOverflow(HighGuid high);
|
static void HandleCounterOverflow(HighGuid high);
|
||||||
|
static bool GetClusterGuid(HighGuid high, uint16 realmId, ObjectGuid::LowType& clusterGuid);
|
||||||
ObjectGuid::LowType _nextGuid;
|
ObjectGuid::LowType _nextGuid;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -298,8 +303,12 @@ class ObjectGuidGenerator : public ObjectGuidGeneratorBase
|
|||||||
public:
|
public:
|
||||||
explicit ObjectGuidGenerator(ObjectGuid::LowType start = 1) : ObjectGuidGeneratorBase(start) { }
|
explicit ObjectGuidGenerator(ObjectGuid::LowType start = 1) : ObjectGuidGeneratorBase(start) { }
|
||||||
|
|
||||||
ObjectGuid::LowType Generate() override
|
ObjectGuid::LowType Generate(uint16 realmId = DEFAULT_NON_CROSSREALM_REALM_ID) override
|
||||||
{
|
{
|
||||||
|
ObjectGuid::LowType clusterGuid = 0;
|
||||||
|
if (GetClusterGuid(high, realmId, clusterGuid))
|
||||||
|
return clusterGuid;
|
||||||
|
|
||||||
if (_nextGuid >= ObjectGuid::GetMaxCounter(high) - 1)
|
if (_nextGuid >= ObjectGuid::GetMaxCounter(high) - 1)
|
||||||
HandleCounterOverflow(high);
|
HandleCounterOverflow(high);
|
||||||
|
|
||||||
|
|||||||
@@ -3783,7 +3783,7 @@ void Player::_LoadSpellCooldowns(PreparedQueryResult result)
|
|||||||
void Player::_SaveSpellCooldowns(CharacterDatabaseTransaction trans, bool logout)
|
void Player::_SaveSpellCooldowns(CharacterDatabaseTransaction trans, bool logout)
|
||||||
{
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_COOLDOWN);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
time_t curTime = GameTime::GetGameTime().count();
|
time_t curTime = GameTime::GetGameTime().count();
|
||||||
@@ -4770,7 +4770,7 @@ void Player::SpawnCorpseBones(bool triggerSave /*= true*/)
|
|||||||
|
|
||||||
// pussywizard: update only ghost flag instead of whole character table entry! data integrity is crucial
|
// pussywizard: update only ghost flag instead of whole character table entry! data integrity is crucial
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_REMOVE_GHOST);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_REMOVE_GHOST);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
_SaveAuras(trans, false);
|
_SaveAuras(trans, false);
|
||||||
@@ -6455,7 +6455,7 @@ void Player::ModifyHonorPoints(int32 value, CharacterDatabaseTransaction trans)
|
|||||||
{
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_HONOR_POINTS);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_HONOR_POINTS);
|
||||||
stmt->SetData(0, newValue);
|
stmt->SetData(0, newValue);
|
||||||
stmt->SetData(1, GetGUID().GetCounter());
|
stmt->SetData(1, GetGUID().GetRawValue());
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6471,7 +6471,7 @@ void Player::ModifyArenaPoints(int32 value, CharacterDatabaseTransaction trans)
|
|||||||
{
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_ARENA_POINTS);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_ARENA_POINTS);
|
||||||
stmt->SetData(0, newValue);
|
stmt->SetData(0, newValue);
|
||||||
stmt->SetData(1, GetGUID().GetCounter());
|
stmt->SetData(1, GetGUID().GetRawValue());
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9324,7 +9324,7 @@ void Player::RemovePet(Pet* pet, PetSaveMode mode, bool returnreagent)
|
|||||||
// Handle removing pet while it is in "temporarily unsummoned" state, for example on mount
|
// Handle removing pet while it is in "temporarily unsummoned" state, for example on mount
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_PET_SLOT_BY_ID);
|
||||||
stmt->SetData(0, PET_SAVE_NOT_IN_SLOT);
|
stmt->SetData(0, PET_SAVE_NOT_IN_SLOT);
|
||||||
stmt->SetData(1, GetGUID().GetCounter());
|
stmt->SetData(1, GetGUID().GetRawValue());
|
||||||
stmt->SetData(2, m_petStable->CurrentPet->PetNumber);
|
stmt->SetData(2, m_petStable->CurrentPet->PetNumber);
|
||||||
CharacterDatabase.Execute(stmt);
|
CharacterDatabase.Execute(stmt);
|
||||||
|
|
||||||
@@ -11502,7 +11502,7 @@ void Player::LeaveBattleground(Battleground* bg)
|
|||||||
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_TRACK_DESERTERS))
|
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_TRACK_DESERTERS))
|
||||||
{
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_DESERTER_TRACK);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_DESERTER_TRACK);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, BG_DESERTION_TYPE_LEAVE_BG);
|
stmt->SetData(1, BG_DESERTION_TYPE_LEAVE_BG);
|
||||||
CharacterDatabase.Execute(stmt);
|
CharacterDatabase.Execute(stmt);
|
||||||
}
|
}
|
||||||
@@ -14026,7 +14026,7 @@ void Player::_LoadSkills(PreparedQueryResult result)
|
|||||||
|
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_SKILL);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_SKILL);
|
||||||
|
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, skill);
|
stmt->SetData(1, skill);
|
||||||
|
|
||||||
CharacterDatabase.Execute(stmt);
|
CharacterDatabase.Execute(stmt);
|
||||||
@@ -14971,7 +14971,7 @@ void Player::_SaveEquipmentSets(CharacterDatabaseTransaction trans)
|
|||||||
stmt->SetData(j++, eqset.IgnoreMask);
|
stmt->SetData(j++, eqset.IgnoreMask);
|
||||||
for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
|
for (uint8 i = 0; i < EQUIPMENT_SLOT_END; ++i)
|
||||||
stmt->SetData(j++, eqset.Items[i].GetCounter());
|
stmt->SetData(j++, eqset.Items[i].GetCounter());
|
||||||
stmt->SetData(j++, GetGUID().GetCounter());
|
stmt->SetData(j++, GetGUID().GetRawValue());
|
||||||
stmt->SetData(j++, eqset.Guid);
|
stmt->SetData(j++, eqset.Guid);
|
||||||
stmt->SetData(j, index);
|
stmt->SetData(j, index);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
@@ -14980,7 +14980,7 @@ void Player::_SaveEquipmentSets(CharacterDatabaseTransaction trans)
|
|||||||
break;
|
break;
|
||||||
case EQUIPMENT_SET_NEW:
|
case EQUIPMENT_SET_NEW:
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_EQUIP_SET);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_EQUIP_SET);
|
||||||
stmt->SetData(j++, GetGUID().GetCounter());
|
stmt->SetData(j++, GetGUID().GetRawValue());
|
||||||
stmt->SetData(j++, eqset.Guid);
|
stmt->SetData(j++, eqset.Guid);
|
||||||
stmt->SetData(j++, index);
|
stmt->SetData(j++, index);
|
||||||
stmt->SetData(j++, eqset.Name.c_str());
|
stmt->SetData(j++, eqset.Name.c_str());
|
||||||
@@ -15010,11 +15010,11 @@ void Player::_SaveEntryPoint(CharacterDatabaseTransaction trans)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_ENTRY_POINT);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_ENTRY_POINT);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_ENTRY_POINT);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_ENTRY_POINT);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData (1, m_entryPointData.joinPos.GetPositionX());
|
stmt->SetData (1, m_entryPointData.joinPos.GetPositionX());
|
||||||
stmt->SetData (2, m_entryPointData.joinPos.GetPositionY());
|
stmt->SetData (2, m_entryPointData.joinPos.GetPositionY());
|
||||||
stmt->SetData (3, m_entryPointData.joinPos.GetPositionZ());
|
stmt->SetData (3, m_entryPointData.joinPos.GetPositionZ());
|
||||||
@@ -15050,7 +15050,7 @@ void Player::RemoveAtLoginFlag(AtLoginFlags flags, bool persist /*= false*/)
|
|||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_REM_AT_LOGIN_FLAG);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_REM_AT_LOGIN_FLAG);
|
||||||
|
|
||||||
stmt->SetData(0, uint16(flags));
|
stmt->SetData(0, uint16(flags));
|
||||||
stmt->SetData(1, GetGUID().GetCounter());
|
stmt->SetData(1, GetGUID().GetRawValue());
|
||||||
|
|
||||||
CharacterDatabase.Execute(stmt);
|
CharacterDatabase.Execute(stmt);
|
||||||
}
|
}
|
||||||
@@ -15097,7 +15097,7 @@ void Player::_SaveCharacter(bool create, CharacterDatabaseTransaction trans)
|
|||||||
//! Insert query
|
//! Insert query
|
||||||
//! TO DO: Filter out more redundant fields that can take their default value at player create
|
//! TO DO: Filter out more redundant fields that can take their default value at player create
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER);
|
||||||
stmt->SetData(index++, GetGUID().GetCounter());
|
stmt->SetData(index++, GetGUID().GetRawValue());
|
||||||
stmt->SetData(index++, GetSession()->GetAccountId());
|
stmt->SetData(index++, GetSession()->GetAccountId());
|
||||||
stmt->SetData(index++, GetName());
|
stmt->SetData(index++, GetName());
|
||||||
stmt->SetData(index++, getRace(true));
|
stmt->SetData(index++, getRace(true));
|
||||||
@@ -15355,7 +15355,7 @@ void Player::_SaveCharacter(bool create, CharacterDatabaseTransaction trans)
|
|||||||
|
|
||||||
stmt->SetData(index++, IsInWorld() && !GetSession()->PlayerLogout() ? 1 : 0);
|
stmt->SetData(index++, IsInWorld() && !GetSession()->PlayerLogout() ? 1 : 0);
|
||||||
// Index
|
// Index
|
||||||
stmt->SetData(index++, GetGUID().GetCounter());
|
stmt->SetData(index++, GetGUID().GetRawValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
@@ -15390,7 +15390,7 @@ void Player::_SaveGlyphs(CharacterDatabaseTransaction trans)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GLYPHS);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_GLYPHS);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
for (uint8 spec = 0; spec < m_specsCount; ++spec)
|
for (uint8 spec = 0; spec < m_specsCount; ++spec)
|
||||||
@@ -15398,7 +15398,7 @@ void Player::_SaveGlyphs(CharacterDatabaseTransaction trans)
|
|||||||
uint8 index = 0;
|
uint8 index = 0;
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_GLYPHS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_GLYPHS);
|
||||||
stmt->SetData(index++, GetGUID().GetCounter());
|
stmt->SetData(index++, GetGUID().GetRawValue());
|
||||||
stmt->SetData(index++, spec);
|
stmt->SetData(index++, spec);
|
||||||
|
|
||||||
for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i)
|
for (uint8 i = 0; i < MAX_GLYPH_SLOT_INDEX; ++i)
|
||||||
@@ -15445,7 +15445,7 @@ void Player::_SaveTalents(CharacterDatabaseTransaction trans)
|
|||||||
if (itr->second->State == PLAYERSPELL_REMOVED || itr->second->State == PLAYERSPELL_CHANGED)
|
if (itr->second->State == PLAYERSPELL_REMOVED || itr->second->State == PLAYERSPELL_CHANGED)
|
||||||
{
|
{
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TALENT_BY_SPELL);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_TALENT_BY_SPELL);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, itr->first);
|
stmt->SetData(1, itr->first);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
@@ -15454,7 +15454,7 @@ void Player::_SaveTalents(CharacterDatabaseTransaction trans)
|
|||||||
if (itr->second->State == PLAYERSPELL_NEW || itr->second->State == PLAYERSPELL_CHANGED)
|
if (itr->second->State == PLAYERSPELL_NEW || itr->second->State == PLAYERSPELL_CHANGED)
|
||||||
{
|
{
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_TALENT);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_TALENT);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, itr->first);
|
stmt->SetData(1, itr->first);
|
||||||
stmt->SetData(2, itr->second->specMask);
|
stmt->SetData(2, itr->second->specMask);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
@@ -15627,7 +15627,7 @@ void Player::ActivateSpec(uint8 spec)
|
|||||||
// load them asynchronously
|
// load them asynchronously
|
||||||
{
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS_SPEC);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, m_activeSpec);
|
stmt->SetData(1, m_activeSpec);
|
||||||
|
|
||||||
WorldSession* mySess = GetSession();
|
WorldSession* mySess = GetSession();
|
||||||
@@ -16142,7 +16142,7 @@ void Player::SetRandomWinner(bool isWinner)
|
|||||||
if (m_IsBGRandomWinner)
|
if (m_IsBGRandomWinner)
|
||||||
{
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_BATTLEGROUND_RANDOM);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_BATTLEGROUND_RANDOM);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
CharacterDatabase.Execute(stmt);
|
CharacterDatabase.Execute(stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -16259,7 +16259,7 @@ void Player::_LoadBrewOfTheMonth(PreparedQueryResult result)
|
|||||||
|
|
||||||
// Update Event Id
|
// Update Event Id
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_BREW_OF_THE_MONTH);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_BREW_OF_THE_MONTH);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, uint32(eventId));
|
stmt->SetData(1, uint32(eventId));
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
|
|||||||
@@ -4978,7 +4978,7 @@ void Player::SetHomebind(WorldLocation const& loc, uint32 areaId)
|
|||||||
stmt->SetData (2, m_homebindX);
|
stmt->SetData (2, m_homebindX);
|
||||||
stmt->SetData (3, m_homebindY);
|
stmt->SetData (3, m_homebindY);
|
||||||
stmt->SetData (4, m_homebindZ);
|
stmt->SetData (4, m_homebindZ);
|
||||||
stmt->SetData(5, GetGUID().GetCounter());
|
stmt->SetData(5, GetGUID().GetRawValue());
|
||||||
CharacterDatabase.Execute(stmt);
|
CharacterDatabase.Execute(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5027,9 +5027,9 @@ bool Player::LoadFromDB(ObjectGuid playerGuid, CharacterDatabaseQueryHolder cons
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectGuid::LowType guid = playerGuid.GetCounter();
|
uint64 guid = playerGuid.GetRawValue();
|
||||||
|
|
||||||
Object::_Create(guid, 0, HighGuid::Player);
|
Object::_Create(playerGuid);
|
||||||
|
|
||||||
m_name = fields[2].Get<std::string>();
|
m_name = fields[2].Get<std::string>();
|
||||||
|
|
||||||
@@ -6101,7 +6101,7 @@ Item* Player::_LoadItem(CharacterDatabaseTransaction trans, uint32 zoneId, uint3
|
|||||||
// xinef: sync query
|
// xinef: sync query
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_REFUNDS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ITEM_REFUNDS);
|
||||||
stmt->SetData(0, item->GetGUID().GetCounter());
|
stmt->SetData(0, item->GetGUID().GetCounter());
|
||||||
stmt->SetData(1, GetGUID().GetCounter());
|
stmt->SetData(1, GetGUID().GetRawValue());
|
||||||
if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
|
if (PreparedQueryResult result = CharacterDatabase.Query(stmt))
|
||||||
{
|
{
|
||||||
item->SetRefundRecipient((*result)[0].Get<uint32>());
|
item->SetRefundRecipient((*result)[0].Get<uint32>());
|
||||||
@@ -7152,7 +7152,7 @@ bool Player::_LoadHomeBind(PreparedQueryResult result)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_HOMEBIND);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_PLAYER_HOMEBIND);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
CharacterDatabase.Execute(stmt);
|
CharacterDatabase.Execute(stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7166,7 +7166,7 @@ bool Player::_LoadHomeBind(PreparedQueryResult result)
|
|||||||
m_homebindZ = info->positionZ;
|
m_homebindZ = info->positionZ;
|
||||||
|
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_HOMEBIND);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_PLAYER_HOMEBIND);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, m_homebindMapId);
|
stmt->SetData(1, m_homebindMapId);
|
||||||
stmt->SetData(2, m_homebindAreaId);
|
stmt->SetData(2, m_homebindAreaId);
|
||||||
stmt->SetData (3, m_homebindX);
|
stmt->SetData (3, m_homebindX);
|
||||||
@@ -7265,7 +7265,7 @@ void Player::SaveGoldToDB(CharacterDatabaseTransaction trans)
|
|||||||
{
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_MONEY);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_MONEY);
|
||||||
stmt->SetData(0, GetMoney());
|
stmt->SetData(0, GetMoney());
|
||||||
stmt->SetData(1, GetGUID().GetCounter());
|
stmt->SetData(1, GetGUID().GetRawValue());
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7279,7 +7279,7 @@ void Player::_SaveActions(CharacterDatabaseTransaction trans)
|
|||||||
{
|
{
|
||||||
case ACTIONBUTTON_NEW:
|
case ACTIONBUTTON_NEW:
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACTION);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACTION);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, m_activeSpec);
|
stmt->SetData(1, m_activeSpec);
|
||||||
stmt->SetData(2, itr->first);
|
stmt->SetData(2, itr->first);
|
||||||
stmt->SetData(3, itr->second.GetAction());
|
stmt->SetData(3, itr->second.GetAction());
|
||||||
@@ -7293,7 +7293,7 @@ void Player::_SaveActions(CharacterDatabaseTransaction trans)
|
|||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ACTION);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ACTION);
|
||||||
stmt->SetData(0, itr->second.GetAction());
|
stmt->SetData(0, itr->second.GetAction());
|
||||||
stmt->SetData(1, uint8(itr->second.GetType()));
|
stmt->SetData(1, uint8(itr->second.GetType()));
|
||||||
stmt->SetData(2, GetGUID().GetCounter());
|
stmt->SetData(2, GetGUID().GetRawValue());
|
||||||
stmt->SetData(3, itr->first);
|
stmt->SetData(3, itr->first);
|
||||||
stmt->SetData(4, m_activeSpec);
|
stmt->SetData(4, m_activeSpec);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
@@ -7303,7 +7303,7 @@ void Player::_SaveActions(CharacterDatabaseTransaction trans)
|
|||||||
break;
|
break;
|
||||||
case ACTIONBUTTON_DELETED:
|
case ACTIONBUTTON_DELETED:
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACTION_BY_BUTTON_SPEC);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACTION_BY_BUTTON_SPEC);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, itr->first);
|
stmt->SetData(1, itr->first);
|
||||||
stmt->SetData(2, m_activeSpec);
|
stmt->SetData(2, m_activeSpec);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
@@ -7320,7 +7320,7 @@ void Player::_SaveActions(CharacterDatabaseTransaction trans)
|
|||||||
void Player::_SaveAuras(CharacterDatabaseTransaction trans, bool logout)
|
void Player::_SaveAuras(CharacterDatabaseTransaction trans, bool logout)
|
||||||
{
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_AURA);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
for (AuraMap::const_iterator itr = m_ownedAuras.begin(); itr != m_ownedAuras.end(); ++itr)
|
for (AuraMap::const_iterator itr = m_ownedAuras.begin(); itr != m_ownedAuras.end(); ++itr)
|
||||||
@@ -7355,7 +7355,7 @@ void Player::_SaveAuras(CharacterDatabaseTransaction trans, bool logout)
|
|||||||
|
|
||||||
uint8 index = 0;
|
uint8 index = 0;
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AURA);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_AURA);
|
||||||
stmt->SetData(index++, GetGUID().GetCounter());
|
stmt->SetData(index++, GetGUID().GetRawValue());
|
||||||
stmt->SetData(index++, itr->second->GetCasterGUID().GetRawValue());
|
stmt->SetData(index++, itr->second->GetCasterGUID().GetRawValue());
|
||||||
stmt->SetData(index++, itr->second->GetCastItemGUID().GetRawValue());
|
stmt->SetData(index++, itr->second->GetCastItemGUID().GetRawValue());
|
||||||
stmt->SetData(index++, itr->second->GetId());
|
stmt->SetData(index++, itr->second->GetId());
|
||||||
@@ -7440,7 +7440,7 @@ void Player::_SaveInventory(CharacterDatabaseTransaction trans)
|
|||||||
if (m_itemUpdateQueue.empty())
|
if (m_itemUpdateQueue.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ObjectGuid::LowType lowGuid = GetGUID().GetCounter();
|
uint64 guid = GetGUID().GetRawValue();
|
||||||
for (std::size_t i = 0; i < m_itemUpdateQueue.size(); ++i)
|
for (std::size_t i = 0; i < m_itemUpdateQueue.size(); ++i)
|
||||||
{
|
{
|
||||||
Item* item = m_itemUpdateQueue[i];
|
Item* item = m_itemUpdateQueue[i];
|
||||||
@@ -7459,12 +7459,12 @@ void Player::_SaveInventory(CharacterDatabaseTransaction trans)
|
|||||||
if (Item* test2 = GetItemByPos(INVENTORY_SLOT_BAG_0, item->GetBagSlot()))
|
if (Item* test2 = GetItemByPos(INVENTORY_SLOT_BAG_0, item->GetBagSlot()))
|
||||||
bagTestGUID = test2->GetGUID().GetCounter();
|
bagTestGUID = test2->GetGUID().GetCounter();
|
||||||
LOG_ERROR("entities.player", "Player(GUID: {} Name: {})::_SaveInventory - the bag({}) and slot({}) values for the item {} (state {}) are incorrect, the player doesn't have an item at that position!",
|
LOG_ERROR("entities.player", "Player(GUID: {} Name: {})::_SaveInventory - the bag({}) and slot({}) values for the item {} (state {}) are incorrect, the player doesn't have an item at that position!",
|
||||||
lowGuid, GetName(), item->GetBagSlot(), item->GetSlot(), item->GetGUID().ToString(), (int32)item->GetState());
|
guid, GetName(), item->GetBagSlot(), item->GetSlot(), item->GetGUID().ToString(), (int32)item->GetState());
|
||||||
// according to the test that was just performed nothing should be in this slot, delete
|
// according to the test that was just performed nothing should be in this slot, delete
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_BAG_SLOT);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INVENTORY_BY_BAG_SLOT);
|
||||||
stmt->SetData(0, bagTestGUID);
|
stmt->SetData(0, bagTestGUID);
|
||||||
stmt->SetData(1, item->GetSlot());
|
stmt->SetData(1, item->GetSlot());
|
||||||
stmt->SetData(2, lowGuid);
|
stmt->SetData(2, guid);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
RemoveTradeableItem(item); // pussywizard
|
RemoveTradeableItem(item); // pussywizard
|
||||||
@@ -7480,7 +7480,7 @@ void Player::_SaveInventory(CharacterDatabaseTransaction trans)
|
|||||||
else if (test != item)
|
else if (test != item)
|
||||||
{
|
{
|
||||||
LOG_ERROR("entities.player", "Player(GUID: {} Name: {})::_SaveInventory - the bag({}) and slot({}) values for the item ({}) are incorrect, the item ({}) is there instead!",
|
LOG_ERROR("entities.player", "Player(GUID: {} Name: {})::_SaveInventory - the bag({}) and slot({}) values for the item ({}) are incorrect, the item ({}) is there instead!",
|
||||||
lowGuid, GetName(), item->GetBagSlot(), item->GetSlot(), item->GetGUID().ToString(), test->GetGUID().ToString());
|
guid, GetName(), item->GetBagSlot(), item->GetSlot(), item->GetGUID().ToString(), test->GetGUID().ToString());
|
||||||
// save all changes to the item...
|
// save all changes to the item...
|
||||||
if (item->GetState() != ITEM_NEW) // only for existing items, no dupes
|
if (item->GetState() != ITEM_NEW) // only for existing items, no dupes
|
||||||
item->SaveToDB(trans);
|
item->SaveToDB(trans);
|
||||||
@@ -7494,7 +7494,7 @@ void Player::_SaveInventory(CharacterDatabaseTransaction trans)
|
|||||||
case ITEM_NEW:
|
case ITEM_NEW:
|
||||||
case ITEM_CHANGED:
|
case ITEM_CHANGED:
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_INVENTORY_ITEM);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_INVENTORY_ITEM);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, guid);
|
||||||
stmt->SetData(1, bag_guid);
|
stmt->SetData(1, bag_guid);
|
||||||
stmt->SetData (2, item->GetSlot());
|
stmt->SetData (2, item->GetSlot());
|
||||||
stmt->SetData(3, item->GetGUID().GetCounter());
|
stmt->SetData(3, item->GetGUID().GetCounter());
|
||||||
@@ -7610,7 +7610,7 @@ void Player::_SaveQuestStatus(CharacterDatabaseTransaction trans)
|
|||||||
uint8 index = 0;
|
uint8 index = 0;
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_QUESTSTATUS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CHAR_QUESTSTATUS);
|
||||||
|
|
||||||
stmt->SetData(index++, GetGUID().GetCounter());
|
stmt->SetData(index++, GetGUID().GetRawValue());
|
||||||
stmt->SetData(index++, statusItr->first);
|
stmt->SetData(index++, statusItr->first);
|
||||||
stmt->SetData(index++, uint8(statusItr->second.Status));
|
stmt->SetData(index++, uint8(statusItr->second.Status));
|
||||||
stmt->SetData(index++, statusItr->second.Explored);
|
stmt->SetData(index++, statusItr->second.Explored);
|
||||||
@@ -7629,7 +7629,7 @@ void Player::_SaveQuestStatus(CharacterDatabaseTransaction trans)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_BY_QUEST);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, saveItr->first);
|
stmt->SetData(1, saveItr->first);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
@@ -7644,7 +7644,7 @@ void Player::_SaveQuestStatus(CharacterDatabaseTransaction trans)
|
|||||||
else // xinef: what the is this? quest can be removed by spelleffect if (!keepAbandoned)
|
else // xinef: what the is this? quest can be removed by spelleffect if (!keepAbandoned)
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_QUESTSTATUS_REWARDED_BY_QUEST);
|
||||||
|
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, saveItr->first);
|
stmt->SetData(1, saveItr->first);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
@@ -7666,14 +7666,14 @@ void Player::_SaveDailyQuestStatus(CharacterDatabaseTransaction trans)
|
|||||||
|
|
||||||
// we don't need transactions here.
|
// we don't need transactions here.
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_DAILY_CHAR);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_DAILY_CHAR);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
for (uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx)
|
for (uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx)
|
||||||
{
|
{
|
||||||
if (GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1 + quest_daily_idx))
|
if (GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1 + quest_daily_idx))
|
||||||
{
|
{
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_DAILYQUESTSTATUS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_DAILYQUESTSTATUS);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1 + quest_daily_idx));
|
stmt->SetData(1, GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1 + quest_daily_idx));
|
||||||
stmt->SetData(2, uint64(m_lastDailyQuestTime));
|
stmt->SetData(2, uint64(m_lastDailyQuestTime));
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
@@ -7685,7 +7685,7 @@ void Player::_SaveDailyQuestStatus(CharacterDatabaseTransaction trans)
|
|||||||
for (DFQuestsDoneList::iterator itr = m_DFQuests.begin(); itr != m_DFQuests.end(); ++itr)
|
for (DFQuestsDoneList::iterator itr = m_DFQuests.begin(); itr != m_DFQuests.end(); ++itr)
|
||||||
{
|
{
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_DAILYQUESTSTATUS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_DAILYQUESTSTATUS);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, (*itr));
|
stmt->SetData(1, (*itr));
|
||||||
stmt->SetData(2, uint64(m_lastDailyQuestTime));
|
stmt->SetData(2, uint64(m_lastDailyQuestTime));
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
@@ -7700,7 +7700,7 @@ void Player::_SaveWeeklyQuestStatus(CharacterDatabaseTransaction trans)
|
|||||||
|
|
||||||
// we don't need transactions here.
|
// we don't need transactions here.
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_WEEKLY_CHAR);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_WEEKLY_CHAR);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
for (QuestSet::const_iterator iter = m_weeklyquests.begin(); iter != m_weeklyquests.end(); ++iter)
|
for (QuestSet::const_iterator iter = m_weeklyquests.begin(); iter != m_weeklyquests.end(); ++iter)
|
||||||
@@ -7708,7 +7708,7 @@ void Player::_SaveWeeklyQuestStatus(CharacterDatabaseTransaction trans)
|
|||||||
uint32 quest_id = *iter;
|
uint32 quest_id = *iter;
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_WEEKLYQUESTSTATUS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_WEEKLYQUESTSTATUS);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, quest_id);
|
stmt->SetData(1, quest_id);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
@@ -7725,7 +7725,7 @@ void Player::_SaveSeasonalQuestStatus(CharacterDatabaseTransaction trans)
|
|||||||
|
|
||||||
// we don't need transactions here.
|
// we don't need transactions here.
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_SEASONAL_CHAR);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_SEASONAL_CHAR);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
m_SeasonalQuestChanged = false;
|
m_SeasonalQuestChanged = false;
|
||||||
@@ -7744,7 +7744,7 @@ void Player::_SaveSeasonalQuestStatus(CharacterDatabaseTransaction trans)
|
|||||||
uint32 questId = *itr;
|
uint32 questId = *itr;
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_SEASONALQUESTSTATUS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_SEASONALQUESTSTATUS);
|
||||||
stmt->SetArguments(GetGUID().GetCounter(), questId, eventId);
|
stmt->SetArguments(GetGUID().GetRawValue(), questId, eventId);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7757,14 +7757,14 @@ void Player::_SaveMonthlyQuestStatus(CharacterDatabaseTransaction trans)
|
|||||||
|
|
||||||
// we don't need transactions here.
|
// we don't need transactions here.
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_MONTHLY_CHAR);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_MONTHLY_CHAR);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
for (QuestSet::const_iterator iter = m_monthlyquests.begin(); iter != m_monthlyquests.end(); ++iter)
|
for (QuestSet::const_iterator iter = m_monthlyquests.begin(); iter != m_monthlyquests.end(); ++iter)
|
||||||
{
|
{
|
||||||
uint32 quest_id = *iter;
|
uint32 quest_id = *iter;
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_MONTHLYQUESTSTATUS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_MONTHLYQUESTSTATUS);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, quest_id);
|
stmt->SetData(1, quest_id);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
@@ -7787,7 +7787,7 @@ void Player::_SaveSkills(CharacterDatabaseTransaction trans)
|
|||||||
if (itr->second.uState == SKILL_DELETED)
|
if (itr->second.uState == SKILL_DELETED)
|
||||||
{
|
{
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SKILL_BY_SKILL);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SKILL_BY_SKILL);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, itr->first);
|
stmt->SetData(1, itr->first);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
@@ -7803,7 +7803,7 @@ void Player::_SaveSkills(CharacterDatabaseTransaction trans)
|
|||||||
{
|
{
|
||||||
case SKILL_NEW:
|
case SKILL_NEW:
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_SKILLS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_SKILLS);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, uint16(itr->first));
|
stmt->SetData(1, uint16(itr->first));
|
||||||
stmt->SetData(2, value);
|
stmt->SetData(2, value);
|
||||||
stmt->SetData(3, max);
|
stmt->SetData(3, max);
|
||||||
@@ -7814,7 +7814,7 @@ void Player::_SaveSkills(CharacterDatabaseTransaction trans)
|
|||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_SKILLS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_UDP_CHAR_SKILLS);
|
||||||
stmt->SetData(0, value);
|
stmt->SetData(0, value);
|
||||||
stmt->SetData(1, max);
|
stmt->SetData(1, max);
|
||||||
stmt->SetData(2, GetGUID().GetCounter());
|
stmt->SetData(2, GetGUID().GetRawValue());
|
||||||
stmt->SetData(3, uint16(itr->first));
|
stmt->SetData(3, uint16(itr->first));
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
@@ -7845,7 +7845,7 @@ void Player::_SaveSpells(CharacterDatabaseTransaction trans)
|
|||||||
if (itr->second->State == PLAYERSPELL_REMOVED || itr->second->State == PLAYERSPELL_CHANGED)
|
if (itr->second->State == PLAYERSPELL_REMOVED || itr->second->State == PLAYERSPELL_CHANGED)
|
||||||
{
|
{
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_BY_SPELL);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_SPELL_BY_SPELL);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, itr->first);
|
stmt->SetData(1, itr->first);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
}
|
}
|
||||||
@@ -7854,7 +7854,7 @@ void Player::_SaveSpells(CharacterDatabaseTransaction trans)
|
|||||||
if (itr->second->State == PLAYERSPELL_NEW || itr->second->State == PLAYERSPELL_CHANGED)
|
if (itr->second->State == PLAYERSPELL_NEW || itr->second->State == PLAYERSPELL_CHANGED)
|
||||||
{
|
{
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_SPELL);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_SPELL);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
stmt->SetData(1, itr->first);
|
stmt->SetData(1, itr->first);
|
||||||
stmt->SetData(2, itr->second->specMask);
|
stmt->SetData(2, itr->second->specMask);
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
@@ -7884,13 +7884,13 @@ void Player::_SaveStats(CharacterDatabaseTransaction trans)
|
|||||||
CharacterDatabasePreparedStatement* stmt = nullptr;
|
CharacterDatabasePreparedStatement* stmt = nullptr;
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_STATS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_STATS);
|
||||||
stmt->SetData(0, GetGUID().GetCounter());
|
stmt->SetData(0, GetGUID().GetRawValue());
|
||||||
trans->Append(stmt);
|
trans->Append(stmt);
|
||||||
|
|
||||||
uint8 index = 0;
|
uint8 index = 0;
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_STATS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_STATS);
|
||||||
stmt->SetData(index++, GetGUID().GetCounter());
|
stmt->SetData(index++, GetGUID().GetRawValue());
|
||||||
stmt->SetData(index++, GetMaxHealth());
|
stmt->SetData(index++, GetMaxHealth());
|
||||||
|
|
||||||
for (uint8 i = 0; i < MAX_POWERS; ++i)
|
for (uint8 i = 0; i < MAX_POWERS; ++i)
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "Cell.h"
|
#include "Cell.h"
|
||||||
#include "CellImpl.h"
|
#include "CellImpl.h"
|
||||||
#include "Common.h"
|
#include "Common.h"
|
||||||
|
#include "Config.h"
|
||||||
#include "DBCStores.h"
|
#include "DBCStores.h"
|
||||||
#include "GameObjectAI.h"
|
#include "GameObjectAI.h"
|
||||||
#include "GameTime.h"
|
#include "GameTime.h"
|
||||||
@@ -30,8 +31,28 @@
|
|||||||
#include "Spell.h"
|
#include "Spell.h"
|
||||||
#include "Vehicle.h"
|
#include "Vehicle.h"
|
||||||
#include "WorldModel.h"
|
#include "WorldModel.h"
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
MotionTransport::MotionTransport() : Transport(), _transportInfo(nullptr), _isMoving(true), _pendingStop(false), _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), _passengersLoaded(false), _delayedTeleport(false)
|
namespace
|
||||||
|
{
|
||||||
|
// Any fixed reference epoch works; this one is 2023-07-12 05:20:00 UTC.
|
||||||
|
std::time_t const startTimestamp = 1689139200;
|
||||||
|
std::chrono::system_clock::time_point const transportStartDate = std::chrono::system_clock::from_time_t(startTimestamp);
|
||||||
|
|
||||||
|
// Calculates time of the next departure cycle.
|
||||||
|
std::chrono::system_clock::time_point calculateNextDepartureTime(int oneIterationInterval)
|
||||||
|
{
|
||||||
|
std::chrono::system_clock::time_point currentTime = std::chrono::system_clock::now();
|
||||||
|
std::chrono::milliseconds interval(oneIterationInterval);
|
||||||
|
std::chrono::milliseconds timeSinceStart = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - transportStartDate);
|
||||||
|
int64 intervalsPassed = timeSinceStart.count() / oneIterationInterval;
|
||||||
|
std::chrono::system_clock::time_point nextDeparture = transportStartDate + (interval * (intervalsPassed + 1));
|
||||||
|
return nextDeparture;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionTransport::MotionTransport() : Transport(), _transportInfo(nullptr), _isMoving(true), _pendingStop(false), _triggeredArrivalEvent(false), _triggeredDepartureEvent(false), _passengersLoaded(false), _delayedTeleport(false),
|
||||||
|
_requiresFirstDepartureSync(false), _firstDepartureTime(transportStartDate)
|
||||||
{
|
{
|
||||||
m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION;
|
m_updateFlag = UPDATEFLAG_TRANSPORT | UPDATEFLAG_LOWGUID | UPDATEFLAG_STATIONARY_POSITION | UPDATEFLAG_ROTATION;
|
||||||
}
|
}
|
||||||
@@ -76,6 +97,13 @@ bool MotionTransport::CreateMoTrans(ObjectGuid::LowType guidlow, uint32 entry, u
|
|||||||
|
|
||||||
_transportInfo = tInfo;
|
_transportInfo = tInfo;
|
||||||
|
|
||||||
|
// Enable transport sync only in cluster mode and for transport with several maps.
|
||||||
|
if (sConfigMgr->GetOption<bool>("Cluster.Enabled", false) && tInfo->mapsUsed.size() > 1)
|
||||||
|
{
|
||||||
|
_requiresFirstDepartureSync = true;
|
||||||
|
this->SetPhaseMask(2, true);
|
||||||
|
}
|
||||||
|
|
||||||
// initialize waypoints
|
// initialize waypoints
|
||||||
_nextFrame = tInfo->keyFrames.begin();
|
_nextFrame = tInfo->keyFrames.begin();
|
||||||
_currentFrame = _nextFrame++;
|
_currentFrame = _nextFrame++;
|
||||||
@@ -108,6 +136,56 @@ bool MotionTransport::CreateMoTrans(ObjectGuid::LowType guidlow, uint32 entry, u
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delays first departure to make sure that transport follows strict schedule
|
||||||
|
// and with that makes transport synced between cluster nodes.
|
||||||
|
uint32 MotionTransport::HandleFirstDepartureSync(uint32 diff)
|
||||||
|
{
|
||||||
|
if (!_requiresFirstDepartureSync)
|
||||||
|
return diff;
|
||||||
|
|
||||||
|
if (_firstDepartureTime == transportStartDate)
|
||||||
|
{
|
||||||
|
_firstDepartureTime = calculateNextDepartureTime(_transportInfo->pathTime);
|
||||||
|
return diff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Making system call for current time to be more accurate.
|
||||||
|
// Shouldn't be an issue since it runs only before the very first departure.
|
||||||
|
int32 millLeftToDeparture = std::chrono::duration_cast<std::chrono::milliseconds>(_firstDepartureTime - std::chrono::system_clock::now()).count();
|
||||||
|
if (millLeftToDeparture > 0)
|
||||||
|
return diff;
|
||||||
|
|
||||||
|
// At this point we are ready for first departure.
|
||||||
|
_requiresFirstDepartureSync = false;
|
||||||
|
this->SetPhaseMask(1, true);
|
||||||
|
|
||||||
|
// Players don't know about transport because it was in a different phase.
|
||||||
|
// We need to notify players that object exists before departure.
|
||||||
|
Map::PlayerList const& players = this->GetMap()->GetPlayers();
|
||||||
|
if (!players.IsEmpty())
|
||||||
|
{
|
||||||
|
for (Map::PlayerList::const_iterator i = players.begin(); i != players.end(); ++i)
|
||||||
|
{
|
||||||
|
if (Player* player = i->GetSource())
|
||||||
|
{
|
||||||
|
// Same phase filter as Map::SendInitTransports: players outside
|
||||||
|
// the transport's phase must not get a create-block for it.
|
||||||
|
if (!player->InSamePhase(this))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
UpdateData transData;
|
||||||
|
this->BuildCreateUpdateBlockForPlayer(&transData, player);
|
||||||
|
|
||||||
|
WorldPacket packet;
|
||||||
|
transData.BuildPacket(packet);
|
||||||
|
player->SendDirectMessage(&packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return millLeftToDeparture * -1;
|
||||||
|
}
|
||||||
|
|
||||||
void MotionTransport::CleanupsBeforeDelete(bool finalCleanup /*= true*/)
|
void MotionTransport::CleanupsBeforeDelete(bool finalCleanup /*= true*/)
|
||||||
{
|
{
|
||||||
UnloadStaticPassengers();
|
UnloadStaticPassengers();
|
||||||
@@ -137,6 +215,13 @@ void MotionTransport::BuildUpdate(UpdateDataMapType& data_map)
|
|||||||
|
|
||||||
void MotionTransport::Update(uint32 diff)
|
void MotionTransport::Update(uint32 diff)
|
||||||
{
|
{
|
||||||
|
if (_requiresFirstDepartureSync)
|
||||||
|
{
|
||||||
|
diff = HandleFirstDepartureSync(diff);
|
||||||
|
if (_requiresFirstDepartureSync)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
uint32 const positionUpdateDelay = 1;
|
uint32 const positionUpdateDelay = 1;
|
||||||
|
|
||||||
if (AI())
|
if (AI())
|
||||||
|
|||||||
@@ -90,6 +90,8 @@ private:
|
|||||||
void UpdatePassengerPositions(PassengerSet& passengers);
|
void UpdatePassengerPositions(PassengerSet& passengers);
|
||||||
void DoEventIfAny(KeyFrame const& node, bool departure);
|
void DoEventIfAny(KeyFrame const& node, bool departure);
|
||||||
|
|
||||||
|
uint32 HandleFirstDepartureSync(uint32 diff);
|
||||||
|
|
||||||
//! Helpers to know if stop frame was reached
|
//! Helpers to know if stop frame was reached
|
||||||
bool IsMoving() const { return _isMoving; }
|
bool IsMoving() const { return _isMoving; }
|
||||||
void SetMoving(bool val) { _isMoving = val; }
|
void SetMoving(bool val) { _isMoving = val; }
|
||||||
@@ -109,6 +111,9 @@ private:
|
|||||||
mutable std::mutex Lock;
|
mutable std::mutex Lock;
|
||||||
bool _passengersLoaded;
|
bool _passengersLoaded;
|
||||||
bool _delayedTeleport;
|
bool _delayedTeleport;
|
||||||
|
|
||||||
|
bool _requiresFirstDepartureSync;
|
||||||
|
std::chrono::system_clock::time_point _firstDepartureTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StaticTransport : public Transport
|
class StaticTransport : public Transport
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "UpdateFieldFlags.h"
|
#include "UpdateFieldFlags.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
@@ -329,7 +330,7 @@ void Group::ConvertToRaid()
|
|||||||
|
|
||||||
_initRaidSubGroupsCounter();
|
_initRaidSubGroupsCounter();
|
||||||
|
|
||||||
if (!isBGGroup() && !isBFGroup())
|
if (!sToCloud9Sidecar->ClusterModeEnabled() && !isBGGroup() && !isBFGroup())
|
||||||
{
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_TYPE);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_TYPE);
|
||||||
|
|
||||||
@@ -577,6 +578,52 @@ bool Group::AddMember(Player* player, uint8 roles /* = 0 */)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Group::AddMemberWithGuid(ObjectGuid guid)
|
||||||
|
{
|
||||||
|
// Idempotent under sidecar event redelivery: never duplicate a MemberSlot.
|
||||||
|
if (IsMember(guid))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Player* player = ObjectAccessor::FindPlayer(guid))
|
||||||
|
{
|
||||||
|
AddMember(player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get first not-full group
|
||||||
|
uint8 subGroup = 0;
|
||||||
|
if (m_subGroupsCounts)
|
||||||
|
{
|
||||||
|
bool groupFound = false;
|
||||||
|
for (; subGroup < MAX_RAID_SUBGROUPS; ++subGroup)
|
||||||
|
{
|
||||||
|
if (m_subGroupsCounts[subGroup] < MAXGROUPSIZE)
|
||||||
|
{
|
||||||
|
groupFound = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We are raid group and no one slot is free
|
||||||
|
if (!groupFound)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemberSlot member;
|
||||||
|
member.guid = guid;
|
||||||
|
sCharacterCache->GetCharacterNameByGuid(guid, member.name);
|
||||||
|
member.group = subGroup;
|
||||||
|
member.flags = 0;
|
||||||
|
member.roles = 0;
|
||||||
|
m_memberSlots.push_back(member);
|
||||||
|
|
||||||
|
if (!isBGGroup() && !isBFGroup())
|
||||||
|
{
|
||||||
|
sCharacterCache->UpdateCharacterGroup(guid, GetGUID());
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGroupCounterIncrease(subGroup);
|
||||||
|
}
|
||||||
|
|
||||||
bool Group::RemoveMember(ObjectGuid guid, RemoveMethod const& method /*= GROUP_REMOVEMETHOD_DEFAULT*/, ObjectGuid kicker /*= ObjectGuid::Empty*/, char const* reason /*= nullptr*/)
|
bool Group::RemoveMember(ObjectGuid guid, RemoveMethod const& method /*= GROUP_REMOVEMETHOD_DEFAULT*/, ObjectGuid kicker /*= ObjectGuid::Empty*/, char const* reason /*= nullptr*/)
|
||||||
{
|
{
|
||||||
BroadcastGroupUpdate();
|
BroadcastGroupUpdate();
|
||||||
@@ -588,8 +635,14 @@ bool Group::RemoveMember(ObjectGuid guid, RemoveMethod const& method /*= GROUP_R
|
|||||||
return m_memberSlots.size() > 0;
|
return m_memberSlots.size() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove member and change leader (if need) only if strong more 2 members _before_ member remove (BG/BF allow 1 member group)
|
// remove member and change leader (if need) only if strong more 2 members _before_ member remove (BG/BF allow 1 member group),
|
||||||
if (GetMembersCount() > ((isBGGroup() || isLFGGroup() || isBFGroup()) ? 1u : 2u))
|
// except in cluster mode, where this branch is taken for any size: the group
|
||||||
|
// service owns the group lifecycle and local Disband() is a no-op, so always
|
||||||
|
// unlink the removed member here; waiting for the disband event leaves the
|
||||||
|
// last two members with a dangling group pointer whenever that event is lost
|
||||||
|
// (group service restart).
|
||||||
|
if (GetMembersCount() > ((isBGGroup() || isLFGGroup() || isBFGroup()) ? 1u : 2u)
|
||||||
|
|| (sToCloud9Sidecar->ClusterModeEnabled() && !isBGGroup() && !isBFGroup()))
|
||||||
{
|
{
|
||||||
Player* player = ObjectAccessor::FindConnectedPlayer(guid);
|
Player* player = ObjectAccessor::FindConnectedPlayer(guid);
|
||||||
if (player)
|
if (player)
|
||||||
@@ -609,19 +662,24 @@ bool Group::RemoveMember(ObjectGuid guid, RemoveMethod const& method /*= GROUP_R
|
|||||||
player->UpdateForQuestWorldObjects();
|
player->UpdateForQuestWorldObjects();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BG/BF groups stay locally owned in cluster mode (see the gates above),
|
||||||
|
// so their removal packets must not be delegated to the group service.
|
||||||
|
if (!sToCloud9Sidecar->ClusterModeEnabled() || isBGGroup() || isBFGroup())
|
||||||
|
{
|
||||||
WorldPacket data;
|
WorldPacket data;
|
||||||
|
|
||||||
if (method == GROUP_REMOVEMETHOD_KICK || method == GROUP_REMOVEMETHOD_KICK_LFG)
|
if (method == GROUP_REMOVEMETHOD_KICK || method == GROUP_REMOVEMETHOD_KICK_LFG)
|
||||||
{
|
{
|
||||||
data.Initialize(SMSG_GROUP_UNINVITE, 0);
|
data.Initialize(SMSG_GROUP_UNINVITE, 0);
|
||||||
player->SendDirectMessage(&data);
|
player->GetSession()->SendPacket(&data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do we really need to send this opcode?
|
// Do we really need to send this opcode?
|
||||||
data.Initialize(SMSG_GROUP_LIST, 1 + 1 + 1 + 1 + 8 + 4 + 4 + 8);
|
data.Initialize(SMSG_GROUP_LIST, 1 + 1 + 1 + 1 + 8 + 4 + 4 + 8);
|
||||||
data << uint8(0x10) << uint8(0) << uint8(0) << uint8(0);
|
data << uint8(0x10) << uint8(0) << uint8(0) << uint8(0);
|
||||||
data << m_guid << uint32(m_counter) << uint32(0) << uint64(0);
|
data << m_guid << uint32(m_counter) << uint32(0) << uint64(0);
|
||||||
player->SendDirectMessage(&data);
|
player->GetSession()->SendPacket(&data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove player from group in DB
|
// Remove player from group in DB
|
||||||
@@ -756,7 +814,7 @@ void Group::ChangeLeader(ObjectGuid newLeaderGuid)
|
|||||||
sScriptMgr->OnGroupChangeLeader(this, newLeaderGuid, m_leaderGuid); // This hook should be executed at the end - Not used anywhere in the original core
|
sScriptMgr->OnGroupChangeLeader(this, newLeaderGuid, m_leaderGuid); // This hook should be executed at the end - Not used anywhere in the original core
|
||||||
}
|
}
|
||||||
|
|
||||||
void Group::Disband(bool hideDestroy /* = false */)
|
void Group::ForcedDisband(bool hideDestroy /* = false */)
|
||||||
{
|
{
|
||||||
sScriptMgr->OnGroupDisband(this);
|
sScriptMgr->OnGroupDisband(this);
|
||||||
|
|
||||||
@@ -852,6 +910,14 @@ void Group::Disband(bool hideDestroy /* = false */)
|
|||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Group::Disband(bool hideDestroy /* = false */)
|
||||||
|
{
|
||||||
|
if (sToCloud9Sidecar->ClusterModeEnabled() && !this->isBFGroup() && !this->isBGGroup())
|
||||||
|
return;
|
||||||
|
|
||||||
|
ForcedDisband(hideDestroy);
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************/
|
/*********************************************************/
|
||||||
/*** LOOT SYSTEM ***/
|
/*** LOOT SYSTEM ***/
|
||||||
/*********************************************************/
|
/*********************************************************/
|
||||||
@@ -1791,6 +1857,12 @@ void Group::SendTargetIconList(WorldSession* session)
|
|||||||
|
|
||||||
void Group::SendUpdate()
|
void Group::SendUpdate()
|
||||||
{
|
{
|
||||||
|
if (sToCloud9Sidecar->ClusterModeEnabled() && !this->isBFGroup() && !this->isBGGroup())
|
||||||
|
{
|
||||||
|
// Group service responsible for sending these updates.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (member_witerator witr = m_memberSlots.begin(); witr != m_memberSlots.end(); ++witr)
|
for (member_witerator witr = m_memberSlots.begin(); witr != m_memberSlots.end(); ++witr)
|
||||||
SendUpdateToPlayer(witr->guid, &(*witr));
|
SendUpdateToPlayer(witr->guid, &(*witr));
|
||||||
}
|
}
|
||||||
@@ -2207,7 +2279,7 @@ void Roll::targetObjectBuildLink()
|
|||||||
void Group::SetDungeonDifficulty(Difficulty difficulty)
|
void Group::SetDungeonDifficulty(Difficulty difficulty)
|
||||||
{
|
{
|
||||||
m_dungeonDifficulty = difficulty;
|
m_dungeonDifficulty = difficulty;
|
||||||
if (!isBGGroup() && !isBFGroup())
|
if (!sToCloud9Sidecar->ClusterModeEnabled() && !isBGGroup() && !isBFGroup())
|
||||||
{
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_DIFFICULTY);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_DIFFICULTY);
|
||||||
|
|
||||||
@@ -2228,7 +2300,7 @@ void Group::SetDungeonDifficulty(Difficulty difficulty)
|
|||||||
void Group::SetRaidDifficulty(Difficulty difficulty)
|
void Group::SetRaidDifficulty(Difficulty difficulty)
|
||||||
{
|
{
|
||||||
m_raidDifficulty = difficulty;
|
m_raidDifficulty = difficulty;
|
||||||
if (!isBGGroup() && !isBFGroup())
|
if (!sToCloud9Sidecar->ClusterModeEnabled() && !isBGGroup() && !isBFGroup())
|
||||||
{
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_RAID_DIFFICULTY);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_GROUP_RAID_DIFFICULTY);
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ class Unit;
|
|||||||
class WorldObject;
|
class WorldObject;
|
||||||
class WorldPacket;
|
class WorldPacket;
|
||||||
class WorldSession;
|
class WorldSession;
|
||||||
|
class ToCloud9GroupHooks;
|
||||||
|
|
||||||
struct MapEntry;
|
struct MapEntry;
|
||||||
|
|
||||||
@@ -174,6 +175,7 @@ public:
|
|||||||
/** todo: uninvite people that not accepted invite **/
|
/** todo: uninvite people that not accepted invite **/
|
||||||
class Group
|
class Group
|
||||||
{
|
{
|
||||||
|
friend class ToCloud9GroupHooks;
|
||||||
public:
|
public:
|
||||||
struct MemberSlot
|
struct MemberSlot
|
||||||
{
|
{
|
||||||
@@ -344,6 +346,9 @@ protected:
|
|||||||
void SubGroupCounterDecrease(uint8 subgroup);
|
void SubGroupCounterDecrease(uint8 subgroup);
|
||||||
void ToggleGroupMemberFlag(member_witerator slot, uint8 flag, bool apply);
|
void ToggleGroupMemberFlag(member_witerator slot, uint8 flag, bool apply);
|
||||||
|
|
||||||
|
void AddMemberWithGuid(ObjectGuid guid);
|
||||||
|
void ForcedDisband(bool hideDestroy = false);
|
||||||
|
|
||||||
MemberSlotList m_memberSlots;
|
MemberSlotList m_memberSlots;
|
||||||
GroupRefMgr m_memberMgr;
|
GroupRefMgr m_memberMgr;
|
||||||
InvitesList m_invitees;
|
InvitesList m_invitees;
|
||||||
|
|||||||
@@ -53,7 +53,11 @@ void GroupMgr::InitGroupIds()
|
|||||||
|
|
||||||
void GroupMgr::RegisterGroupId(ObjectGuid::LowType groupId)
|
void GroupMgr::RegisterGroupId(ObjectGuid::LowType groupId)
|
||||||
{
|
{
|
||||||
// Allocation was done in InitGroupIds()
|
// InitGroupIds() sizes the bitmap to the local MAX(guid) at startup. In cluster mode the
|
||||||
|
// group service assigns ids (auto-increment), which can exceed that bound, so grow on demand.
|
||||||
|
if (groupId >= _groupIds.size())
|
||||||
|
_groupIds.resize(groupId + 1);
|
||||||
|
|
||||||
_groupIds[groupId] = true;
|
_groupIds[groupId] = true;
|
||||||
|
|
||||||
// Groups are pulled in ascending order from db and _nextGroupId is initialized with 1,
|
// Groups are pulled in ascending order from db and _nextGroupId is initialized with 1,
|
||||||
|
|||||||
@@ -18,6 +18,8 @@
|
|||||||
#include "ChannelMgr.h"
|
#include "ChannelMgr.h"
|
||||||
#include "ObjectMgr.h" // for normalizePlayerName
|
#include "ObjectMgr.h" // for normalizePlayerName
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
|
#include "Language.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
|
||||||
void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)
|
void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)
|
||||||
@@ -38,6 +40,23 @@ void WorldSession::HandleJoinChannel(WorldPacket& recvPacket)
|
|||||||
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetPlayer()->GetZoneId());
|
AreaTableEntry const* zone = sAreaTableStore.LookupEntry(GetPlayer()->GetZoneId());
|
||||||
if (!zone || !GetPlayer()->CanJoinConstantChannelInZone(channel, zone))
|
if (!zone || !GetPlayer()->CanJoinConstantChannelInZone(channel, zone))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Cluster mode rebuilds the localized channel name so nodes agree on it;
|
||||||
|
// stock servers keep the client-supplied name.
|
||||||
|
if (sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
|
{
|
||||||
|
auto const locale = GetSessionDbcLocale();
|
||||||
|
std::string const& zoneName = zone->area_name[locale];
|
||||||
|
std::string const cityName = sObjectMgr->GetAcoreStringForDBCLocale(LANG_CHANNEL_CITY);
|
||||||
|
char const* nameExt = (channel->flags & CHANNEL_DBC_FLAG_CITY_ONLY) ? cityName.c_str() : zoneName.c_str();
|
||||||
|
|
||||||
|
std::array<char, 128> buffer{};
|
||||||
|
if (char const* pattern = channel->pattern[locale])
|
||||||
|
{
|
||||||
|
std::snprintf(buffer.data(), buffer.size(), pattern, nameExt);
|
||||||
|
channelName = buffer.data();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channelName.empty())
|
if (channelName.empty())
|
||||||
|
|||||||
@@ -54,6 +54,7 @@
|
|||||||
#include "SpellAuraEffects.h"
|
#include "SpellAuraEffects.h"
|
||||||
#include "SpellAuras.h"
|
#include "SpellAuras.h"
|
||||||
#include "StringConvert.h"
|
#include "StringConvert.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "Tokenize.h"
|
#include "Tokenize.h"
|
||||||
#include "Transport.h"
|
#include "Transport.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
@@ -81,125 +82,126 @@ bool LoginQueryHolder::Initialize()
|
|||||||
SetSize(MAX_PLAYER_LOGIN_QUERY);
|
SetSize(MAX_PLAYER_LOGIN_QUERY);
|
||||||
|
|
||||||
bool res = true;
|
bool res = true;
|
||||||
ObjectGuid::LowType lowGuid = m_guid.GetCounter();
|
uint64 rawGUID = m_guid.GetRawValue();
|
||||||
|
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_FROM, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_FROM, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AURAS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AURAS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_AURAS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_AURAS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELL);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELL);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SPELLS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SPELLS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_DAILYQUESTSTATUS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_DAILYQUESTSTATUS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MONTHLYQUESTSTATUS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MONTHLYQUESTSTATUS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_REPUTATION);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_REPUTATION);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_REPUTATION, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_REPUTATION, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_INVENTORY);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_INVENTORY);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_INVENTORY, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_INVENTORY, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ACTIONS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ACTIONS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAIL);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
|
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MAILS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MAILS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_MAILITEMS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MAIL_ITEMS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SOCIALLIST);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SOCIALLIST);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_HOMEBIND);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_HOMEBIND);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_HOME_BIND, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_HOME_BIND, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS, stmt);
|
||||||
|
|
||||||
if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED))
|
if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED))
|
||||||
{
|
{
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES, stmt);
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACHIEVEMENTS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACHIEVEMENTS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ENTRY_POINT);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ENTRY_POINT);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ENTRY_POINT, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ENTRY_POINT, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GLYPHS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GLYPHS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GLYPHS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GLYPHS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TALENTS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TALENTS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_TALENTS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_TALENTS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PLAYER_ACCOUNT_DATA);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PLAYER_ACCOUNT_DATA);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SKILLS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SKILLS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SKILLS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SKILLS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_RANDOMBG);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_RANDOMBG);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BANNED);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BANNED);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_BANNED, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_BANNED, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_BREW_OF_THE_MONTH);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_BREW_OF_THE_MONTH);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_BREW_OF_THE_MONTH, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_BREW_OF_THE_MONTH, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES);
|
||||||
@@ -207,19 +209,19 @@ bool LoginQueryHolder::Initialize()
|
|||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_LOCATION);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CORPSE_LOCATION);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_SETTINGS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_SETTINGS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CHARACTER_SETTINGS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CHARACTER_SETTINGS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PETS);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_PETS);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_PET_SLOTS, stmt);
|
||||||
|
|
||||||
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_ACHIEVEMENT_OFFLINE_UPDATES);
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHAR_ACHIEVEMENT_OFFLINE_UPDATES);
|
||||||
stmt->SetData(0, lowGuid);
|
stmt->SetData(0, rawGUID);
|
||||||
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_OFFLINE_ACHIEVEMENTS_UPDATES, stmt);
|
res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_OFFLINE_ACHIEVEMENTS_UPDATES, stmt);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@@ -699,7 +701,9 @@ void WorldSession::HandlePlayerLoginOpcode(WorldPacket& recvData)
|
|||||||
ObjectGuid playerGuid;
|
ObjectGuid playerGuid;
|
||||||
recvData >> playerGuid;
|
recvData >> playerGuid;
|
||||||
|
|
||||||
if (!IsLegitCharacterForAccount(playerGuid))
|
// The ownership check is delegated to the gateway in cluster mode, but a
|
||||||
|
// non-player GUID is invalid regardless of who authenticated the session.
|
||||||
|
if (!playerGuid.IsPlayer() || (!sToCloud9Sidecar->ClusterModeEnabled() && !IsLegitCharacterForAccount(playerGuid)))
|
||||||
{
|
{
|
||||||
LOG_ERROR("network", "Account ({}) can't login with that character ({}).", GetAccountId(), playerGuid.ToString());
|
LOG_ERROR("network", "Account ({}) can't login with that character ({}).", GetAccountId(), playerGuid.ToString());
|
||||||
KickPlayer("Account can't login with this character");
|
KickPlayer("Account can't login with this character");
|
||||||
@@ -847,6 +851,8 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder)
|
|||||||
chH.PSendSysMessage("{}", GitRevision::GetFullVersion());
|
chH.PSendSysMessage("{}", GitRevision::GetFullVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
|
{
|
||||||
if (uint32 guildId = sCharacterCache->GetCharacterGuildIdByGuid(pCurrChar->GetGUID()))
|
if (uint32 guildId = sCharacterCache->GetCharacterGuildIdByGuid(pCurrChar->GetGUID()))
|
||||||
{
|
{
|
||||||
Guild* guild = sGuildMgr->GetGuildById(guildId);
|
Guild* guild = sGuildMgr->GetGuildById(guildId);
|
||||||
@@ -870,6 +876,12 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder)
|
|||||||
pCurrChar->SetInGuild(0);
|
pCurrChar->SetInGuild(0);
|
||||||
pCurrChar->SetRank(0);
|
pCurrChar->SetRank(0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pCurrChar->SetInGuild(0);
|
||||||
|
pCurrChar->SetRank(0);
|
||||||
|
}
|
||||||
|
|
||||||
data.Initialize(SMSG_LEARNED_DANCE_MOVES, 4 + 4);
|
data.Initialize(SMSG_LEARNED_DANCE_MOVES, 4 + 4);
|
||||||
data << uint32(0);
|
data << uint32(0);
|
||||||
@@ -914,9 +926,12 @@ void WorldSession::HandlePlayerLoginFromDB(LoginQueryHolder const& holder)
|
|||||||
|
|
||||||
pCurrChar->SendInitialPacketsAfterAddToMap();
|
pCurrChar->SendInitialPacketsAfterAddToMap();
|
||||||
|
|
||||||
|
if (!sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ONLINE);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_CHAR_ONLINE);
|
||||||
stmt->SetData(0, pCurrChar->GetGUID().GetCounter());
|
stmt->SetData(0, pCurrChar->GetGUID().GetCounter());
|
||||||
CharacterDatabase.Execute(stmt);
|
CharacterDatabase.Execute(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
LoginDatabasePreparedStatement* loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_ONLINE);
|
LoginDatabasePreparedStatement* loginStmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_ONLINE);
|
||||||
loginStmt->SetData(0, realm.Id.Realm);
|
loginStmt->SetData(0, realm.Id.Realm);
|
||||||
|
|||||||
@@ -713,6 +713,18 @@ namespace Acore
|
|||||||
|
|
||||||
void WorldSession::HandleTextEmoteOpcode(WorldPacket& recvData)
|
void WorldSession::HandleTextEmoteOpcode(WorldPacket& recvData)
|
||||||
{
|
{
|
||||||
|
uint32 text_emote;
|
||||||
|
recvData >> text_emote;
|
||||||
|
|
||||||
|
constexpr uint32 readyEmote = 126;
|
||||||
|
|
||||||
|
// Handle confirmation redirect when the player types "/ready" after the new node becomes available for redirection.
|
||||||
|
if (text_emote == readyEmote && GetPlayer()->GetMap()->IsPlayerRedirectKickTimerActive())
|
||||||
|
{
|
||||||
|
HandleTC9PrepareForRedirect(recvData);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!GetPlayer()->IsAlive())
|
if (!GetPlayer()->IsAlive())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -728,10 +740,9 @@ void WorldSession::HandleTextEmoteOpcode(WorldPacket& recvData)
|
|||||||
if (GetPlayer()->IsSpectator())
|
if (GetPlayer()->IsSpectator())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32 text_emote, emoteNum;
|
uint32 emoteNum;
|
||||||
ObjectGuid guid;
|
ObjectGuid guid;
|
||||||
|
|
||||||
recvData >> text_emote;
|
|
||||||
recvData >> emoteNum;
|
recvData >> emoteNum;
|
||||||
recvData >> guid;
|
recvData >> guid;
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "SocialMgr.h"
|
#include "SocialMgr.h"
|
||||||
#include "Spell.h"
|
#include "Spell.h"
|
||||||
#include "SpellMgr.h"
|
#include "SpellMgr.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
#include "WorldPacket.h"
|
#include "WorldPacket.h"
|
||||||
#include "WorldSession.h"
|
#include "WorldSession.h"
|
||||||
@@ -505,6 +506,79 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool needsCrossrealmHandling = sToCloud9Sidecar->IsCrossrealm() && _player->GetGUID().GetRealmID() != trader->GetGUID().GetRealmID();
|
||||||
|
|
||||||
|
// Create new items for crossrealm usage.
|
||||||
|
if (needsCrossrealmHandling)
|
||||||
|
{
|
||||||
|
CharacterDatabasePreparedStatement* stmt = nullptr;
|
||||||
|
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||||
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_NO_OP_PROVIDE_REALM_CONTEXT);
|
||||||
|
stmt->SetData(0, _player->GetGUID().GetRealmID());
|
||||||
|
trans->Append(stmt);
|
||||||
|
|
||||||
|
for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; i++)
|
||||||
|
{
|
||||||
|
if (myItems[i])
|
||||||
|
{
|
||||||
|
Item* newItem = myItems[i]->CloneItem(myItems[i]->GetCount(), trader);
|
||||||
|
if (!newItem)
|
||||||
|
{
|
||||||
|
ItemPosCountVec playerDst;
|
||||||
|
if (_player->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, myItems[i], false) == EQUIP_ERR_OK)
|
||||||
|
_player->MoveItemToInventory(playerDst, myItems[i], true, true);
|
||||||
|
|
||||||
|
// Should we handle else statement here?
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
|
||||||
|
stmt->SetData(0, myItems[i]->GetGUID().GetCounter());
|
||||||
|
trans->Append(stmt);
|
||||||
|
|
||||||
|
delete myItems[i];
|
||||||
|
|
||||||
|
myItems[i] = newItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CharacterDatabase.CommitTransaction(trans);
|
||||||
|
|
||||||
|
trans = CharacterDatabase.BeginTransaction();
|
||||||
|
|
||||||
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_NO_OP_PROVIDE_REALM_CONTEXT);
|
||||||
|
stmt->SetData(0, trader->GetGUID().GetRealmID());
|
||||||
|
trans->Append(stmt);
|
||||||
|
|
||||||
|
for (uint8 i = 0; i < TRADE_SLOT_TRADED_COUNT; i++)
|
||||||
|
{
|
||||||
|
if (hisItems[i])
|
||||||
|
{
|
||||||
|
Item* newItem = hisItems[i]->CloneItem(hisItems[i]->GetCount(), _player);
|
||||||
|
if (!newItem)
|
||||||
|
{
|
||||||
|
ItemPosCountVec playerDst;
|
||||||
|
if (trader->CanStoreItem(NULL_BAG, NULL_SLOT, playerDst, hisItems[i], false) == EQUIP_ERR_OK)
|
||||||
|
trader->MoveItemToInventory(playerDst, hisItems[i], true, true);
|
||||||
|
|
||||||
|
// Should we handle else statement here?
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_ITEM_INSTANCE);
|
||||||
|
stmt->SetData(0, hisItems[i]->GetGUID().GetCounter());
|
||||||
|
trans->Append(stmt);
|
||||||
|
|
||||||
|
delete hisItems[i];
|
||||||
|
|
||||||
|
hisItems[i] = newItem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CharacterDatabase.CommitTransaction(trans);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// execute trade: 2. store
|
// execute trade: 2. store
|
||||||
moveItems(myItems, hisItems);
|
moveItems(myItems, hisItems);
|
||||||
|
|
||||||
@@ -575,11 +649,25 @@ void WorldSession::HandleAcceptTradeOpcode(WorldPacket& /*recvPacket*/)
|
|||||||
delete trader->m_trade;
|
delete trader->m_trade;
|
||||||
trader->m_trade = nullptr;
|
trader->m_trade = nullptr;
|
||||||
|
|
||||||
|
// We can't use single transaction with different databases.
|
||||||
|
if (needsCrossrealmHandling)
|
||||||
|
{
|
||||||
|
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||||
|
_player->SaveInventoryAndGoldToDB(trans);
|
||||||
|
CharacterDatabase.CommitTransaction(trans);
|
||||||
|
|
||||||
|
trans = CharacterDatabase.BeginTransaction();
|
||||||
|
trader->SaveInventoryAndGoldToDB(trans);
|
||||||
|
CharacterDatabase.CommitTransaction(trans);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards)
|
// desynchronized with the other saves here (SaveInventoryAndGoldToDB() not have own transaction guards)
|
||||||
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||||
_player->SaveInventoryAndGoldToDB(trans);
|
_player->SaveInventoryAndGoldToDB(trans);
|
||||||
trader->SaveInventoryAndGoldToDB(trans);
|
trader->SaveInventoryAndGoldToDB(trans);
|
||||||
CharacterDatabase.CommitTransaction(trans);
|
CharacterDatabase.CommitTransaction(trans);
|
||||||
|
}
|
||||||
|
|
||||||
info.Status = TRADE_STATUS_TRADE_COMPLETE;
|
info.Status = TRADE_STATUS_TRADE_COMPLETE;
|
||||||
trader->GetSession()->SendTradeStatus(info);
|
trader->GetSession()->SendTradeStatus(info);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "ObjectMgr.h"
|
#include "ObjectMgr.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
#include "Transport.h"
|
#include "Transport.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
@@ -164,6 +165,9 @@ InstanceSave::~InstanceSave()
|
|||||||
|
|
||||||
void InstanceSave::InsertToDB()
|
void InstanceSave::InsertToDB()
|
||||||
{
|
{
|
||||||
|
if (sToCloud9Sidecar->ClusterModeEnabled() && !sToCloud9Sidecar->IsMapAssigned(GetMapId()))
|
||||||
|
return;
|
||||||
|
|
||||||
std::string data;
|
std::string data;
|
||||||
uint32 completedEncounters = 0;
|
uint32 completedEncounters = 0;
|
||||||
|
|
||||||
@@ -454,6 +458,157 @@ void InstanceSaveMgr::LoadCharacterBinds()
|
|||||||
lock_instLists = false;
|
lock_instLists = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Runs on a std::async worker thread. Only the two synchronous CharacterDatabase
|
||||||
|
// reads happen here (safe: the synch connection pool is mutex-guarded per connection).
|
||||||
|
// All manager-state access is deferred to MergeWithNewInstanceSaves on the world thread.
|
||||||
|
InstanceMapLoadRows InstanceSaveMgr::LoadInstanceSavesAndBindsForMapIDs(std::vector<uint32> const& mapIDs)
|
||||||
|
{
|
||||||
|
InstanceMapLoadRows rows;
|
||||||
|
|
||||||
|
std::stringstream mapIDsStr;
|
||||||
|
for (size_t i = 0; i < mapIDs.size(); ++i)
|
||||||
|
{
|
||||||
|
mapIDsStr << mapIDs[i];
|
||||||
|
if (i < mapIDs.size() - 1)
|
||||||
|
mapIDsStr << ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
QueryResult result = CharacterDatabase.Query("SELECT id, map, resettime, difficulty, completedEncounters, data FROM instance WHERE map IN ({}) ORDER BY id ASC", mapIDsStr.str());
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Field* fields = result->Fetch();
|
||||||
|
|
||||||
|
InstanceMapLoadRows::InstanceRow row;
|
||||||
|
row.instanceId = fields[0].Get<uint32>();
|
||||||
|
row.mapId = fields[1].Get<uint16>();
|
||||||
|
row.resetTime = time_t(fields[2].Get<uint32>());
|
||||||
|
row.difficulty = fields[3].Get<uint8>();
|
||||||
|
row.completedEncounters = fields[4].Get<uint32>();
|
||||||
|
row.data = fields[5].Get<std::string>();
|
||||||
|
rows.instances.push_back(std::move(row));
|
||||||
|
} while (result->NextRow());
|
||||||
|
}
|
||||||
|
|
||||||
|
result = CharacterDatabase.Query("SELECT guid, instance, permanent, extended FROM character_instance WHERE instance IN (SELECT id FROM instance WHERE map IN ({}))", mapIDsStr.str());
|
||||||
|
if (result)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
Field* fields = result->Fetch();
|
||||||
|
|
||||||
|
InstanceMapLoadRows::BindRow row;
|
||||||
|
row.guidLow = fields[0].Get<uint32>();
|
||||||
|
row.instanceId = fields[1].Get<uint32>();
|
||||||
|
row.perm = fields[2].Get<bool>();
|
||||||
|
row.extended = fields[3].Get<bool>();
|
||||||
|
rows.binds.push_back(row);
|
||||||
|
} while (result->NextRow());
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runs on the world thread (TC9 async completion callback). Safe to touch
|
||||||
|
// m_instanceSaveById, playerBindStorage, m_resetExtendedTimeByMapDifficulty and MapMgr here.
|
||||||
|
void InstanceSaveMgr::MergeWithNewInstanceSaves(InstanceMapLoadRows const& loadResult)
|
||||||
|
{
|
||||||
|
// Same guard as LoadCharacterBinds: without it, an unbind cascading into
|
||||||
|
// DeleteInstanceSaveIfNeeded would delete the very DB rows being merged.
|
||||||
|
lock_instLists = true;
|
||||||
|
|
||||||
|
for (InstanceMapLoadRows::InstanceRow const& row : loadResult.instances)
|
||||||
|
{
|
||||||
|
MapEntry const* entry = sMapStore.LookupEntry(row.mapId);
|
||||||
|
if (!entry)
|
||||||
|
{
|
||||||
|
LOG_ERROR("instance.save", "InstanceSaveMgr::MergeWithNewInstanceSaves: wrong mapid = {}, instanceid = {}!", row.mapId, row.instanceId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same row validation as AddInstanceSave for rows loaded on reassignment.
|
||||||
|
if (row.instanceId == 0)
|
||||||
|
{
|
||||||
|
LOG_ERROR("instance.save", "InstanceSaveMgr::MergeWithNewInstanceSaves: mapid = {}, wrong instanceid = {}!", row.mapId, row.instanceId);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.difficulty >= (entry->IsRaid() ? MAX_RAID_DIFFICULTY : MAX_DUNGEON_DIFFICULTY))
|
||||||
|
{
|
||||||
|
LOG_ERROR("instance.save", "InstanceSaveMgr::MergeWithNewInstanceSaves: mapid = {}, instanceid = {}, wrong difficulty {}!", row.mapId, row.instanceId, row.difficulty);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t extendedResetTime = 0;
|
||||||
|
if (entry->IsRaid() || row.difficulty > DUNGEON_DIFFICULTY_NORMAL)
|
||||||
|
extendedResetTime = GetExtendedResetTimeFor(row.mapId, Difficulty(row.difficulty));
|
||||||
|
|
||||||
|
InstanceSave* save = new InstanceSave(row.mapId, row.instanceId, Difficulty(row.difficulty), row.resetTime, extendedResetTime);
|
||||||
|
save->SetCompletedEncounterMask(row.completedEncounters);
|
||||||
|
save->SetInstanceData(row.data);
|
||||||
|
if (row.resetTime > 0)
|
||||||
|
save->SetResetTime(row.resetTime);
|
||||||
|
|
||||||
|
InstanceSaveHashMap::iterator currentSave = m_instanceSaveById.find(row.instanceId);
|
||||||
|
if (currentSave != m_instanceSaveById.end())
|
||||||
|
{
|
||||||
|
InstanceSave* oldSave = currentSave->second;
|
||||||
|
|
||||||
|
// Unbind every player still pointing at the stale save before it is
|
||||||
|
// freed, in-memory only: the DB rows were just refetched and are
|
||||||
|
// rebound below. Iterate a copy, PlayerUnbindInstance mutates the list.
|
||||||
|
GuidList players = oldSave->m_playerList;
|
||||||
|
for (ObjectGuid const& playerGuid : players)
|
||||||
|
PlayerUnbindInstance(playerGuid, oldSave->GetMapId(), oldSave->GetDifficulty(), false);
|
||||||
|
|
||||||
|
m_instanceSaveById.erase(currentSave);
|
||||||
|
delete oldSave;
|
||||||
|
}
|
||||||
|
m_instanceSaveById[row.instanceId] = save;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (InstanceMapLoadRows::BindRow const& row : loadResult.binds)
|
||||||
|
{
|
||||||
|
InstanceSaveHashMap::iterator itr = m_instanceSaveById.find(row.instanceId);
|
||||||
|
InstanceSave* save = itr != m_instanceSaveById.end() ? itr->second : nullptr;
|
||||||
|
if (!save)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ObjectGuid guid = ObjectGuid::Create<HighGuid::Player>(row.guidLow);
|
||||||
|
|
||||||
|
PlayerCreateBoundInstancesMaps(guid);
|
||||||
|
InstancePlayerBind& bind = playerBindStorage[guid]->m[save->GetDifficulty()][save->GetMapId()];
|
||||||
|
if (bind.save) // pussywizard: another bind for the same map and difficulty! may happen because of mysql thread races
|
||||||
|
{
|
||||||
|
if (bind.perm) // already loaded perm -> delete currently checked one from db
|
||||||
|
{
|
||||||
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID);
|
||||||
|
stmt->SetData(0, guid.GetCounter());
|
||||||
|
stmt->SetData(1, row.instanceId);
|
||||||
|
CharacterDatabase.Execute(stmt);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else // override temp bind by newest one
|
||||||
|
{
|
||||||
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_INSTANCE_BY_INSTANCE_GUID);
|
||||||
|
stmt->SetData(0, guid.GetCounter());
|
||||||
|
stmt->SetData(1, bind.save->GetInstanceId());
|
||||||
|
CharacterDatabase.Execute(stmt);
|
||||||
|
bind.save->RemovePlayer(guid, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bind.save = save;
|
||||||
|
bind.perm = row.perm;
|
||||||
|
bind.extended = row.extended;
|
||||||
|
save->AddPlayer(guid);
|
||||||
|
if (row.perm)
|
||||||
|
save->SetCanReset(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_instLists = false;
|
||||||
|
}
|
||||||
|
|
||||||
void InstanceSaveMgr::ScheduleReset(time_t time, InstResetEvent event)
|
void InstanceSaveMgr::ScheduleReset(time_t time, InstResetEvent event)
|
||||||
{
|
{
|
||||||
m_resetTimeQueue.insert(std::pair<time_t, InstResetEvent>(time, event));
|
m_resetTimeQueue.insert(std::pair<time_t, InstResetEvent>(time, event));
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include <map>
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
struct InstanceTemplate;
|
struct InstanceTemplate;
|
||||||
struct MapEntry;
|
struct MapEntry;
|
||||||
@@ -103,6 +104,31 @@ private:
|
|||||||
|
|
||||||
typedef std::unordered_map<uint32 /*PAIR32(map, difficulty)*/, time_t /*resetTime*/> ResetTimeByMapDifficultyMap;
|
typedef std::unordered_map<uint32 /*PAIR32(map, difficulty)*/, time_t /*resetTime*/> ResetTimeByMapDifficultyMap;
|
||||||
|
|
||||||
|
// Raw rows fetched on a worker thread by LoadInstanceSavesAndBindsForMapIDs.
|
||||||
|
// Contains no manager-owned state, so it is safe to build off the world thread
|
||||||
|
// and consume later on the world thread in MergeWithNewInstanceSaves.
|
||||||
|
struct InstanceMapLoadRows
|
||||||
|
{
|
||||||
|
struct InstanceRow
|
||||||
|
{
|
||||||
|
uint32 instanceId;
|
||||||
|
uint16 mapId;
|
||||||
|
time_t resetTime;
|
||||||
|
uint8 difficulty;
|
||||||
|
uint32 completedEncounters;
|
||||||
|
std::string data;
|
||||||
|
};
|
||||||
|
struct BindRow
|
||||||
|
{
|
||||||
|
uint32 guidLow;
|
||||||
|
uint32 instanceId;
|
||||||
|
bool perm;
|
||||||
|
bool extended;
|
||||||
|
};
|
||||||
|
std::vector<InstanceRow> instances;
|
||||||
|
std::vector<BindRow> binds;
|
||||||
|
};
|
||||||
|
|
||||||
class InstanceSaveMgr
|
class InstanceSaveMgr
|
||||||
{
|
{
|
||||||
friend class InstanceSave;
|
friend class InstanceSave;
|
||||||
@@ -133,6 +159,11 @@ public:
|
|||||||
void LoadInstanceSaves();
|
void LoadInstanceSaves();
|
||||||
void LoadCharacterBinds();
|
void LoadCharacterBinds();
|
||||||
|
|
||||||
|
// Worker thread: performs only the (blocking) DB reads, touches no manager state.
|
||||||
|
[[nodiscard]] InstanceMapLoadRows LoadInstanceSavesAndBindsForMapIDs(std::vector<uint32> const& mapIDs);
|
||||||
|
// World thread: builds InstanceSaves and player binds from the fetched rows and merges them in.
|
||||||
|
void MergeWithNewInstanceSaves(InstanceMapLoadRows const& loadResult);
|
||||||
|
|
||||||
[[nodiscard]] time_t GetResetTimeFor(uint32 mapid, Difficulty d) const
|
[[nodiscard]] time_t GetResetTimeFor(uint32 mapid, Difficulty d) const
|
||||||
{
|
{
|
||||||
ResetTimeByMapDifficultyMap::const_iterator itr = m_resetTimeByMapDifficulty.find(MAKE_PAIR32(mapid, d));
|
ResetTimeByMapDifficultyMap::const_iterator itr = m_resetTimeByMapDifficulty.find(MAKE_PAIR32(mapid, d));
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "RBAC.h"
|
#include "RBAC.h"
|
||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
#include "Spell.h"
|
#include "Spell.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "WorldSession.h"
|
#include "WorldSession.h"
|
||||||
|
|
||||||
BossBoundaryData::~BossBoundaryData()
|
BossBoundaryData::~BossBoundaryData()
|
||||||
@@ -41,6 +42,9 @@ BossBoundaryData::~BossBoundaryData()
|
|||||||
|
|
||||||
void InstanceScript::SaveToDB()
|
void InstanceScript::SaveToDB()
|
||||||
{
|
{
|
||||||
|
if (sToCloud9Sidecar->ClusterModeEnabled() && !sToCloud9Sidecar->IsMapAssigned(instance->GetEntry()->MapID))
|
||||||
|
return;
|
||||||
|
|
||||||
std::string data = GetSaveData();
|
std::string data = GetSaveData();
|
||||||
//if (data.empty()) // pussywizard: encounterMask can be updated and theres no reason to not save
|
//if (data.empty()) // pussywizard: encounterMask can be updated and theres no reason to not save
|
||||||
// return;
|
// return;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
#include "Pet.h"
|
#include "Pet.h"
|
||||||
#include "PoolMgr.h"
|
#include "PoolMgr.h"
|
||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "Transport.h"
|
#include "Transport.h"
|
||||||
#include "VMapFactory.h"
|
#include "VMapFactory.h"
|
||||||
#include "Vehicle.h"
|
#include "Vehicle.h"
|
||||||
@@ -518,6 +519,8 @@ void Map::Update(const uint32 t_diff, const uint32 s_diff, bool /*thread*/)
|
|||||||
|
|
||||||
HandleDelayedVisibility();
|
HandleDelayedVisibility();
|
||||||
|
|
||||||
|
UpdatePlayersRedirectKickEvent(t_diff);
|
||||||
|
|
||||||
UpdateWeather(t_diff);
|
UpdateWeather(t_diff);
|
||||||
UpdateExpiredCorpses(t_diff);
|
UpdateExpiredCorpses(t_diff);
|
||||||
|
|
||||||
@@ -1670,7 +1673,7 @@ void Map::SendInitTransports(Player* player)
|
|||||||
// Hack to send out transports
|
// Hack to send out transports
|
||||||
UpdateData transData;
|
UpdateData transData;
|
||||||
for (TransportsContainer::const_iterator itr = _transports.begin(); itr != _transports.end(); ++itr)
|
for (TransportsContainer::const_iterator itr = _transports.begin(); itr != _transports.end(); ++itr)
|
||||||
if (*itr != player->GetTransport())
|
if (*itr != player->GetTransport() && (!sToCloud9Sidecar->ClusterModeEnabled() || player->InSamePhase(*itr)))
|
||||||
(*itr)->BuildCreateUpdateBlockForPlayer(&transData, player);
|
(*itr)->BuildCreateUpdateBlockForPlayer(&transData, player);
|
||||||
|
|
||||||
if (!transData.HasData())
|
if (!transData.HasData())
|
||||||
@@ -1848,6 +1851,50 @@ uint32 Map::GetPlayersCountExceptGMs(bool aliveOnly /*= false*/) const
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Map::StartPlayersRedirectKickTimer()
|
||||||
|
{
|
||||||
|
for (MapRefMgr::iterator itr = m_mapRefMgr.begin(); itr != m_mapRefMgr.end(); ++itr)
|
||||||
|
itr->GetSource()->SendSystemMessage("Preparing to enter parallel dimension... One minute!\nAccelerate transfer: Teleport or type \"/ready\" in chat.");
|
||||||
|
|
||||||
|
_redirectKickTimer.Reset(60 * SECOND * IN_MILLISECONDS);
|
||||||
|
_lastAnnounceRedirectKickTimer.Reset(55 * SECOND * IN_MILLISECONDS);
|
||||||
|
|
||||||
|
_lastAnnounceRedirectKickTimer.Update(1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Map::StopPlayersRedirectKickTimer()
|
||||||
|
{
|
||||||
|
_redirectKickTimer.Reset(0);
|
||||||
|
_lastAnnounceRedirectKickTimer.Reset(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Map::UpdatePlayersRedirectKickEvent(uint32 diff)
|
||||||
|
{
|
||||||
|
if (_redirectKickTimer.Passed())
|
||||||
|
return;
|
||||||
|
|
||||||
|
_redirectKickTimer.Update(diff);
|
||||||
|
|
||||||
|
if (_redirectKickTimer.Passed())
|
||||||
|
{
|
||||||
|
auto emptyPacket = WorldPacket();
|
||||||
|
for (MapRefMgr::iterator itr = m_mapRefMgr.begin(); itr != m_mapRefMgr.end(); ++itr)
|
||||||
|
itr->GetSource()->GetSession()->HandleTC9PrepareForRedirect(emptyPacket);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_lastAnnounceRedirectKickTimer.Passed())
|
||||||
|
return;
|
||||||
|
|
||||||
|
_lastAnnounceRedirectKickTimer.Update(diff);
|
||||||
|
|
||||||
|
if (_lastAnnounceRedirectKickTimer.Passed())
|
||||||
|
for (MapRefMgr::iterator itr = m_mapRefMgr.begin(); itr != m_mapRefMgr.end(); ++itr)
|
||||||
|
itr->GetSource()->SendSystemMessage("Dimensional shift incoming! Prepare to transition in 5 seconds...");
|
||||||
|
}
|
||||||
|
|
||||||
void Map::SendToPlayers(WorldPacket const* data) const
|
void Map::SendToPlayers(WorldPacket const* data) const
|
||||||
{
|
{
|
||||||
for (MapRefMgr::const_iterator itr = m_mapRefMgr.begin(); itr != m_mapRefMgr.end(); ++itr)
|
for (MapRefMgr::const_iterator itr = m_mapRefMgr.begin(); itr != m_mapRefMgr.end(); ++itr)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "GameObjectModel.h"
|
#include "GameObjectModel.h"
|
||||||
#include "GridDefines.h"
|
#include "GridDefines.h"
|
||||||
#include "GridRefMgr.h"
|
#include "GridRefMgr.h"
|
||||||
|
#include "Timer.h"
|
||||||
#include "MapCollisionData.h"
|
#include "MapCollisionData.h"
|
||||||
#include "MapGridManager.h"
|
#include "MapGridManager.h"
|
||||||
#include "MapRefMgr.h"
|
#include "MapRefMgr.h"
|
||||||
@@ -325,6 +326,10 @@ public:
|
|||||||
|
|
||||||
void SendToPlayers(WorldPacket const* data) const;
|
void SendToPlayers(WorldPacket const* data) const;
|
||||||
|
|
||||||
|
void StartPlayersRedirectKickTimer();
|
||||||
|
void StopPlayersRedirectKickTimer();
|
||||||
|
bool IsPlayerRedirectKickTimerActive() { return !_redirectKickTimer.Passed(); }
|
||||||
|
|
||||||
typedef MapRefMgr PlayerList;
|
typedef MapRefMgr PlayerList;
|
||||||
[[nodiscard]] PlayerList const& GetPlayers() const { return m_mapRefMgr; }
|
[[nodiscard]] PlayerList const& GetPlayers() const { return m_mapRefMgr; }
|
||||||
|
|
||||||
@@ -585,6 +590,8 @@ private:
|
|||||||
|
|
||||||
void SendObjectUpdates();
|
void SendObjectUpdates();
|
||||||
|
|
||||||
|
void UpdatePlayersRedirectKickEvent(uint32 diff);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Type specific code for add/remove to/from grid
|
// Type specific code for add/remove to/from grid
|
||||||
template<class T>
|
template<class T>
|
||||||
@@ -693,6 +700,9 @@ private:
|
|||||||
PendingAddUpdatableObjectList _pendingAddUpdatableObjectList;
|
PendingAddUpdatableObjectList _pendingAddUpdatableObjectList;
|
||||||
IntervalTimer _updatableObjectListRecheckTimer;
|
IntervalTimer _updatableObjectListRecheckTimer;
|
||||||
ZoneWideVisibleWorldObjectsMap _zoneWideVisibleWorldObjectsMap;
|
ZoneWideVisibleWorldObjectsMap _zoneWideVisibleWorldObjectsMap;
|
||||||
|
|
||||||
|
TimeTrackerSmall _redirectKickTimer;
|
||||||
|
TimeTrackerSmall _lastAnnounceRedirectKickTimer;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum InstanceResetMethod
|
enum InstanceResetMethod
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "Opcodes.h"
|
#include "Opcodes.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "ScriptMgr.h"
|
#include "ScriptMgr.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "Transport.h"
|
#include "Transport.h"
|
||||||
#include "World.h"
|
#include "World.h"
|
||||||
#include "WorldPacket.h"
|
#include "WorldPacket.h"
|
||||||
@@ -405,6 +406,9 @@ void MapMgr::RegisterInstanceId(uint32 instanceId)
|
|||||||
|
|
||||||
uint32 MapMgr::GenerateInstanceId()
|
uint32 MapMgr::GenerateInstanceId()
|
||||||
{
|
{
|
||||||
|
if (sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
|
return sToCloud9Sidecar->GenerateInstanceGuid();
|
||||||
|
|
||||||
uint32 newInstanceId = _nextInstanceId;
|
uint32 newInstanceId = _nextInstanceId;
|
||||||
|
|
||||||
// find the lowest available id starting from the current _nextInstanceId
|
// find the lowest available id starting from the current _nextInstanceId
|
||||||
|
|||||||
@@ -21,6 +21,9 @@
|
|||||||
#include "MoveSpline.h"
|
#include "MoveSpline.h"
|
||||||
#include "QueryResult.h"
|
#include "QueryResult.h"
|
||||||
#include "Transport.h"
|
#include "Transport.h"
|
||||||
|
#include "TaskScheduler.h"
|
||||||
|
#include "Config.h"
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
TransportTemplate::~TransportTemplate()
|
TransportTemplate::~TransportTemplate()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1439,6 +1439,8 @@ void OpcodeTable::Initialize()
|
|||||||
/*0x51C*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1, STATUS_NEVER);
|
/*0x51C*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1, STATUS_NEVER);
|
||||||
/*0x51D*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2, STATUS_NEVER);
|
/*0x51D*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2, STATUS_NEVER);
|
||||||
/*0x51E*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MULTIPLE_MOVES, STATUS_NEVER);
|
/*0x51E*/ DEFINE_SERVER_OPCODE_HANDLER(SMSG_MULTIPLE_MOVES, STATUS_NEVER);
|
||||||
|
/*0x51F*/ DEFINE_HANDLER(TC9_CMSG_PREPARE_FOR_REDIRECT, STATUS_AUTHED, PROCESS_THREADUNSAFE, &WorldSession::HandleTC9PrepareForRedirect);
|
||||||
|
/*0x520*/ DEFINE_SERVER_OPCODE_HANDLER(TC9_SMSG_READY_FOR_REDIRECT, STATUS_NEVER);
|
||||||
|
|
||||||
#undef DEFINE_HANDLER
|
#undef DEFINE_HANDLER
|
||||||
#undef DEFINE_SERVER_OPCODE_HANDLER
|
#undef DEFINE_SERVER_OPCODE_HANDLER
|
||||||
|
|||||||
@@ -1338,7 +1338,9 @@ enum Opcodes : uint16
|
|||||||
SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1 = 0x51C,
|
SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT1 = 0x51C,
|
||||||
SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2 = 0x51D,
|
SMSG_COMMENTATOR_SKIRMISH_QUEUE_RESULT2 = 0x51D,
|
||||||
SMSG_MULTIPLE_MOVES = 0x51E, // uncompressed version of SMSG_COMPRESSED_MOVES
|
SMSG_MULTIPLE_MOVES = 0x51E, // uncompressed version of SMSG_COMPRESSED_MOVES
|
||||||
NUM_MSG_TYPES = 0x51F
|
TC9_CMSG_PREPARE_FOR_REDIRECT = 0x51F,
|
||||||
|
TC9_SMSG_READY_FOR_REDIRECT = 0x520,
|
||||||
|
NUM_MSG_TYPES = 0x521
|
||||||
};
|
};
|
||||||
|
|
||||||
enum OpcodeMisc : uint16
|
enum OpcodeMisc : uint16
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
\ingroup u2w
|
\ingroup u2w
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "WorldSession.h"
|
#include "WorldSession.h"
|
||||||
#include "AccountMgr.h"
|
#include "AccountMgr.h"
|
||||||
#include "BattlegroundMgr.h"
|
#include "BattlegroundMgr.h"
|
||||||
@@ -673,7 +674,7 @@ void WorldSession::SendPlayTimeWarning(PlayTimeFlag flag, int32 playTimeRemainin
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// %Log the player out
|
/// %Log the player out
|
||||||
void WorldSession::LogoutPlayer(bool save)
|
void WorldSession::LogoutPlayer(bool save, bool redirecting)
|
||||||
{
|
{
|
||||||
// finish pending transfers before starting the logout
|
// finish pending transfers before starting the logout
|
||||||
while (_player && _player->IsBeingTeleportedFar())
|
while (_player && _player->IsBeingTeleportedFar())
|
||||||
@@ -759,6 +760,8 @@ void WorldSession::LogoutPlayer(bool save)
|
|||||||
// there are some positive auras from boss encounters that can be kept by logging out and logging in after boss is dead, and may be used on next bosses
|
// there are some positive auras from boss encounters that can be kept by logging out and logging in after boss is dead, and may be used on next bosses
|
||||||
_player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP);
|
_player->RemoveAurasWithInterruptFlags(AURA_INTERRUPT_FLAG_CHANGE_MAP);
|
||||||
|
|
||||||
|
if (!redirecting)
|
||||||
|
{
|
||||||
if (Group *group = _player->GetGroupInvite())
|
if (Group *group = _player->GetGroupInvite())
|
||||||
sWorld->getBoolConfig(CONFIG_LEAVE_GROUP_ON_LOGOUT)
|
sWorld->getBoolConfig(CONFIG_LEAVE_GROUP_ON_LOGOUT)
|
||||||
? _player->UninviteFromGroup() // Can disband group.
|
? _player->UninviteFromGroup() // Can disband group.
|
||||||
@@ -766,7 +769,7 @@ void WorldSession::LogoutPlayer(bool save)
|
|||||||
|
|
||||||
// remove player from the group if he is:
|
// remove player from the group if he is:
|
||||||
// a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) d) LeaveGroupOnLogout is enabled
|
// a) in group; b) not in raid group; c) logging out normally (not being kicked or disconnected) d) LeaveGroupOnLogout is enabled
|
||||||
if (_player->GetGroup() && !_player->GetGroup()->isRaidGroup() && !_player->GetGroup()->isLFGGroup() && m_Socket && sWorld->getBoolConfig(CONFIG_LEAVE_GROUP_ON_LOGOUT))
|
if (!sToCloud9Sidecar->ClusterModeEnabled() && _player->GetGroup() && !_player->GetGroup()->isRaidGroup() && !_player->GetGroup()->isLFGGroup() && m_Socket && sWorld->getBoolConfig(CONFIG_LEAVE_GROUP_ON_LOGOUT))
|
||||||
_player->RemoveFromGroup();
|
_player->RemoveFromGroup();
|
||||||
// Remove player from active loot rolls in LFG groups (player stays in group but should not block rolls)
|
// Remove player from active loot rolls in LFG groups (player stays in group but should not block rolls)
|
||||||
else if (Group* group = _player->GetGroup())
|
else if (Group* group = _player->GetGroup())
|
||||||
@@ -776,6 +779,7 @@ void WorldSession::LogoutPlayer(bool save)
|
|||||||
// pussywizard: checked second time after being removed from a group
|
// pussywizard: checked second time after being removed from a group
|
||||||
if (!_player->IsBeingTeleportedFar() && !_player->m_InstanceValid && !_player->IsGameMaster())
|
if (!_player->IsBeingTeleportedFar() && !_player->m_InstanceValid && !_player->IsGameMaster())
|
||||||
_player->RepopAtGraveyard();
|
_player->RepopAtGraveyard();
|
||||||
|
}
|
||||||
|
|
||||||
// Repop at Graveyard or other player far teleport will prevent saving player because of not present map
|
// Repop at Graveyard or other player far teleport will prevent saving player because of not present map
|
||||||
// Teleport player immediately for correct player save
|
// Teleport player immediately for correct player save
|
||||||
@@ -814,12 +818,15 @@ void WorldSession::LogoutPlayer(bool save)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!redirecting)
|
||||||
|
{
|
||||||
//! Broadcast a logout message to the player's friends
|
//! Broadcast a logout message to the player's friends
|
||||||
sSocialMgr->SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUID(), true);
|
sSocialMgr->SendFriendStatus(_player, FRIEND_OFFLINE, _player->GetGUID(), true);
|
||||||
sSocialMgr->RemovePlayerSocial(_player->GetGUID());
|
sSocialMgr->RemovePlayerSocial(_player->GetGUID());
|
||||||
|
|
||||||
//! Call script hook before deletion
|
//! Call script hook before deletion
|
||||||
sScriptMgr->OnPlayerLogout(_player);
|
sScriptMgr->OnPlayerLogout(_player);
|
||||||
|
}
|
||||||
|
|
||||||
METRIC_EVENT("player_events", "Logout", _player->GetName());
|
METRIC_EVENT("player_events", "Logout", _player->GetName());
|
||||||
|
|
||||||
@@ -845,10 +852,13 @@ void WorldSession::LogoutPlayer(bool save)
|
|||||||
LOG_DEBUG("network", "SESSION: Sent SMSG_LOGOUT_COMPLETE Message");
|
LOG_DEBUG("network", "SESSION: Sent SMSG_LOGOUT_COMPLETE Message");
|
||||||
|
|
||||||
//! Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline
|
//! Since each account can only have one online character at any given time, ensure all characters for active account are marked as offline
|
||||||
|
if (!redirecting)
|
||||||
|
{
|
||||||
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_ONLINE);
|
CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ACCOUNT_ONLINE);
|
||||||
stmt->SetData(0, GetAccountId());
|
stmt->SetData(0, GetAccountId());
|
||||||
CharacterDatabase.Execute(stmt);
|
CharacterDatabase.Execute(stmt);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_playerLogout = false;
|
m_playerLogout = false;
|
||||||
m_playerSave = false;
|
m_playerSave = false;
|
||||||
@@ -1563,6 +1573,8 @@ void WorldSession::InitializeSessionCallback(CharacterDatabaseQueryHolder const&
|
|||||||
LoadAccountData(realmHolder.GetPreparedResult(AccountInfoQueryHolderPerRealm::GLOBAL_ACCOUNT_DATA), GLOBAL_CACHE_MASK);
|
LoadAccountData(realmHolder.GetPreparedResult(AccountInfoQueryHolderPerRealm::GLOBAL_ACCOUNT_DATA), GLOBAL_CACHE_MASK);
|
||||||
LoadTutorialsData(realmHolder.GetPreparedResult(AccountInfoQueryHolderPerRealm::TUTORIALS));
|
LoadTutorialsData(realmHolder.GetPreparedResult(AccountInfoQueryHolderPerRealm::TUTORIALS));
|
||||||
|
|
||||||
|
if (!sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
|
{
|
||||||
if (!m_inQueue)
|
if (!m_inQueue)
|
||||||
{
|
{
|
||||||
SendAuthResponse(AUTH_OK, true);
|
SendAuthResponse(AUTH_OK, true);
|
||||||
@@ -1571,13 +1583,59 @@ void WorldSession::InitializeSessionCallback(CharacterDatabaseQueryHolder const&
|
|||||||
{
|
{
|
||||||
SendAuthWaitQueue(0);
|
SendAuthWaitQueue(0);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SetInQueue(false);
|
SetInQueue(false);
|
||||||
ResetTimeOutTime(false);
|
ResetTimeOutTime(false);
|
||||||
|
|
||||||
|
if (!sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
|
{
|
||||||
SendAddonsInfo();
|
SendAddonsInfo();
|
||||||
SendClientCacheVersion(clientCacheVersion);
|
SendClientCacheVersion(clientCacheVersion);
|
||||||
SendTutorialsData();
|
SendTutorialsData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WorldSession::HandleTC9PrepareForRedirect(WorldPacket& /*recvData*/)
|
||||||
|
{
|
||||||
|
if (!sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
Player* player = this->GetPlayer();
|
||||||
|
if (player == nullptr)
|
||||||
|
{
|
||||||
|
WorldPacket data(TC9_SMSG_READY_FOR_REDIRECT, 1);
|
||||||
|
data << uint8(1); // 1 - Failed.
|
||||||
|
SendPacket(&data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("network", "Starting saving, AccountId = {}", GetAccountId());
|
||||||
|
|
||||||
|
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||||
|
player->SaveToDB(trans, false, true);
|
||||||
|
AddTransactionCallback(CharacterDatabase.AsyncCommitTransaction(trans)).AfterComplete([this](bool success)
|
||||||
|
{
|
||||||
|
WorldPacket data(TC9_SMSG_READY_FOR_REDIRECT, 1);
|
||||||
|
data << uint8(!success); // 0 - Success, 1 - Failed.
|
||||||
|
SendPacket(&data);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
LOG_ERROR("network", "Failed to save player, AccountId = {}", GetAccountId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG("network", "Saved, AccountId = {}", GetAccountId());
|
||||||
|
|
||||||
|
Player* player = GetPlayer();
|
||||||
|
if (!player)
|
||||||
|
return;
|
||||||
|
|
||||||
|
player->m_Events.AddEventAtOffset([this](){
|
||||||
|
KickPlayer("HandlePrepareForRedirect client redirected");
|
||||||
|
}, 100ms);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void WorldSession::SetPacketLogging(bool state)
|
void WorldSession::SetPacketLogging(bool state)
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ public:
|
|||||||
return (_logoutTime > 0 && currTime >= _logoutTime + 20);
|
return (_logoutTime > 0 && currTime >= _logoutTime + 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogoutPlayer(bool save);
|
void LogoutPlayer(bool save, bool redirecting = false);
|
||||||
void KickPlayer(bool setKicked = true) { return this->KickPlayer("Unknown reason", setKicked); }
|
void KickPlayer(bool setKicked = true) { return this->KickPlayer("Unknown reason", setKicked); }
|
||||||
void KickPlayer(std::string const& reason, bool setKicked = true);
|
void KickPlayer(std::string const& reason, bool setKicked = true);
|
||||||
|
|
||||||
@@ -687,6 +687,8 @@ public: // opcodes handlers
|
|||||||
void SendCharFactionChange(ResponseCodes result, CharacterFactionChangeInfo const* factionChangeInfo);
|
void SendCharFactionChange(ResponseCodes result, CharacterFactionChangeInfo const* factionChangeInfo);
|
||||||
void SendSetPlayerDeclinedNamesResult(DeclinedNameResult result, ObjectGuid guid);
|
void SendSetPlayerDeclinedNamesResult(DeclinedNameResult result, ObjectGuid guid);
|
||||||
|
|
||||||
|
void HandleTC9PrepareForRedirect(WorldPacket& recvData);
|
||||||
|
|
||||||
// played time
|
// played time
|
||||||
void HandlePlayedTime(WorldPackets::Character::PlayedTimeClient& packet);
|
void HandlePlayedTime(WorldPackets::Character::PlayedTimeClient& packet);
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "WorldSocket.h"
|
#include "WorldSocket.h"
|
||||||
#include "AccountMgr.h"
|
#include "AccountMgr.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
@@ -579,6 +580,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<ClientAuthSession> a
|
|||||||
LoginDatabase.Execute(stmt);
|
LoginDatabase.Execute(stmt);
|
||||||
// This also allows to check for possible "hack" attempts on account
|
// This also allows to check for possible "hack" attempts on account
|
||||||
|
|
||||||
|
if (!sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
// even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it
|
// even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it
|
||||||
_authCrypt.Init(account.SessionKey);
|
_authCrypt.Init(account.SessionKey);
|
||||||
|
|
||||||
@@ -591,7 +593,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<ClientAuthSession> a
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authSession->RealmID != realm.Id.Realm)
|
if (!sToCloud9Sidecar->ClusterModeEnabled() && authSession->RealmID != realm.Id.Realm)
|
||||||
{
|
{
|
||||||
SendAuthResponseError(REALM_LIST_REALM_NOT_FOUND);
|
SendAuthResponseError(REALM_LIST_REALM_NOT_FOUND);
|
||||||
LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} requested connecting with realm id {} but this realm has id {} set in config.",
|
LOG_ERROR("network", "WorldSocket::HandleAuthSession: Client {} requested connecting with realm id {} but this realm has id {} set in config.",
|
||||||
@@ -600,8 +602,10 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<ClientAuthSession> a
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be done before WorldSession is created
|
|
||||||
bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
|
bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
|
||||||
|
if (!sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
|
{
|
||||||
|
// Must be done before WorldSession is created
|
||||||
if (wardenActive && account.OS != "Win" && account.OS != "OSX")
|
if (wardenActive && account.OS != "Win" && account.OS != "OSX")
|
||||||
{
|
{
|
||||||
SendAuthResponseError(AUTH_REJECT);
|
SendAuthResponseError(AUTH_REJECT);
|
||||||
@@ -696,8 +700,8 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<ClientAuthSession> a
|
|||||||
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP);
|
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LAST_IP);
|
||||||
stmt->SetData(0, address);
|
stmt->SetData(0, address);
|
||||||
stmt->SetData(1, authSession->Account);
|
stmt->SetData(1, authSession->Account);
|
||||||
|
|
||||||
LoginDatabase.Execute(stmt);
|
LoginDatabase.Execute(stmt);
|
||||||
|
}
|
||||||
|
|
||||||
// At this point, we can safely hook a successful login
|
// At this point, we can safely hook a successful login
|
||||||
sScriptMgr->OnAccountLogin(account.Id);
|
sScriptMgr->OnAccountLogin(account.Id);
|
||||||
@@ -712,8 +716,9 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<ClientAuthSession> a
|
|||||||
_worldSession->ReadAddonsInfo(authSession->AddonInfo);
|
_worldSession->ReadAddonsInfo(authSession->AddonInfo);
|
||||||
|
|
||||||
// Initialize Warden system only if it is enabled by config
|
// Initialize Warden system only if it is enabled by config
|
||||||
if (wardenActive)
|
if (!sToCloud9Sidecar->ClusterModeEnabled() && wardenActive)
|
||||||
{
|
{
|
||||||
|
// TODO: move warden outside of a node?
|
||||||
_worldSession->InitWarden(account.SessionKey, account.OS);
|
_worldSession->InitWarden(account.SessionKey, account.OS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _ASYNC_TASK_H
|
||||||
|
#define _ASYNC_TASK_H
|
||||||
|
|
||||||
|
#include "Errors.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include <chrono>
|
||||||
|
#include <functional>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class AsyncTask
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using AsyncFunction = std::function<T()>;
|
||||||
|
using CallbackFunction = std::function<void(T)>;
|
||||||
|
|
||||||
|
AsyncTask(AsyncFunction asyncFunc, CallbackFunction callbackFunc)
|
||||||
|
: asyncFunc(std::move(asyncFunc)), callbackFunc(std::move(callbackFunc)), isReady(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~AsyncTask()
|
||||||
|
{
|
||||||
|
// Ensure that the asynchronous task has completed before destruction
|
||||||
|
if (asyncTask.valid() && asyncTask.wait_for(std::chrono::seconds(0)) != std::future_status::ready)
|
||||||
|
{
|
||||||
|
asyncTask.wait(); // Wait for the task to complete
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InvokeIfReady()
|
||||||
|
{
|
||||||
|
if (!isReady)
|
||||||
|
{
|
||||||
|
// Check if the asynchronous task is ready
|
||||||
|
if (asyncTask.valid() && asyncTask.wait_for(std::chrono::seconds(0)) == std::future_status::ready)
|
||||||
|
{
|
||||||
|
// get() rethrows anything the async function threw. Swallowing it
|
||||||
|
// would wedge the cluster handoff (the completion callback signals
|
||||||
|
// map readiness to the registry), so fail fast with context and let
|
||||||
|
// the registry's crash recovery rebalance this node.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
callbackFunc(asyncTask.get());
|
||||||
|
}
|
||||||
|
catch (std::exception const& e)
|
||||||
|
{
|
||||||
|
LOG_ERROR("server.tc9", "AsyncTask failed: {}", e.what());
|
||||||
|
ABORT("AsyncTask failed: {}", e.what());
|
||||||
|
}
|
||||||
|
isReady = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExecuteAsync()
|
||||||
|
{
|
||||||
|
// Capture the function by value so a moved AsyncTask does not leave
|
||||||
|
// the in-flight async holding a dangling this pointer.
|
||||||
|
AsyncFunction fn = asyncFunc;
|
||||||
|
asyncTask = std::async(std::launch::async, [fn = std::move(fn)]() mutable
|
||||||
|
{
|
||||||
|
return fn();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AsyncFunction asyncFunc;
|
||||||
|
CallbackFunction callbackFunc;
|
||||||
|
std::shared_future<T> asyncTask;
|
||||||
|
bool isReady;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _ASYNC_TASK_H
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "TC9GroupHooks.h"
|
||||||
|
#include "CharacterCache.h"
|
||||||
|
#include "Group.h"
|
||||||
|
#include "GroupMgr.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
void ToCloud9GroupHooks::OnGroupCreated(EventObjectGroup *group)
|
||||||
|
{
|
||||||
|
LOG_INFO("server", "Group created. ID: {}; Leader: {}.", group->guid, group->leader);
|
||||||
|
|
||||||
|
// Idempotent under sidecar event redelivery: a replayed create must not leak a second Group.
|
||||||
|
if (sGroupMgr->GetGroupByGUID(group->guid))
|
||||||
|
return;
|
||||||
|
|
||||||
|
Group* g = new Group();
|
||||||
|
g->m_guid = ObjectGuid(HighGuid::Group, group->guid);
|
||||||
|
g->m_leaderGuid = ObjectGuid(group->leader);
|
||||||
|
sCharacterCache->GetCharacterNameByGuid(g->m_leaderGuid, g->m_leaderName);
|
||||||
|
g->m_dungeonDifficulty = Difficulty(group->difficulty);
|
||||||
|
g->m_raidDifficulty = Difficulty(group->raidDifficulty);
|
||||||
|
g->m_lootMethod = LootMethod(group->lootMethod);
|
||||||
|
g->m_lootThreshold = ItemQualities(group->lootThreshold);
|
||||||
|
g->m_looterGuid = ObjectGuid(group->looterGuid);
|
||||||
|
g->m_masterLooterGuid = ObjectGuid(group->masterLooterGuid);
|
||||||
|
g->m_groupType = GroupType(group->groupType);
|
||||||
|
|
||||||
|
// Must precede member insertion: it zeroes the subgroup counters that AddMemberWithGuid increments.
|
||||||
|
if (g->m_groupType & GROUPTYPE_RAID)
|
||||||
|
g->_initRaidSubGroupsCounter();
|
||||||
|
|
||||||
|
for (int i = 0; i < group->membersSize; i++)
|
||||||
|
g->AddMemberWithGuid(ObjectGuid(group->members[i]));
|
||||||
|
|
||||||
|
sGroupMgr->AddGroup(g);
|
||||||
|
// Mark the service-assigned id used so a locally generated group can't collide with it.
|
||||||
|
sGroupMgr->RegisterGroupId(g->GetGUID().GetCounter());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9GroupHooks::OnGroupDisbanded(uint32 group)
|
||||||
|
{
|
||||||
|
LOG_INFO("server", "Group disbanded. ID: {}.", group);
|
||||||
|
|
||||||
|
if (Group* g = sGroupMgr->GetGroupByGUID(group))
|
||||||
|
g->ForcedDisband(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9GroupHooks::OnGroupMemberAdded(uint32 group, uint64 member)
|
||||||
|
{
|
||||||
|
LOG_INFO("server", "Group member added. ID: {}; Member: {}.", group, member);
|
||||||
|
|
||||||
|
if (Group* g = sGroupMgr->GetGroupByGUID(group))
|
||||||
|
g->AddMemberWithGuid(ObjectGuid(member));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9GroupHooks::OnGroupMemberRemoved(uint32 group, uint64 member, uint64 newLeader)
|
||||||
|
{
|
||||||
|
LOG_INFO("server", "Group member removed. ID: {}; Member: {}; NewLeader: {}.", group, member, newLeader);
|
||||||
|
|
||||||
|
if (Group* g = sGroupMgr->GetGroupByGUID(group))
|
||||||
|
g->RemoveMember(ObjectGuid(member));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9GroupHooks::OnGroupLootTypeChanged(uint32 group, uint8 lootType, uint64 looter, uint8 lootThreshold)
|
||||||
|
{
|
||||||
|
LOG_INFO("server", "Group loot type changed. ID: {}; LootType: {}; Looter: {}; LootThreshold: {}.",
|
||||||
|
group, lootType, looter, lootThreshold);
|
||||||
|
|
||||||
|
if (Group* g = sGroupMgr->GetGroupByGUID(group))
|
||||||
|
{
|
||||||
|
g->SetLootMethod((LootMethod)lootType);
|
||||||
|
g->SetMasterLooterGuid(ObjectGuid(looter));
|
||||||
|
g->SetLootThreshold((ItemQualities)lootThreshold);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9GroupHooks::OnGroupConvertedToRaid(uint32 group)
|
||||||
|
{
|
||||||
|
LOG_INFO("server", "Group converted to raid. ID: {}.", group);
|
||||||
|
|
||||||
|
if (Group* g = sGroupMgr->GetGroupByGUID(group))
|
||||||
|
g->ConvertToRaid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9GroupHooks::OnGroupRaidDifficultyChanged(uint32 group, uint8 difficulty)
|
||||||
|
{
|
||||||
|
LOG_INFO("server", "Raid difficulty changed. ID: {}; Difficulty: {}.", group, difficulty);
|
||||||
|
|
||||||
|
if (Group* g = sGroupMgr->GetGroupByGUID(group))
|
||||||
|
g->SetRaidDifficulty((Difficulty)difficulty);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9GroupHooks::OnGroupDungeonDifficultyChanged(uint32 group, uint8 difficulty)
|
||||||
|
{
|
||||||
|
LOG_INFO("server", "Dungeon difficulty changed. ID: {}; Difficulty: {}.", group, difficulty);
|
||||||
|
|
||||||
|
if (Group* g = sGroupMgr->GetGroupByGUID(group))
|
||||||
|
g->SetDungeonDifficulty((Difficulty)difficulty);
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TC9_GROUP_HOOKS_H
|
||||||
|
#define _TC9_GROUP_HOOKS_H
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "libsidecar.h"
|
||||||
|
|
||||||
|
class ToCloud9GroupHooks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ToCloud9GroupHooks() {};
|
||||||
|
~ToCloud9GroupHooks() {};
|
||||||
|
|
||||||
|
static void OnGroupCreated(EventObjectGroup *group);
|
||||||
|
static void OnGroupDisbanded(uint32 group);
|
||||||
|
static void OnGroupMemberAdded(uint32 group, uint64 member);
|
||||||
|
static void OnGroupMemberRemoved(uint32 group, uint64 member, uint64 newLeader);
|
||||||
|
static void OnGroupLootTypeChanged(uint32 group, uint8 lootType, uint64 looter, uint8 lootThreshold);
|
||||||
|
static void OnGroupConvertedToRaid(uint32 group);
|
||||||
|
static void OnGroupRaidDifficultyChanged(uint32 group, uint8 difficulty);
|
||||||
|
static void OnGroupDungeonDifficultyChanged(uint32 group, uint8 difficulty);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* TC9GroupHooks_h */
|
||||||
@@ -0,0 +1,374 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "TC9GrpcHandler.h"
|
||||||
|
#include "Bag.h"
|
||||||
|
#include "BattlegroundMgr.h"
|
||||||
|
#include "Item.h"
|
||||||
|
#include "ObjectAccessor.h"
|
||||||
|
#include "Player.h"
|
||||||
|
|
||||||
|
GetPlayerItemsByGuidsResponse ToCloud9GrpcHandler::GetPlayerItemsByGuids(uint64 playerGuid, uint64* items, int itemsLen)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(playerGuid));
|
||||||
|
if (!player)
|
||||||
|
{
|
||||||
|
GetPlayerItemsByGuidsResponse resp;
|
||||||
|
resp.errorCode = PlayerItemErrorCodePlayerNotFound;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemsLen <= 0)
|
||||||
|
{
|
||||||
|
GetPlayerItemsByGuidsResponse resp;
|
||||||
|
resp.errorCode = PlayerItemErrorCodeNoError;
|
||||||
|
resp.items = nullptr;
|
||||||
|
resp.itemsSize = 0;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int itemsFound = 0;
|
||||||
|
std::unique_ptr<Item* []> foundItems(new Item * [itemsLen]);
|
||||||
|
for (int i = 0; i < itemsLen; i++)
|
||||||
|
{
|
||||||
|
foundItems[i] = player->GetItemByGuid(ObjectGuid(items[i]));
|
||||||
|
if (foundItems[i])
|
||||||
|
itemsFound++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't forget to delete on "that" side.
|
||||||
|
PlayerItem* itemsResult = static_cast<PlayerItem *>(malloc(sizeof(PlayerItem) * itemsFound));
|
||||||
|
int itemsResultsItr = 0;
|
||||||
|
for (int i = 0; i < itemsLen; i++)
|
||||||
|
{
|
||||||
|
if (!foundItems[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Item* pItem = foundItems[i];
|
||||||
|
|
||||||
|
PlayerItem item;
|
||||||
|
item.guid = pItem->GetGUID().GetRawValue();
|
||||||
|
item.entry = pItem->GetEntry();
|
||||||
|
item.owner = playerGuid;
|
||||||
|
item.bagSlot = pItem->GetBagSlot();
|
||||||
|
item.slot = pItem->GetSlot();
|
||||||
|
item.isTradable = pItem->CanBeTraded(true);
|
||||||
|
item.count = pItem->GetCount();
|
||||||
|
item.flags = pItem->GetUInt32Value(ITEM_FIELD_FLAGS);
|
||||||
|
item.durability = pItem->GetUInt32Value(ITEM_FIELD_DURABILITY);
|
||||||
|
item.randomPropertyID = pItem->GetItemRandomPropertyId();
|
||||||
|
|
||||||
|
// Don't forget to delete on "that" side.
|
||||||
|
char *text = (char*)malloc(sizeof(char) * (pItem->GetText().length() + 1));
|
||||||
|
strcpy(text, pItem->GetText().c_str());
|
||||||
|
item.text = text;
|
||||||
|
|
||||||
|
itemsResult[itemsResultsItr] = item;
|
||||||
|
|
||||||
|
itemsResultsItr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetPlayerItemsByGuidsResponse resp;
|
||||||
|
resp.errorCode = PlayerItemErrorCodeNoError;
|
||||||
|
resp.items = itemsResult;
|
||||||
|
resp.itemsSize = itemsFound;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveItemsWithGuidsFromPlayerResponse ToCloud9GrpcHandler::RemoveItemsWithGuidsFromPlayer(uint64 playerGuid, uint64* items, int itemsLen, uint64 assignToPlayerGuid)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(playerGuid));
|
||||||
|
if (!player)
|
||||||
|
{
|
||||||
|
RemoveItemsWithGuidsFromPlayerResponse resp;
|
||||||
|
resp.errorCode = PlayerItemErrorCodePlayerNotFound;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemsLen <= 0)
|
||||||
|
{
|
||||||
|
RemoveItemsWithGuidsFromPlayerResponse resp;
|
||||||
|
resp.errorCode = PlayerItemErrorCodeNoError;
|
||||||
|
resp.updatedItems = nullptr;
|
||||||
|
resp.updatedItemsSize = 0;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||||
|
|
||||||
|
int itemsFound = 0;
|
||||||
|
std::unique_ptr<uint64[]> deletedItems(new uint64 [itemsLen]);
|
||||||
|
for (int i = 0; i < itemsLen; i++)
|
||||||
|
{
|
||||||
|
Item *item = player->GetItemByGuid(ObjectGuid(items[i]));
|
||||||
|
if (!item)
|
||||||
|
{
|
||||||
|
deletedItems[i] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemsFound++;
|
||||||
|
deletedItems[i] = item->GetGUID().GetRawValue();
|
||||||
|
|
||||||
|
item->SetNotRefundable(player);
|
||||||
|
player->MoveItemFromInventory(item->GetBagSlot(), item->GetSlot(), true);
|
||||||
|
|
||||||
|
item->DeleteFromInventoryDB(trans);
|
||||||
|
item->SetOwnerGUID(ObjectGuid(assignToPlayerGuid));
|
||||||
|
item->SetState(ITEM_CHANGED);
|
||||||
|
item->SaveToDB(trans);
|
||||||
|
|
||||||
|
delete item;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (itemsFound > 0)
|
||||||
|
{
|
||||||
|
player->SaveInventoryAndGoldToDB(trans);
|
||||||
|
CharacterDatabase.CommitTransaction(trans);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't forget to delete on "that" side.
|
||||||
|
uint64_t* itemsResult = (uint64_t*)malloc(sizeof(uint64_t) * itemsFound);
|
||||||
|
int itemsResultsItr = 0;
|
||||||
|
for (int i = 0; i < itemsLen; i++)
|
||||||
|
{
|
||||||
|
if (deletedItems[i] == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
itemsResult[itemsResultsItr] = deletedItems[i];
|
||||||
|
itemsResultsItr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveItemsWithGuidsFromPlayerResponse resp;
|
||||||
|
resp.errorCode = PlayerItemErrorCodeNoError;
|
||||||
|
resp.updatedItems = itemsResult;
|
||||||
|
resp.updatedItemsSize = itemsResultsItr;
|
||||||
|
return resp;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerItemErrorCode ToCloud9GrpcHandler::AddExistingItemToPlayer(AddExistingItemToPlayerRequest* request)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(request->playerGuid));
|
||||||
|
if (!player)
|
||||||
|
return PlayerItemErrorCodePlayerNotFound;
|
||||||
|
|
||||||
|
ItemTemplate const* proto = sObjectMgr->GetItemTemplate(request->itemEntry);
|
||||||
|
if (!proto)
|
||||||
|
return PlayerItemErrorUnknownTemplate;
|
||||||
|
|
||||||
|
Item* item = NewItemOrBag(proto);
|
||||||
|
if (!item->Create(ObjectGuid(request->itemGuid).GetCounter(), request->itemEntry, player))
|
||||||
|
{
|
||||||
|
delete item;
|
||||||
|
return PlayerItemErrorFailedToCreateItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
item->SetUInt32Value(ITEM_FIELD_FLAGS, request->itemFlags);
|
||||||
|
item->SetUInt32Value(ITEM_FIELD_DURABILITY, request->itemDurability);
|
||||||
|
item->SetItemRandomProperties(request->itemRandomPropertyID);
|
||||||
|
item->SetCount(request->itemCount);
|
||||||
|
|
||||||
|
// TODO: Add text.
|
||||||
|
|
||||||
|
ItemPosCountVec dest;
|
||||||
|
uint8 msg = player->CanStoreItem(NULL_BAG, NULL_SLOT, dest, item, false);
|
||||||
|
if (msg != EQUIP_ERR_OK)
|
||||||
|
{
|
||||||
|
delete item;
|
||||||
|
return PlayerItemErrorNoInventorySpace;
|
||||||
|
}
|
||||||
|
|
||||||
|
player->MoveItemToInventory(dest, item, true);
|
||||||
|
|
||||||
|
CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
|
||||||
|
player->SaveInventoryAndGoldToDB(trans);
|
||||||
|
CharacterDatabase.CommitTransaction(trans);
|
||||||
|
|
||||||
|
return PlayerItemErrorCodeNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetMoneyForPlayerResponse ToCloud9GrpcHandler::GetMoneyForPlayer(uint64 playerGuid)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(playerGuid));
|
||||||
|
if (!player)
|
||||||
|
{
|
||||||
|
GetMoneyForPlayerResponse resp;
|
||||||
|
resp.errorCode = PlayerMoneyErrorCodePlayerNotFound;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
GetMoneyForPlayerResponse resp;
|
||||||
|
resp.errorCode = PlayerMoneyErrorCodeNoError;
|
||||||
|
resp.money = player->GetMoney();
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModifyMoneyForPlayerResponse ToCloud9GrpcHandler::ModifyMoneyForPlayer(uint64 playerGuid, int32 value)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(playerGuid));
|
||||||
|
if (!player)
|
||||||
|
{
|
||||||
|
ModifyMoneyForPlayerResponse resp;
|
||||||
|
resp.errorCode = PlayerMoneyErrorCodePlayerNotFound;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!player->ModifyMoney(value, true))
|
||||||
|
{
|
||||||
|
ModifyMoneyForPlayerResponse resp;
|
||||||
|
resp.errorCode = PlayerMoneyErrorCodeTooMuchMoney;
|
||||||
|
resp.newMoneyValue = player->GetMoney();
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModifyMoneyForPlayerResponse resp;
|
||||||
|
resp.errorCode = PlayerMoneyErrorCodeNoError;
|
||||||
|
resp.newMoneyValue = player->GetMoney();
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
CanPlayerInteractWithGOAndTypeResponse ToCloud9GrpcHandler::CanPlayerInteractWithGOAndType(uint64 playerGuid, uint64 go, uint8 goType)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(playerGuid));
|
||||||
|
if (!player)
|
||||||
|
{
|
||||||
|
CanPlayerInteractWithGOAndTypeResponse resp;
|
||||||
|
resp.errorCode = PlayerInteractionErrorCodeCodePlayerNotFound;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
CanPlayerInteractWithGOAndTypeResponse resp;
|
||||||
|
resp.errorCode = PlayerInteractionErrorCodeNoError;
|
||||||
|
resp.canInteract = player->GetGameObjectIfCanInteractWith(ObjectGuid(go), (GameobjectTypes)goType) != nullptr;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
CanPlayerInteractWithNPCAndFlagsResponse ToCloud9GrpcHandler::CanPlayerInteractWithNPCAndFlags(uint64 playerGuid, uint64 npc, uint32 unitFlags)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(playerGuid));
|
||||||
|
if (!player)
|
||||||
|
{
|
||||||
|
CanPlayerInteractWithNPCAndFlagsResponse resp;
|
||||||
|
resp.errorCode = PlayerInteractionErrorCodeCodePlayerNotFound;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
CanPlayerInteractWithNPCAndFlagsResponse resp;
|
||||||
|
resp.errorCode = PlayerInteractionErrorCodeNoError;
|
||||||
|
resp.canInteract = player->GetNPCIfCanInteractWith(ObjectGuid(npc), (NPCFlags)unitFlags) != nullptr;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
BattlegroundStartResponse ToCloud9GrpcHandler::StartBattleground(BattlegroundStartRequest* req)
|
||||||
|
{
|
||||||
|
PvPDifficultyEntry const* pvpEntry = GetBattlegroundBracketByLevel(req->mapID, req->bracketLvl);
|
||||||
|
if (!pvpEntry)
|
||||||
|
{
|
||||||
|
BattlegroundStartResponse resp;
|
||||||
|
resp.errorCode = BattlegroundErrorFailedToCreateBG;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
BattlegroundTypeId bgTypeId = BattlegroundTypeId(req->battlegroundTypeID);
|
||||||
|
|
||||||
|
Battleground* bg = sBattlegroundMgr->CreateNewBattleground(bgTypeId, pvpEntry, req->arenaType, req->isRated);
|
||||||
|
if (!bg)
|
||||||
|
{
|
||||||
|
BattlegroundStartResponse resp;
|
||||||
|
resp.errorCode = BattlegroundErrorFailedToCreateBG;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bg->StartBattleground();
|
||||||
|
|
||||||
|
bg->IncreaseInvitedCount(TEAM_HORDE);
|
||||||
|
bg->IncreaseInvitedCount(TEAM_ALLIANCE);
|
||||||
|
|
||||||
|
BattlegroundStartResponse resp;
|
||||||
|
resp.errorCode = BattlegroundErrorCodeNoError;
|
||||||
|
resp.instanceID = bg->GetInstanceID();
|
||||||
|
resp.instanceClientID = bg->GetClientInstanceID();
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
|
BattlegroundErrorCode ToCloud9GrpcHandler::AddPlayersToBattleground(BattlegroundAddPlayersRequest* request)
|
||||||
|
{
|
||||||
|
BattlegroundTypeId bgTypeId = BattlegroundTypeId(request->battlegroundTypeID);
|
||||||
|
|
||||||
|
Battleground* bg = sBattlegroundMgr->GetBattleground(request->instanceID, BATTLEGROUND_TYPE_NONE);
|
||||||
|
if (!bg)
|
||||||
|
return BattlegroundErrorBattlegroundNotFound;
|
||||||
|
|
||||||
|
for (int i = 0; i < request->alliancePlayersToAddSize; i++)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(request->alliancePlayersToAdd[i]));
|
||||||
|
if (player)
|
||||||
|
{
|
||||||
|
player->SetEntryPoint();
|
||||||
|
player->SetBattlegroundId(bg->GetInstanceID(), bg->GetBgTypeID(), 1, true, bgTypeId == BATTLEGROUND_RB, player->GetTeamId(true));
|
||||||
|
sBattlegroundMgr->SendToBattleground(player, bg->GetInstanceID(), bgTypeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < request->hordePlayersToAddSize; i++)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(request->hordePlayersToAdd[i]));
|
||||||
|
if (player)
|
||||||
|
{
|
||||||
|
player->SetEntryPoint();
|
||||||
|
player->SetBattlegroundId(bg->GetInstanceID(), bg->GetBgTypeID(), 1, true, bgTypeId == BATTLEGROUND_RB, player->GetTeamId(true));
|
||||||
|
sBattlegroundMgr->SendToBattleground(player, bg->GetInstanceID(), bgTypeId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return BattlegroundErrorCodeNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
BattlegroundJoinCheckErrorCode ToCloud9GrpcHandler::CanPlayerJoinBattlegroundQueue(uint64 playerGuid)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(playerGuid));
|
||||||
|
if (!player)
|
||||||
|
return BattlegroundJoinCheckErrorCodePlayerNotFound;
|
||||||
|
|
||||||
|
// Lets ignore RBAC checks for now.
|
||||||
|
Battleground* bg = sBattlegroundMgr->GetBattlegroundTemplate(BATTLEGROUND_RB);
|
||||||
|
if (!bg)
|
||||||
|
return BattlegroundJoinCheckErrorCodeResponseIsFalse;
|
||||||
|
|
||||||
|
// has deserter debuff
|
||||||
|
if (!player->CanJoinToBattleground(bg))
|
||||||
|
return BattlegroundJoinCheckErrorCodeResponseIsFalse;
|
||||||
|
|
||||||
|
// don't let Death Knights join BG queues when they are not allowed to be teleported yet
|
||||||
|
if (player->IsClass(CLASS_DEATH_KNIGHT, CLASS_CONTEXT_TELEPORT) && player->GetMapId() == 609 && !player->IsGameMaster() && !player->HasSpell(50977))
|
||||||
|
return BattlegroundJoinCheckErrorCodeResponseIsFalse;
|
||||||
|
|
||||||
|
return BattlegroundJoinCheckErrorCodeOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
BattlegroundJoinCheckErrorCode ToCloud9GrpcHandler::CanPlayerTeleportToBattleground(uint64 playerGuid)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(playerGuid));
|
||||||
|
if (!player)
|
||||||
|
return BattlegroundJoinCheckErrorCodePlayerNotFound;
|
||||||
|
|
||||||
|
if (player->GetCharmGUID() || player->IsInCombat())
|
||||||
|
return BattlegroundJoinCheckErrorCodeResponseIsFalse;
|
||||||
|
|
||||||
|
return BattlegroundJoinCheckErrorCodeOK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TC9_GRPC_HANDLER_H
|
||||||
|
#define _TC9_GRPC_HANDLER_H
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
#include "libsidecar.h"
|
||||||
|
|
||||||
|
class ToCloud9GrpcHandler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ToCloud9GrpcHandler() {};
|
||||||
|
~ToCloud9GrpcHandler() {};
|
||||||
|
|
||||||
|
// Items
|
||||||
|
static GetPlayerItemsByGuidsResponse GetPlayerItemsByGuids(uint64 player, uint64* items, int items_len);
|
||||||
|
static RemoveItemsWithGuidsFromPlayerResponse RemoveItemsWithGuidsFromPlayer(uint64 player, uint64* items, int itemsLen, uint64 assignToPlayer);
|
||||||
|
static PlayerItemErrorCode AddExistingItemToPlayer(AddExistingItemToPlayerRequest*);
|
||||||
|
|
||||||
|
// Money
|
||||||
|
static GetMoneyForPlayerResponse GetMoneyForPlayer(uint64 player);
|
||||||
|
static ModifyMoneyForPlayerResponse ModifyMoneyForPlayer(uint64 player, int32 value);
|
||||||
|
|
||||||
|
// Interactions
|
||||||
|
static CanPlayerInteractWithGOAndTypeResponse CanPlayerInteractWithGOAndType(uint64 player, uint64 go, uint8 goType);
|
||||||
|
static CanPlayerInteractWithNPCAndFlagsResponse CanPlayerInteractWithNPCAndFlags(uint64 player, uint64 npc, uint32 unitFlags);
|
||||||
|
|
||||||
|
// Battlegrounds
|
||||||
|
static BattlegroundStartResponse StartBattleground(BattlegroundStartRequest* request);
|
||||||
|
static BattlegroundErrorCode AddPlayersToBattleground(BattlegroundAddPlayersRequest* request);
|
||||||
|
static BattlegroundJoinCheckErrorCode CanPlayerJoinBattlegroundQueue(uint64 player);
|
||||||
|
static BattlegroundJoinCheckErrorCode CanPlayerTeleportToBattleground(uint64 player);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _TC9_GRPC_HANDLER_H
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "TC9GuildHooks.h"
|
||||||
|
#include "ObjectAccessor.h"
|
||||||
|
#include "Player.h"
|
||||||
|
|
||||||
|
void ToCloud9GuildHooks::OnGuildMemberAdded(uint64 guild, uint64 character)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(character));
|
||||||
|
if (!player)
|
||||||
|
return;
|
||||||
|
|
||||||
|
player->SetInGuild(guild);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9GuildHooks::OnGuildMemberRemoved(uint64 /*guild*/, uint64 character)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(character));
|
||||||
|
if (!player)
|
||||||
|
return;
|
||||||
|
|
||||||
|
player->SetInGuild(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9GuildHooks::OnGuildMemberLeft(uint64 /*guild*/, uint64 character)
|
||||||
|
{
|
||||||
|
Player *player = ObjectAccessor::FindPlayer(ObjectGuid(character));
|
||||||
|
if (!player)
|
||||||
|
return;
|
||||||
|
|
||||||
|
player->SetInGuild(0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TC9_GUILD_HOOKS_H
|
||||||
|
#define _TC9_GUILD_HOOKS_H
|
||||||
|
|
||||||
|
#include "Common.h"
|
||||||
|
|
||||||
|
class ToCloud9GuildHooks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ToCloud9GuildHooks() {};
|
||||||
|
~ToCloud9GuildHooks() {};
|
||||||
|
|
||||||
|
static void OnGuildMemberAdded(uint64 guild, uint64 character);
|
||||||
|
static void OnGuildMemberRemoved(uint64 guild, uint64 character);
|
||||||
|
static void OnGuildMemberLeft(uint64 guild, uint64 character);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _TC9_GUILD_HOOKS_H
|
||||||
@@ -0,0 +1,268 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
|
#include "Config.h"
|
||||||
|
#include "InstanceSaveMgr.h"
|
||||||
|
#include "libsidecar.h"
|
||||||
|
#include "Log.h"
|
||||||
|
#include "MapMgr.h"
|
||||||
|
#include "Player.h"
|
||||||
|
#include "TC9GroupHooks.h"
|
||||||
|
#include "TC9GrpcHandler.h"
|
||||||
|
#include "TC9GuildHooks.h"
|
||||||
|
#include "UpdateTime.h"
|
||||||
|
#include "WorldSessionMgr.h"
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#define AVAILABLE_MAPS_ALL_MAPS ""
|
||||||
|
|
||||||
|
MonitoringDataCollectorResponse HandleMonitoringRequest();
|
||||||
|
|
||||||
|
ToCloud9Sidecar* ToCloud9Sidecar::instance()
|
||||||
|
{
|
||||||
|
static ToCloud9Sidecar instance;
|
||||||
|
return &instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
ToCloud9Sidecar::ToCloud9Sidecar() : _clusterModeEnabled(false), _isCrossrealm(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9Sidecar::Init(uint16 port, int realmId)
|
||||||
|
{
|
||||||
|
_clusterModeEnabled = sConfigMgr->GetOption<bool>("Cluster.Enabled", false);
|
||||||
|
|
||||||
|
if (_clusterModeEnabled)
|
||||||
|
{
|
||||||
|
uint32 *assignedMaps;
|
||||||
|
int assignedMapsSize = 0;
|
||||||
|
|
||||||
|
_isCrossrealm = sConfigMgr->GetOption<bool>("Cluster.IsCrossrealm", false);
|
||||||
|
|
||||||
|
std::string availableMaps = sConfigMgr->GetOption<std::string>("Cluster.AvailableMaps", AVAILABLE_MAPS_ALL_MAPS);
|
||||||
|
TC9InitLib(port, realmId, _isCrossrealm, availableMaps.data(), &assignedMaps, &assignedMapsSize);
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_MAP_ID; i++)
|
||||||
|
_assignedMapsByID[i] = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < assignedMapsSize; i++)
|
||||||
|
{
|
||||||
|
uint32 mapId = assignedMaps[i];
|
||||||
|
if (mapId >= MAX_MAP_ID)
|
||||||
|
{
|
||||||
|
LOG_ERROR("server", "ToCloud9Sidecar::Init: map id {} out of range [0, {}), ignored",
|
||||||
|
mapId, MAX_MAP_ID);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_assignedMapsByID[mapId] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assignedMapsSize > 0)
|
||||||
|
free(assignedMaps);
|
||||||
|
|
||||||
|
SetupHooks();
|
||||||
|
SetupGrpcHandlers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9Sidecar::Deinit()
|
||||||
|
{
|
||||||
|
if (_clusterModeEnabled)
|
||||||
|
TC9GracefulShutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9Sidecar::SetupHooks()
|
||||||
|
{
|
||||||
|
TC9SetOnMapsReassignedHook(&ToCloud9Sidecar::OnMapsReassigned);
|
||||||
|
|
||||||
|
TC9SetOnGuildMemberLeftHook(&ToCloud9GuildHooks::OnGuildMemberLeft);
|
||||||
|
TC9SetOnGuildMemberAddedHook(&ToCloud9GuildHooks::OnGuildMemberAdded);
|
||||||
|
TC9SetOnGuildMemberRemovedHook(&ToCloud9GuildHooks::OnGuildMemberRemoved);
|
||||||
|
|
||||||
|
TC9SetOnGroupCreatedHook(&ToCloud9GroupHooks::OnGroupCreated);
|
||||||
|
TC9SetOnGroupDisbandedHook(&ToCloud9GroupHooks::OnGroupDisbanded);
|
||||||
|
TC9SetOnGroupMemberAddedHook(&ToCloud9GroupHooks::OnGroupMemberAdded);
|
||||||
|
TC9SetOnGroupMemberRemovedHook(&ToCloud9GroupHooks::OnGroupMemberRemoved);
|
||||||
|
TC9SetOnGroupLootTypeChangedHook(&ToCloud9GroupHooks::OnGroupLootTypeChanged);
|
||||||
|
TC9SetOnGroupConvertedToRaidHook(&ToCloud9GroupHooks::OnGroupConvertedToRaid);
|
||||||
|
TC9SetOnGroupRaidDifficultyChangedHook(&ToCloud9GroupHooks::OnGroupRaidDifficultyChanged);
|
||||||
|
TC9SetOnGroupDungeonDifficultyChangedHook(&ToCloud9GroupHooks::OnGroupDungeonDifficultyChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9Sidecar::SetupGrpcHandlers()
|
||||||
|
{
|
||||||
|
TC9SetGetPlayerItemsByGuidsHandler(&ToCloud9GrpcHandler::GetPlayerItemsByGuids);
|
||||||
|
TC9SetRemoveItemsWithGuidsFromPlayerHandler(&ToCloud9GrpcHandler::RemoveItemsWithGuidsFromPlayer);
|
||||||
|
TC9SetAddExistingItemToPlayerHandler(&ToCloud9GrpcHandler::AddExistingItemToPlayer);
|
||||||
|
|
||||||
|
TC9SetGetMoneyForPlayerHandler(&ToCloud9GrpcHandler::GetMoneyForPlayer);
|
||||||
|
TC9SetModifyMoneyForPlayerHandler(&ToCloud9GrpcHandler::ModifyMoneyForPlayer);
|
||||||
|
|
||||||
|
TC9SetCanPlayerInteractWithGOAndTypeHandler(&ToCloud9GrpcHandler::CanPlayerInteractWithGOAndType);
|
||||||
|
TC9SetCanPlayerInteractWithNPCAndFlagsHandler(&ToCloud9GrpcHandler::CanPlayerInteractWithNPCAndFlags);
|
||||||
|
|
||||||
|
TC9SetBattlegroundStartHandler(&ToCloud9GrpcHandler::StartBattleground);
|
||||||
|
TC9SetBattlegroundAddPlayersHandler(&ToCloud9GrpcHandler::AddPlayersToBattleground);
|
||||||
|
TC9SetCanPlayerJoinBattlegroundQueueHandler(&ToCloud9GrpcHandler::CanPlayerJoinBattlegroundQueue);
|
||||||
|
TC9SetCanPlayerTeleportToBattlegroundHandler(&ToCloud9GrpcHandler::CanPlayerTeleportToBattleground);
|
||||||
|
|
||||||
|
TC9SetMonitoringDataCollectorHandler(&HandleMonitoringRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9Sidecar::ProcessHooks()
|
||||||
|
{
|
||||||
|
TC9ProcessEventsHooks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9Sidecar::ProcessGrpcOrHttpRequests()
|
||||||
|
{
|
||||||
|
TC9ProcessGRPCOrHTTPRequests();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9Sidecar::ProcessAsyncTasks()
|
||||||
|
{
|
||||||
|
_asyncTasksProcessor.ProcessReadyCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ToCloud9Sidecar::IsMapAssigned(uint32 mapId)
|
||||||
|
{
|
||||||
|
if (mapId >= MAX_MAP_ID)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return _assignedMapsByID[mapId];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ToCloud9Sidecar::GenerateCharacterGuid(uint16 realmId)
|
||||||
|
{
|
||||||
|
return uint32(TC9GetNextAvailableCharacterGuid(realmId));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ToCloud9Sidecar::GenerateItemGuid(uint16 realmId)
|
||||||
|
{
|
||||||
|
return uint32(TC9GetNextAvailableItemGuid(realmId));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 ToCloud9Sidecar::GenerateInstanceGuid(uint16 realmId)
|
||||||
|
{
|
||||||
|
return uint32(TC9GetNextAvailableInstanceGuid(realmId));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9Sidecar::OnPlayerLeftBattleground(uint64 playerGUID, uint32 realmID, uint32 instanceID)
|
||||||
|
{
|
||||||
|
TC9PlayerLeftBattleground(playerGUID, realmID, instanceID);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9Sidecar::OnBattlegroundStatusChanged(uint32 instanceID, uint8 status)
|
||||||
|
{
|
||||||
|
TC9BattlegroundStatusChanged(instanceID, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ToCloud9Sidecar::NatsPublish(std::string const& subject, std::string const& payload)
|
||||||
|
{
|
||||||
|
if (!_clusterModeEnabled)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (payload.size() > size_t(std::numeric_limits<int>::max()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return TC9NatsPublish(subject.c_str(), payload.c_str(), int(payload.size())) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ToCloud9Sidecar::NatsSubscribe(std::string const& subject, void (*handler)(char const*, char const*, int))
|
||||||
|
{
|
||||||
|
if (!_clusterModeEnabled || !handler)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return TC9NatsSubscribe(subject.c_str(), handler) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ToCloud9Sidecar::OnMapsReassigned(uint32* addedMaps, int addedMapsSize, uint32* removedMaps, int removedMapsSize)
|
||||||
|
{
|
||||||
|
std::vector<uint32_t> newMapIDs;
|
||||||
|
newMapIDs.reserve(addedMapsSize > 0 ? addedMapsSize : 0);
|
||||||
|
|
||||||
|
for (int i = 0; i < addedMapsSize; i++)
|
||||||
|
{
|
||||||
|
uint32 mapId = addedMaps[i];
|
||||||
|
if (mapId >= MAX_MAP_ID)
|
||||||
|
{
|
||||||
|
LOG_ERROR("server", "ToCloud9Sidecar::OnMapsReassigned: added map id {} out of range [0, {}), ignored",
|
||||||
|
mapId, MAX_MAP_ID);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sToCloud9Sidecar->_assignedMapsByID[mapId] = true;
|
||||||
|
newMapIDs.push_back(mapId);
|
||||||
|
|
||||||
|
if (Map* map = sMapMgr->FindBaseNonInstanceMap(mapId))
|
||||||
|
map->StopPlayersRedirectKickTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < removedMapsSize; i++)
|
||||||
|
{
|
||||||
|
uint32 mapId = removedMaps[i];
|
||||||
|
if (mapId >= MAX_MAP_ID)
|
||||||
|
{
|
||||||
|
LOG_ERROR("server", "ToCloud9Sidecar::OnMapsReassigned: removed map id {} out of range [0, {}), ignored",
|
||||||
|
mapId, MAX_MAP_ID);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
sToCloud9Sidecar->_assignedMapsByID[mapId] = false;
|
||||||
|
|
||||||
|
if (Map* map = sMapMgr->FindBaseNonInstanceMap(mapId))
|
||||||
|
map->StartPlayersRedirectKickTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newMapIDs.empty())
|
||||||
|
{
|
||||||
|
auto loadRowsPtr = std::make_shared<InstanceMapLoadRows>();
|
||||||
|
|
||||||
|
AsyncTask<bool> task(
|
||||||
|
[loadRowsPtr, newMapIDs]() -> bool {
|
||||||
|
LOG_INFO("server", "Starting to load data for newly assigned maps...");
|
||||||
|
|
||||||
|
*loadRowsPtr = sInstanceSaveMgr->LoadInstanceSavesAndBindsForMapIDs(newMapIDs);
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
[loadRowsPtr, newMapIDs](bool) {
|
||||||
|
sInstanceSaveMgr->MergeWithNewInstanceSaves(*loadRowsPtr);
|
||||||
|
TC9ReadyToAcceptPlayersFromMaps((uint32_t*)newMapIDs.data(), newMapIDs.size());
|
||||||
|
|
||||||
|
LOG_INFO("server", "Finished loading data for newly assigned maps.");
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
task.ExecuteAsync();
|
||||||
|
sToCloud9Sidecar->_asyncTasksProcessor.AddCallback(std::move(task));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MonitoringDataCollectorResponse HandleMonitoringRequest()
|
||||||
|
{
|
||||||
|
MonitoringDataCollectorResponse res;
|
||||||
|
res.errorCode = MonitoringErrorCodeNoError;
|
||||||
|
res.diffMean = sWorldUpdateTime.GetAverageUpdateTime();
|
||||||
|
res.diffMedian = sWorldUpdateTime.GetPercentile(50);
|
||||||
|
res.diff95Percentile = sWorldUpdateTime.GetPercentile(95);
|
||||||
|
res.diff99Percentile = sWorldUpdateTime.GetPercentile(99);
|
||||||
|
res.diffMaxPercentile = sWorldUpdateTime.GetPercentile(100);
|
||||||
|
res.connectedPlayers = sWorldSessionMgr->GetActiveSessionCount();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the AzerothCore Project. See AUTHORS file for Copyright information
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Affero General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TC9_SIDECAR_H
|
||||||
|
#define _TC9_SIDECAR_H
|
||||||
|
|
||||||
|
#include "AsyncCallbackProcessor.h"
|
||||||
|
#include "AsyncTask.h"
|
||||||
|
#include "Common.h"
|
||||||
|
#include "ObjectGuid.h"
|
||||||
|
|
||||||
|
#define MAX_MAP_ID 800 // Probably too much, but let's lean towards caution.
|
||||||
|
|
||||||
|
class ToCloud9Sidecar
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
ToCloud9Sidecar();
|
||||||
|
~ToCloud9Sidecar() {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static ToCloud9Sidecar* instance();
|
||||||
|
|
||||||
|
void Init(uint16 port, int realmId);
|
||||||
|
void Deinit();
|
||||||
|
|
||||||
|
bool ClusterModeEnabled() { return _clusterModeEnabled; }
|
||||||
|
bool IsCrossrealm() { return _isCrossrealm; }
|
||||||
|
|
||||||
|
bool IsMapAssigned(uint32 mapId);
|
||||||
|
|
||||||
|
void SetupHooks();
|
||||||
|
void SetupGrpcHandlers();
|
||||||
|
|
||||||
|
void ProcessHooks();
|
||||||
|
void ProcessGrpcOrHttpRequests();
|
||||||
|
void ProcessAsyncTasks();
|
||||||
|
|
||||||
|
uint32 GenerateCharacterGuid(uint16 realmId = DEFAULT_NON_CROSSREALM_REALM_ID);
|
||||||
|
uint32 GenerateItemGuid(uint16 realmId = DEFAULT_NON_CROSSREALM_REALM_ID);
|
||||||
|
uint32 GenerateInstanceGuid(uint16 realmId = DEFAULT_NON_CROSSREALM_REALM_ID);
|
||||||
|
|
||||||
|
void OnPlayerLeftBattleground(uint64 playerGUID, uint32 realmID, uint32 instanceID);
|
||||||
|
void OnBattlegroundStatusChanged(uint32 instanceID, uint8 status);
|
||||||
|
|
||||||
|
// Generic NATS pub/sub (single choke point for in-process modules).
|
||||||
|
// No-ops outside cluster mode. Subscribe callbacks run on the world
|
||||||
|
// thread (ProcessHooks).
|
||||||
|
bool NatsPublish(std::string const& subject, std::string const& payload);
|
||||||
|
bool NatsSubscribe(std::string const& subject, void (*handler)(char const* subject, char const* payload, int payloadLen));
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void OnMapsReassigned(uint32* addedMaps, int addedMapsSize, uint32* removedMaps, int removedMapsSize);
|
||||||
|
|
||||||
|
bool _clusterModeEnabled;
|
||||||
|
bool _isCrossrealm;
|
||||||
|
|
||||||
|
bool _assignedMapsByID[MAX_MAP_ID];
|
||||||
|
|
||||||
|
AsyncCallbackProcessor<AsyncTask<bool>> _asyncTasksProcessor;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define sToCloud9Sidecar ToCloud9Sidecar::instance()
|
||||||
|
|
||||||
|
#endif // _TC9_SIDECAR_H
|
||||||
@@ -23,8 +23,8 @@
|
|||||||
#include "AccountMgr.h"
|
#include "AccountMgr.h"
|
||||||
#include "AchievementMgr.h"
|
#include "AchievementMgr.h"
|
||||||
#include "AddonMgr.h"
|
#include "AddonMgr.h"
|
||||||
#include "ArenaTeamMgr.h"
|
|
||||||
#include "ArenaSeasonMgr.h"
|
#include "ArenaSeasonMgr.h"
|
||||||
|
#include "ArenaTeamMgr.h"
|
||||||
#include "AuctionHouseMgr.h"
|
#include "AuctionHouseMgr.h"
|
||||||
#include "AutobroadcastMgr.h"
|
#include "AutobroadcastMgr.h"
|
||||||
#include "BattlefieldMgr.h"
|
#include "BattlefieldMgr.h"
|
||||||
@@ -53,8 +53,8 @@
|
|||||||
#include "GridNotifiersImpl.h"
|
#include "GridNotifiersImpl.h"
|
||||||
#include "GroupMgr.h"
|
#include "GroupMgr.h"
|
||||||
#include "GuildMgr.h"
|
#include "GuildMgr.h"
|
||||||
#include "IPLocation.h"
|
|
||||||
#include "InstanceSaveMgr.h"
|
#include "InstanceSaveMgr.h"
|
||||||
|
#include "IPLocation.h"
|
||||||
#include "ItemEnchantmentMgr.h"
|
#include "ItemEnchantmentMgr.h"
|
||||||
#include "LFGMgr.h"
|
#include "LFGMgr.h"
|
||||||
#include "Language.h"
|
#include "Language.h"
|
||||||
@@ -82,6 +82,7 @@
|
|||||||
#include "SmartAI.h"
|
#include "SmartAI.h"
|
||||||
#include "SpellMgr.h"
|
#include "SpellMgr.h"
|
||||||
#include "TaskScheduler.h"
|
#include "TaskScheduler.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "TicketMgr.h"
|
#include "TicketMgr.h"
|
||||||
#include "Transport.h"
|
#include "Transport.h"
|
||||||
#include "TransportMgr.h"
|
#include "TransportMgr.h"
|
||||||
@@ -1341,6 +1342,24 @@ void World::Update(uint32 diff)
|
|||||||
sScriptMgr->OnWorldUpdate(diff);
|
sScriptMgr->OnWorldUpdate(diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sToCloud9Sidecar->ClusterModeEnabled())
|
||||||
|
{
|
||||||
|
{
|
||||||
|
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Process TC9 async tasks"));
|
||||||
|
sToCloud9Sidecar->ProcessAsyncTasks();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Process TC9 hooks"));
|
||||||
|
sToCloud9Sidecar->ProcessHooks();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Process TC9 gRPC and HTTP requests"));
|
||||||
|
sToCloud9Sidecar->ProcessGrpcOrHttpRequests();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update metrics"));
|
METRIC_TIMER("world_update_time", METRIC_TAG("type", "Update metrics"));
|
||||||
// Stats logger update
|
// Stats logger update
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "MapMgr.h"
|
#include "MapMgr.h"
|
||||||
#include "Player.h"
|
#include "Player.h"
|
||||||
#include "SharedDefines.h"
|
#include "SharedDefines.h"
|
||||||
|
#include "TC9Sidecar.h"
|
||||||
#include "UnitAI.h"
|
#include "UnitAI.h"
|
||||||
#include "Weather.h"
|
#include "Weather.h"
|
||||||
#include "WorldState.h"
|
#include "WorldState.h"
|
||||||
@@ -160,6 +161,12 @@ void WorldState::LoadWorldStates()
|
|||||||
// Setting a worldstate will save it to DB
|
// Setting a worldstate will save it to DB
|
||||||
void WorldState::setWorldState(uint32 index, uint64 timeValue)
|
void WorldState::setWorldState(uint32 index, uint64 timeValue)
|
||||||
{
|
{
|
||||||
|
// Crossrealm nodes must not persist worldstates: their CharacterDatabase is
|
||||||
|
// the routing proxy and the write would land in an arbitrary realm DB. The
|
||||||
|
// in-memory value still has to be updated so read-modify-write users
|
||||||
|
// (e.g. the Wintergrasp clock) keep working.
|
||||||
|
if (!sToCloud9Sidecar->IsCrossrealm())
|
||||||
|
{
|
||||||
auto const& it = _worldstates.find(index);
|
auto const& it = _worldstates.find(index);
|
||||||
if (it != _worldstates.end())
|
if (it != _worldstates.end())
|
||||||
{
|
{
|
||||||
@@ -175,6 +182,7 @@ void WorldState::setWorldState(uint32 index, uint64 timeValue)
|
|||||||
stmt->SetData(1, uint32(timeValue));
|
stmt->SetData(1, uint32(timeValue));
|
||||||
CharacterDatabase.Execute(stmt);
|
CharacterDatabase.Execute(stmt);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_worldstates[index] = timeValue;
|
_worldstates[index] = timeValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -232,7 +232,8 @@ target_link_libraries(scripts
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
acore-core-interface
|
acore-core-interface
|
||||||
PUBLIC
|
PUBLIC
|
||||||
game-interface)
|
game-interface
|
||||||
|
libsidecar)
|
||||||
|
|
||||||
target_include_directories(scripts
|
target_include_directories(scripts
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
|||||||
Reference in New Issue
Block a user