Skip to content
Merged
15 changes: 15 additions & 0 deletions Library/include/CSP/Common/NetworkEventData.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,21 @@ class CSP_API SequenceChangedNetworkEventData : public NetworkEventData
csp::common::Optional<csp::common::HotspotSequenceChangedNetworkEventData> HotspotData = nullptr;
};

class CSP_API AsyncCallCompletedEventData : public NetworkEventData
{
public:
/// @brief The name of the async operation that has been completed.
csp::common::String OperationName;

/// @brief An Id related to the async operation that has been completed.
/// This could for example be a group Id, if this were an async duplicate group operation.
csp::common::String ReferenceId;

/// @brief The type that the Id represents.
/// In the previous example this would be "GroupId".
csp::common::String ReferenceType;
};

// TODO, this should not be here. It's not an event data, it's just a type for a callback used in the AssetSystem.
// The annoyance is that ChangeType is defined for these EventDatas, gotta break that at some point.
// I don't really know where this should go at the moment.
Expand Down
9 changes: 5 additions & 4 deletions Library/include/CSP/Multiplayer/MultiPlayerConnection.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@ class CSP_API MultiplayerConnection
/// @brief Start the connection and register to start receiving updates from the server.
/// Connect should be called after LogIn and before EnterSpace.
/// @param Callback ErrorCodeCallbackHandler : a callback with failure state.
CSP_NO_EXPORT void Connect(ErrorCodeCallbackHandler Callback, [[maybe_unused]] const csp::common::String& MultiplayerUri, const csp::common::String& AccessToken, const csp::common::String& DeviceId);
CSP_NO_EXPORT void Connect(ErrorCodeCallbackHandler Callback, [[maybe_unused]] const csp::common::String& MultiplayerUri,
const csp::common::String& AccessToken, const csp::common::String& DeviceId);

/// @brief Indicates whether the multiplayer connection is established
/// @return bool : true if connected, false otherwise
Expand All @@ -153,8 +154,8 @@ class CSP_API MultiplayerConnection
CSP_NO_EXPORT csp::multiplayer::NetworkEventManagerImpl* GetNetworkEventManager() { return NetworkEventManager; }

/// @brief Getter for the NetworkEventBus
/// @return NetworkEventBus* : pointer to the NetworkEventBus
CSP_NO_EXPORT NetworkEventBus* GetEventBusPtr() { return EventBusPtr; }
/// @return NetworkEventBus& : reference to the NetworkEventBus
CSP_NO_EXPORT NetworkEventBus& GetEventBus() { return *EventBus; }

/// @brief Disconnect the multiplayer and provide a reason
/// @param Reason csp::common::String& : the reason to disconnect
Expand Down Expand Up @@ -243,7 +244,7 @@ class CSP_API MultiplayerConnection

class csp::multiplayer::IWebSocketClient* WebSocketClient;
class NetworkEventManagerImpl* NetworkEventManager;
class NetworkEventBus* EventBusPtr;
class NetworkEventBus* EventBus;

csp::common::LogSystem& LogSystem;

Expand Down
7 changes: 4 additions & 3 deletions Library/include/CSP/Multiplayer/NetworkEventBus.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,8 +199,9 @@ class CSP_API NetworkEventBus
SequenceChanged, // Unpacks to SequenceChangedNetworkEventData or SequenceHotspotChangedEventData (Better if there was a seperate event for
// each.)
AccessControlChanged, // Unpacks to AccessControlChangedNetworkEventData
GeneralPurposeEvent // Unpacks to NetworkEventData (Base type). An external event unknown to us that may have been registered with any string
// value.
GeneralPurposeEvent, // Unpacks to NetworkEventData (Base type). An external event unknown to us that may have been registered with any string
// value.
AsyncCallCompleted // Unpacks to AsyncCallCompletedEventData
};

static NetworkEvent NetworkEventFromString(const csp::common::String& EventString);
Expand All @@ -223,7 +224,7 @@ class CSP_API NetworkEventBus
static inline const std::unordered_map<NetworkEvent, csp::common::String>
CustomDeserializationEventMap { { NetworkEvent::AssetDetailBlobChanged, "AssetDetailBlobChanged" },
{ NetworkEvent::Conversation, "Conversation" }, { NetworkEvent::SequenceChanged, "SequenceChanged" },
{ NetworkEvent::AccessControlChanged, "AccessControlChanged" } };
{ NetworkEvent::AccessControlChanged, "AccessControlChanged" }, { NetworkEvent::AsyncCallCompleted, "AsyncCallCompleted" } };

CSP_END_IGNORE

Expand Down
2 changes: 1 addition & 1 deletion Library/include/CSP/Systems/Assets/AssetSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ class CSP_API AssetSystem : public SystemBase

private:
AssetSystem(); // This constructor is only provided to appease the wrapper generator and should not be used
CSP_NO_EXPORT AssetSystem(csp::web::WebClient* InWebClient, csp::multiplayer::NetworkEventBus* InEventBus, common::LogSystem& LogSystem);
CSP_NO_EXPORT AssetSystem(csp::web::WebClient* WebClient, csp::multiplayer::NetworkEventBus& EventBus, common::LogSystem& LogSystem);
~AssetSystem();

CSP_ASYNC_RESULT void DeleteAssetCollectionById(const csp::common::String& AssetCollectionId, NullResultCallback Callback);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class CSP_API HotspotSequenceSystem : public SystemBase
CSP_END_IGNORE

HotspotSequenceSystem(csp::systems::SequenceSystem* SequenceSystem, csp::systems::SpaceSystem* SpaceSystem,
csp::multiplayer::NetworkEventBus* InEventBus, csp::common::LogSystem& LogSystem);
csp::multiplayer::NetworkEventBus& EventBus, csp::common::LogSystem& LogSystem);
/// @brief Create a Hotspot group
/// @param GroupName csp::common::String : The unique grouping name
/// @param HotspotIds csp::common::Array<csp::common::String> : set of Hotspot ids to add to the group
Expand Down
2 changes: 1 addition & 1 deletion Library/include/CSP/Systems/Sequence/SequenceSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ class CSP_API SequenceSystem : public SystemBase

private:
SequenceSystem(); // This constructor is only provided to appease the wrapper generator and should not be used
SequenceSystem(csp::web::WebClient* InWebClient, csp::multiplayer::NetworkEventBus* InEventBus, csp::common::LogSystem& LogSystem);
SequenceSystem(csp::web::WebClient* WebClient, csp::multiplayer::NetworkEventBus& EventBus, csp::common::LogSystem& LogSystem);
~SequenceSystem();

csp::services::ApiBase* SequenceAPI;
Expand Down
49 changes: 45 additions & 4 deletions Library/include/CSP/Systems/Spaces/SpaceSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -343,22 +343,61 @@ class CSP_API CSP_NO_DISPOSE SpaceSystem : public SystemBase
/// @param Callback NullResultCallback : callback when asynchronous task finishes
CSP_ASYNC_RESULT void DeleteSpaceGeoLocation(const csp::common::String& SpaceId, NullResultCallback Callback);

/// @brief Duplicate an existing space and assign it to the current user
/// @brief Duplicate an existing space and assign it to the current user.
/// This is a synchronous operation and can have a high execution time for complex spaces.
/// \deprecated Use DuplicateSpaceAsync() instead. This method performs a synchronous duplication of a Space which can timeout and fail for
/// complex Spaces or if the backend services are under excessive load.
/// @param SpaceId csp::common::String : Id of the space to duplicate.
/// @param NewName csp::common::String : A unique name for the duplicated space.
/// @param NewAttributes csp::systems::SpaceAttributes : Attributes to apply to the duplicated space.
/// @param MemberGroupIds csp::common::Array<csp::common::String> : An optional array of group (space) IDs to copy users from.
/// @param MemberGroupIds csp::common::Array<csp::common::String> : An optional array of group (space) IDs. Members of these groups will be added
/// to the duplicated space with the same roles.
/// @param ShallowCopy bool : If true, the duplicated space will reference the assets of the original space. Otherwise, all assets will be
/// duplicated.
/// @param Callback NullResultCallback : callback when asynchronous task finishes
/// @param Callback SpaceResultCallback : callback when asynchronous task finishes.
CSP_ASYNC_RESULT void DuplicateSpace(const csp::common::String& SpaceId, const csp::common::String& NewName, SpaceAttributes NewAttributes,
const csp::common::Optional<csp::common::Array<csp::common::String>>& MemberGroupIds, bool ShallowCopy, SpaceResultCallback Callback);

/// @brief Duplicate an existing space and assign it to the current user.
/// This is an asynchronous operation. Please subcribe to the AsyncCallCompletedCallback via @ref SpaceSystem::SetAsyncCallCompletedCallback() to
/// be notified when the duplication operation is complete. The AsyncCallCompletedEventData returned by the AsyncCallCompletedCallback will
/// contain the following information:
/// - OperationName: "DuplicateSpaceAsync".
/// - ReferenceId: Id of the newly duplicated Space.
/// - ReferenceType: "GroupId".
/// @param SpaceId csp::common::String : Id of the space to duplicate.
/// @param NewName csp::common::String : A unique name for the duplicated space.
/// @param NewAttributes csp::systems::SpaceAttributes : Attributes to apply to the duplicated space.
/// @param MemberGroupIds csp::common::Array<csp::common::String> : An optional array of group (space) IDs. Members of these groups will be added
/// to the duplicated space with the same roles.
/// @param ShallowCopy bool : If true, the duplicated space will reference the assets of the original space. Otherwise, all assets will be
/// duplicated.
/// @param Callback NullResultCallback : callback when asynchronous task is successfully received by the backend services.
CSP_ASYNC_RESULT void DuplicateSpaceAsync(const csp::common::String& SpaceId, const csp::common::String& NewName, SpaceAttributes NewAttributes,
const csp::common::Optional<csp::common::Array<csp::common::String>>& MemberGroupIds, bool ShallowCopy, NullResultCallback Callback);

///@}

/// @brief The callback for receiving an alert when an async operation is completed.
/// Currently this callback is only being used for the DuplicateSpaceAsync operation.
/// A callback can be set via @ref SpaceSystem::SetAsyncCallCompletedCallback().
typedef std::function<void(const csp::common::AsyncCallCompletedEventData&)> AsyncCallCompletedCallbackHandler;

/// @brief Sets a callback for the async call completed event. Triggered when an async call to DuplicateSpace is completed.
/// @param Callback AsyncCallCompletedCallbackHandler: Callback to receive data concerning the Space duplication.
CSP_EVENT void SetAsyncCallCompletedCallback(AsyncCallCompletedCallbackHandler Callback);

/// @brief Deserialises the AsyncCallCompleted event values.
/// The AsyncCallCompletedEventData returned by the AsyncCallCompletedCallback will contain the following information:
/// - OperationName: "DuplicateSpaceAsync".
/// - ReferenceId: Id of the newly duplicated Space.
/// - ReferenceType: "GroupId".
/// @param EventValues std::vector<signalr::value> : event values to deserialise
CSP_NO_EXPORT void OnAsyncCallCompletedEvent(const csp::common::NetworkEventData& NetworkEventData);

private:
SpaceSystem(); // This constructor is only provided to appease the wrapper generator and should not be used
SpaceSystem(csp::web::WebClient* InWebClient, csp::common::LogSystem& LogSystem);
SpaceSystem(csp::web::WebClient* WebClient, csp::multiplayer::NetworkEventBus& EventBus, csp::common::LogSystem& LogSystem);
~SpaceSystem();

// Space Metadata
Expand All @@ -376,6 +415,8 @@ class CSP_API CSP_NO_DISPOSE SpaceSystem : public SystemBase

void GetSpaceGeoLocationInternal(const csp::common::String& SpaceId, SpaceGeoLocationResultCallback Callback);

AsyncCallCompletedCallbackHandler AsyncCallCompletedCallback;

// CreateSpace Continuations
async::task<SpaceResult> CreateSpaceGroupInfo(const csp::common::String& Name, const csp::common::String& Description, SpaceAttributes Attributes,
const csp::common::Optional<csp::common::Array<csp::common::String>>& Tags);
Expand Down
8 changes: 6 additions & 2 deletions Library/include/CSP/Systems/SystemBase.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,17 @@ namespace csp::systems
{
/// @brief Base class for all Connected Spaces Platform Systems, which enforces passing of a WebClient or NetworkEventBus instance in the constructor
/// of each System.
/// @invariant EventBusPtr can never be null. The NetworkEventBus is owned by the MultiplayerConnection and persists for it's lifetime. It is passed
/// to each system (which derive from SystemBase) by reference to their ctor. This ref is dereferenced before being passed to the SystemBase ctor.
/// @invariant LogSystem can never be null. The LogSystem is owned by the SystemsManager and persists for it's lifetime. It is passed to
/// each system (which derive from SystemBase) by reference to their ctor. This ref is dereferenced before being passed to the SystemBase ctor.
class CSP_API CSP_NO_DISPOSE SystemBase
{
friend class csp::multiplayer::MultiplayerConnection;

protected:
CSP_NO_EXPORT SystemBase(csp::web::WebClient* InWebClient, csp::multiplayer::NetworkEventBus* InEventBus, csp::common::LogSystem* LogSystem);
CSP_NO_EXPORT SystemBase(csp::multiplayer::NetworkEventBus* InEventBus, csp::common::LogSystem* LogSystem);
CSP_NO_EXPORT SystemBase(csp::web::WebClient* InWebClient, csp::multiplayer::NetworkEventBus* EventBus, csp::common::LogSystem* LogSystem);
CSP_NO_EXPORT SystemBase(csp::multiplayer::NetworkEventBus* EventBus, csp::common::LogSystem* LogSystem);

csp::web::WebClient* WebClient;
csp::multiplayer::NetworkEventBus* EventBusPtr;
Expand Down
3 changes: 1 addition & 2 deletions Library/include/CSP/Systems/SystemsManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ class CSP_API SystemsManager

csp::multiplayer::MultiplayerConnection* GetMultiplayerConnection();

csp::multiplayer::NetworkEventBus* GetEventBus();
csp::multiplayer::NetworkEventBus& GetEventBus();

// Convenience methods for the moment. This will need to be broken at formal modularization, but the standard pattern it creates throughout
// integrations/tests will no doubt be helpful in doing that anyhow, rather than having big constructors everywhere.
Expand All @@ -198,7 +198,6 @@ class CSP_API SystemsManager
csp::web::WebClient* WebClient;

csp::multiplayer::MultiplayerConnection* MultiplayerConnection;
csp::multiplayer::NetworkEventBus* NetworkEventBus;
std::shared_ptr<csp::common::IRealtimeEngine> RealtimeEngine;
UserSystem* UserSystem;
SpaceSystem* SpaceSystem;
Expand Down
2 changes: 1 addition & 1 deletion Library/include/CSP/Systems/Users/UserSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ class CSP_API UserSystem : public SystemBase
// Emergency Fix: We have a circular dependency issue due to SignalR requiring the AuthContext for construction. To get around this
// we pass nullptr to the UserSystem ctor for the NetworkEventBus, and then call this method to set it after the NetworkEventBus has been
// constructed.
void SetNetworkEventBus(csp::multiplayer::NetworkEventBus* EventBus);
void SetNetworkEventBus(csp::multiplayer::NetworkEventBus& EventBus);

[[nodiscard]] bool EmailCheck(const std::string& Email) const;

Expand Down
12 changes: 6 additions & 6 deletions Library/src/Multiplayer/Election/ClientElectionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -484,21 +484,21 @@ bool ClientElectionManager::IsConnected() const

void ClientElectionManager::BindNetworkEvents()
{
NetworkEventBus* NetworkEventBus = OnlineRealtimeEnginePtr->GetMultiplayerConnectionInstance()->GetEventBusPtr();
NetworkEventBus& NetworkEventBus = OnlineRealtimeEnginePtr->GetMultiplayerConnectionInstance()->GetEventBus();

NetworkEventBus->ListenNetworkEvent(csp::multiplayer::NetworkEventRegistration("CSPInternal::ClientElectionManager", ClientElectionMessage),
NetworkEventBus.ListenNetworkEvent(csp::multiplayer::NetworkEventRegistration("CSPInternal::ClientElectionManager", ClientElectionMessage),
[this](const csp::common::NetworkEventData& NetworkEventData) { this->OnClientElectionEvent(NetworkEventData.EventValues); });

NetworkEventBus->ListenNetworkEvent(csp::multiplayer::NetworkEventRegistration("CSPInternal::ClientElectionManager", RemoteRunScriptMessage),
NetworkEventBus.ListenNetworkEvent(csp::multiplayer::NetworkEventRegistration("CSPInternal::ClientElectionManager", RemoteRunScriptMessage),
[this](const csp::common::NetworkEventData& NetworkEventData) { this->OnRemoteRunScriptEvent(NetworkEventData.EventValues); });
}

void ClientElectionManager::UnBindNetworkEvents()
{
NetworkEventBus* NetworkEventBus = OnlineRealtimeEnginePtr->GetMultiplayerConnectionInstance()->GetEventBusPtr();
NetworkEventBus& NetworkEventBus = OnlineRealtimeEnginePtr->GetMultiplayerConnectionInstance()->GetEventBus();

NetworkEventBus->StopListenNetworkEvent(csp::multiplayer::NetworkEventRegistration("CSPInternal::ClientElectionManager", ClientElectionMessage));
NetworkEventBus->StopListenNetworkEvent(csp::multiplayer::NetworkEventRegistration("CSPInternal::ClientElectionManager", RemoteRunScriptMessage));
NetworkEventBus.StopListenNetworkEvent(csp::multiplayer::NetworkEventRegistration("CSPInternal::ClientElectionManager", ClientElectionMessage));
NetworkEventBus.StopListenNetworkEvent(csp::multiplayer::NetworkEventRegistration("CSPInternal::ClientElectionManager", RemoteRunScriptMessage));
}

void ClientElectionManager::OnClientElectionEvent(const csp::common::Array<csp::common::ReplicatedValue>& Data)
Expand Down
8 changes: 4 additions & 4 deletions Library/src/Multiplayer/MultiplayerConnection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ MultiplayerConnection::MultiplayerConnection(csp::common::LogSystem& LogSystem,
, Connected(false)
, MultiplayerHubMethods(MultiplayerHubMethodMap())
{
EventBusPtr = new NetworkEventBus(this, LogSystem);
EventBus = new NetworkEventBus(this, LogSystem);
}

MultiplayerConnection::~MultiplayerConnection()
Expand All @@ -170,7 +170,7 @@ MultiplayerConnection::~MultiplayerConnection()
delete (Connection);
delete (WebSocketClient);
delete (NetworkEventManager);
delete (EventBusPtr);
delete (EventBus);
}
}

Expand All @@ -191,7 +191,7 @@ MultiplayerConnection::MultiplayerConnection(const MultiplayerConnection& InBoun
DisconnectionCallback = InBoundConnection.DisconnectionCallback;
ConnectionCallback = InBoundConnection.ConnectionCallback;
NetworkInterruptionCallback = InBoundConnection.NetworkInterruptionCallback;
EventBusPtr = InBoundConnection.EventBusPtr;
EventBus = InBoundConnection.EventBus;
Connected = (InBoundConnection.Connected) ? true : false;
}

Expand Down Expand Up @@ -373,7 +373,7 @@ void MultiplayerConnection::Connect(ErrorCodeCallbackHandler Callback, [[maybe_u
BindOnRequestToSendObject();
BindOnRequestToDisconnect();

EventBusPtr->StartEventMessageListening();
EventBus->StartEventMessageListening();

// We register the network interruption callback as a wrapper because we want to unwrap any signalR exceptions.
RegisterNetworkInterruptedCallback(Connection, LogSystem, NetworkInterruptionCallback);
Expand Down
2 changes: 2 additions & 0 deletions Library/src/Multiplayer/NetworkEventBus.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ std::unique_ptr<csp::common::NetworkEventData> NetworkEventBus::DeserialiseForEv
return std::make_unique<AccessControlChangedNetworkEventData>(csp::multiplayer::DeserializeAccessControlChangedEvent(EventValues, LogSystem));
case NetworkEvent::GeneralPurposeEvent:
return std::make_unique<NetworkEventData>(csp::multiplayer::DeserializeGeneralPurposeEvent(EventValues, LogSystem));
case NetworkEvent::AsyncCallCompleted:
return std::make_unique<AsyncCallCompletedEventData>(csp::multiplayer::DeserializeAsyncCallCompletedEvent(EventValues, LogSystem));
default:
throw std::invalid_argument(
fmt::format("DeserialiseForEventType: unknown enum value {}", static_cast<std::underlying_type_t<NetworkEvent>>(EventType)));
Expand Down
13 changes: 13 additions & 0 deletions Library/src/Multiplayer/NetworkEventSerialisation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -418,4 +418,17 @@ csp::common::SequenceChangedNetworkEventData DeserializeSequenceHotspotChangedEv

return ParsedEvent;
}

csp::common::AsyncCallCompletedEventData DeserializeAsyncCallCompletedEvent(
const std::vector<signalr::value>& EventValues, csp::common::LogSystem& LogSystem)
{
csp::common::AsyncCallCompletedEventData ParsedEvent {};
PopulateCommonEventData(EventValues, ParsedEvent, LogSystem);

ParsedEvent.OperationName = ParsedEvent.EventValues[0].GetString();
ParsedEvent.ReferenceId = ParsedEvent.EventValues[1].GetString();
ParsedEvent.ReferenceType = ParsedEvent.EventValues[2].GetString();

return ParsedEvent;
}
}
Loading