void RPG_ActionHandler::PerformAction(RPG_ActionType_e const& action, bool forceAction /*= false*/, RPG_BaseEntity* const interactionEntity /*= NULL*/, hkvVec3 const& interactionPosition /*= hkvVec3(0, 0, 0)*/, int const flags /*= 0*/) { // if the action and the target are the same, we're just updating flags or interaction. bool updatingActionParams = false; if(m_activeAction.m_Action == action) { if(m_activeAction.m_interactionEntity != interactionEntity || !m_activeAction.m_interactionPosition.isIdentical(interactionPosition) || m_activeAction.m_flags != flags) { updatingActionParams = true; } } if(!forceAction && m_activeAction.m_Action != AT_None && action != AT_None) { // there's an action already playing, and we aren't forcing the new one. perfor more checks. if(m_Actions[m_activeAction.m_Action]->CanOverrideActionWith(action) || m_Actions[action]->CanThisActionOverride(m_activeAction.m_Action)) { forceAction = true; } } if (forceAction || updatingActionParams || CanPerformAction(action)) { // bundle the action into a struct for easier network replication RPG_ActionData actionData(action, interactionEntity, interactionPosition, flags); // simulate the action locally ProcessAction(actionData, forceAction); // replicate the action to the server //@todo: Once the network branch is integrated, here's where we replicate this action to the server. /* Work that needs to happen here: - Find out whether this is a non-authoritative client. - If all we're doing is updating action flags, preserve bandwidth by calling a client->server UpdateActionFlags() with just that data - If we're doing a new Action, call a client->server ProcessAction() using the constructed struct. */ } else if(action != AT_None && m_Actions[m_activeAction.m_Action]->CanChainAction(action)) { // can't process the new action, so check to see if we can chain it RPG_ActionData actionData(action, interactionEntity, interactionPosition, flags); m_pendingAction = actionData; } }
json_t * NetworkGroup::ToJson() const { json_t * jsonGroup = json_object(); json_object_set_new(jsonGroup, "id", json_integer(Id)); json_object_set_new(jsonGroup, "name", json_string(GetName().c_str())); json_t * actionsArray = json_array(); for (size_t i = 0; i < NetworkActions::Actions.size(); i++) { if (CanPerformAction(i)) { const char * perm_name = NetworkActions::Actions[i].PermissionName.c_str(); json_array_append_new(actionsArray, json_string(perm_name)); } } json_object_set_new(jsonGroup, "permissions", actionsArray); return jsonGroup; }
virtual void EnumerateActions(TArray<EFriendActionType::Type>& Actions, bool bFromChat = false) override { bool bIsFriendInSameSession = FriendsAndChatManager.Pin()->IsFriendInSameSession(FriendItem); if(FriendItem->IsGameRequest()) { if (FriendItem->IsGameJoinable()) { Actions.Add(EFriendActionType::JoinGame); } Actions.Add(EFriendActionType::RejectGame); } else if(FriendItem->IsPendingAccepted()) { Actions.Add(EFriendActionType::Updating); } else if (FriendItem->GetListType() == EFriendsDisplayLists::RecentPlayersDisplay) { TSharedPtr<IFriendItem> ExistingFriend = FriendsAndChatManager.Pin()->FindUser(*FriendItem->GetUniqueID()); if (!ExistingFriend.IsValid()) { Actions.Add(EFriendActionType::SendFriendRequest); } if (FriendsAndChatManager.Pin()->IsInJoinableGameSession() && FriendItem->IsOnline()) { Actions.Add(EFriendActionType::InviteToGame); } } else { switch (FriendItem->GetInviteStatus()) { case EInviteStatus::Accepted : { if (FriendItem->IsOnline() && !bIsFriendInSameSession && FriendItem->IsGameJoinable()) { if(CanPerformAction(EFriendActionType::JoinGame)) { Actions.Add(EFriendActionType::JoinGame); } } if (FriendItem->IsOnline() && !bIsFriendInSameSession && FriendItem->CanInvite() && FriendsAndChatManager.Pin()->IsInJoinableGameSession()) { Actions.Add(EFriendActionType::InviteToGame); } if(!bFromChat) { if (FriendItem->IsOnline()) { Actions.Add(EFriendActionType::Chat); } Actions.Add(EFriendActionType::RemoveFriend); } } break; case EInviteStatus::PendingInbound : { Actions.Add(EFriendActionType::AcceptFriendRequest); Actions.Add(EFriendActionType::IgnoreFriendRequest); } break; case EInviteStatus::PendingOutbound : { Actions.Add(EFriendActionType::CancelFriendRequest); } break; default: Actions.Add(EFriendActionType::SendFriendRequest); break; } } }
void RPG_ActionHandler::ProcessAction(RPG_ActionData const& actionData, bool const forceAction /*= false*/) { // if we're already doing the requested move, ignore the call except to update flags or interaction entities. if (actionData.m_Action == m_activeAction.m_Action) { // same move, updated flags if (actionData.m_Action != AT_None && actionData.m_flags != m_activeAction.m_flags) { m_activeAction.m_flags = actionData.m_flags; //@todo: if this is happening on the authoritative server, replicate this flag change to clients. if (m_Actions[actionData.m_Action]) { m_Actions[actionData.m_Action]->UpdateFlags(actionData.m_flags); } } // same move, updated interaction entity if(actionData.m_interactionEntity != m_activeAction.m_interactionEntity || !actionData.m_interactionPosition.isIdentical(m_activeAction.m_interactionPosition)) { m_activeAction.m_interactionEntity = actionData.m_interactionEntity; m_activeAction.m_interactionPosition = actionData.m_interactionPosition; if(m_Actions[actionData.m_Action]) { m_Actions[actionData.m_Action]->UpdateInteraction(actionData.m_interactionEntity, actionData.m_interactionPosition); // clear the pending action, as enough data has changed for the pending action to probably not be the desired behavior. m_pendingAction.Clear(); } } // clear the pending action if this was forced if(forceAction) { m_pendingAction.Clear(); } // no further action required, since this isn't a new move. return; } // if we're chaining from an action that needs to complete first, defer this action if (m_endingAction) { m_pendingAction = actionData; return; } // verify that we can do this move if (actionData.m_Action != AT_None && !forceAction && !m_chainingAction && !CanPerformAction(actionData.m_Action)) { Vision::Error.Warning("Cannot perform requested Action."); return; } // ready to go. m_previousAction = m_activeAction; // stop the previous action, if any if (m_activeAction.m_Action != AT_None) { m_endingAction = true; m_activeAction.m_Action = AT_None; RPG_ActionType_e nextAction = actionData.m_Action; if (nextAction == AT_None && m_pendingAction.m_Action != AT_None) { nextAction = m_pendingAction.m_Action; } CleanUpAction(m_previousAction.m_Action, nextAction); m_endingAction = false; } // if we need to start a pending action, do it now if (actionData.m_Action == AT_None && m_pendingAction.m_Action != AT_None) { // Recursively Process the pending action if one exists. m_chainingAction = true; m_activeAction.m_Action = m_previousAction.m_Action; // restore this value, since the pending action call will need it. ProcessAction(m_pendingAction); m_chainingAction = false; if (m_activeAction.m_Action == m_pendingAction.m_Action) { m_pendingAction.Clear(); return; } } // set the new Action m_activeAction = actionData; // @todo: Once the network branch is in, replicate these values. // - m_replicatedAction = m_activeAction; // - force net update if (m_activeAction.m_Action != AT_None) { StartAction(m_activeAction.m_Action, m_previousAction.m_Action, forceAction, m_activeAction.m_interactionEntity, m_activeAction.m_interactionPosition, m_activeAction.m_flags); // if this was a forced action, clear any pending action, as this was an interrupt of the current action if (forceAction) { m_pendingAction.Clear(); } } }