private void ClientRemote_OnContainerOpened(IStaticWorldObject worldObject) { var privateState = GetPrivateState(worldObject); var itemsContainer = privateState.ItemsContainer; var soundClose = Client.UI.GetApplicationResource<SoundUI>("SoundWindowContainerClose"); var menuWindow = WindowContainerExchange.Show( itemsContainer, soundClose: soundClose, isAutoClose: true); var character = Client.Characters.CurrentPlayerCharacter; InteractionCheckerSystem.SharedRegister( character, worldObject, finishAction: _ => menuWindow.CloseWindow()); ClientInteractionUISystem.Register( worldObject, menuWindow, onMenuClosedByClient: () => { InteractionCheckerSystem.SharedUnregister(character, worldObject, isAbort: false); if (!worldObject.IsDestroyed) { this.CallServer(_ => _.ServerRemote_OnClientInteractFinish(worldObject)); } }); Logger.Important("Started object interaction with " + worldObject); ClientCurrentInteractionMenu.RegisterMenuWindow(menuWindow); ClientCurrentInteractionMenu.Open(); }
protected override void ClientInteractStart(ClientObjectData data) { var worldObject = data.GameObject; var character = Client.Characters.CurrentPlayerCharacter; var menuWindow = WindowCraftingStation.Open(this); ClientCurrentInteractionMenu.RegisterMenuWindow(menuWindow); InteractionCheckerSystem.SharedRegister( character, worldObject, finishAction: _ => menuWindow.CloseWindow()); ClientInteractionUISystem.Register( worldObject, menuWindow, onMenuClosedByClient: () => InteractionCheckerSystem.SharedUnregister( character, worldObject, isAbort: false)); ClientCurrentInteractionMenu.Open(); }
private void ServerRemote_OnClientInteractFinish(IStaticWorldObject worldObject) { var character = ServerRemoteContext.Character; if (!InteractionCheckerSystem.SharedUnregister(character, worldObject, isAbort: false)) { return; } Logger.Important($"Client {character} informed that the object interaction with {worldObject} is finished"); }
private void SharedAbortActionInternal(ICharacter character, TActionRequest request) { var characterPrivateState = PlayerCharacter.GetPrivateState(character); var state = characterPrivateState.CurrentActionState; if (!(state is TActionState actionState)) { // no action or action of another state type return; } if (!request.Equals(actionState.Request)) { // different request active return; } if (!state.IsCompleted) { // reset action state actionState.Cancel(); // return now - because this method was just called again by SetCurrentActionState return; } // ensure the action state is reset characterPrivateState.SetCurrentActionState(null); Logger.Info("Action cancelled: " + state, character); if (state.TargetWorldObject is not null) { InteractionCheckerSystem.SharedUnregister(character, state.TargetWorldObject, isAbort: false); } if (IsClient && !state.IsCancelledByServer) { Logger.Info("Sending action abort request: " + request); Instance.CallServer(_ => _.ServerRemote_AbortAction(request)); } else if (IsServer && !ServerRemoteContext.IsRemoteCall) { Instance.CallClient(character, _ => _.ClientRemote_AbortAction(request)); // TODO: notify other players as well } }
public void SharedOnActionCompleted(TActionState state) { var character = state.Character; var request = state.Request; Logger.Info("Action completed: " + request, character); if (state.TargetWorldObject is not null) { InteractionCheckerSystem.SharedUnregister(character, state.TargetWorldObject, isAbort: false); } var canComplete = true; try { // ensure the request is still valid this.SharedValidateRequest(request); } catch (Exception ex) { canComplete = false; Logger.Warning("Exception during completed action processing: " + ex.Message + Environment.NewLine + request); } if (canComplete) { try { this.SharedOnActionCompletedInternal(state, character); } catch (Exception ex) { Logger.Exception(ex, "Exception during completed action processing"); } } PlayerCharacter.GetPrivateState(character) .SetCurrentActionState(null); }
private async void ClientInteractStartAsync(IWorldObject worldObject) { if (this.isAwaitingServerInteraction) { return; } var character = Client.Characters.CurrentPlayerCharacter; if (InteractionCheckerSystem.SharedGetCurrentInteraction(character) == worldObject) { // already interacting with this object return; } this.isAwaitingServerInteraction = true; try { var requestId = ++lastRequestId; var isOpened = await this.CallServer(_ => _.ServerRemote_OnClientInteractStart(worldObject)); if (!isOpened || requestId != lastRequestId) { return; } } finally { this.isAwaitingServerInteraction = false; } var objectWindow = SharedGetProto(worldObject).ClientOpenUI(worldObject); if (objectWindow is null) { Logger.Info("Cannot open menu for object interaction with " + worldObject); this.CallServer(_ => _.ServerRemote_OnClientInteractFinish(worldObject)); return; } Api.SafeInvoke(() => ClientMenuCreated?.Invoke(worldObject, objectWindow)); if (!(objectWindow is IMenu)) { ClientCurrentInteractionMenu.RegisterMenuWindow(objectWindow); } else { ClientCurrentInteractionMenu.TryCloseCurrentMenu(); } InteractionCheckerSystem.SharedRegister( character, worldObject, finishAction: _ => objectWindow.CloseWindow()); ClientInteractionUISystem.Register( worldObject, objectWindow, onMenuClosedByClient: () => { InteractionCheckerSystem.SharedUnregister(character, worldObject, isAbort: false); if (!worldObject.IsDestroyed) { ++lastRequestId; this.CallServer(_ => _.ServerRemote_OnClientInteractFinish(worldObject)); } }); Logger.Info("Started object interaction with " + worldObject); if (objectWindow is IMenu objectMenu) { if (!objectMenu.IsOpened) { objectMenu.Toggle(); } } else { ClientCurrentInteractionMenu.Open(); } }
public static void ServerTryAbortInteraction(ICharacter character, IWorldObject worldObject) { InteractionCheckerSystem.SharedUnregister(character, worldObject, isAbort: true); }