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 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(); }
private bool ServerRemote_OnClientInteractStart(IWorldObject worldObject) { var character = ServerRemoteContext.Character; if (worldObject is null || !worldObject.ProtoWorldObject.SharedCanInteract(character, worldObject, writeToLog: true)) { // player is too far from the world object or world object is destroyed return(false); } InteractionCheckerSystem.SharedAbortCurrentInteraction(character); var proto = SharedGetProto(worldObject); proto.ServerOnClientInteract(character, worldObject); if (proto.IsAutoEnterPrivateScopeOnInteraction) { // enter private scope - containers will be sent to the player character Server.World.EnterPrivateScope(character, worldObject); } // register private scope exit on interaction cancel InteractionCheckerSystem.SharedRegister( character, worldObject, finishAction: isAbort => { if (worldObject.IsDestroyed) { return; } this.ServerFinishInteractionInternal(character, worldObject); if (isAbort) { // notify client this.CallClient(character, _ => this.ClientRemote_FinishInteraction(worldObject)); } }); Logger.Info($"Started object interaction with {worldObject} for {character}"); return(true); }
public bool ServerGather(IStaticWorldObject worldObject, ICharacter character) { var privateState = GetPrivateState(worldObject); if (privateState.IsDropListSpawned) { // this loot container was already search - drop list was already spawned return(true); } // spawn items accordingly to the droplist privateState.IsDropListSpawned = true; var lootDroplist = this.ServerGetLootDroplist(worldObject); var dropItemContext = new DropItemContext(character, worldObject); CreateItemResult dropItemResult; var attemptRemains = 100; var itemsContainer = privateState.ItemsContainer; do { dropItemResult = lootDroplist.TryDropToContainer(itemsContainer, dropItemContext); } // ensure that at least something is spawned... // perhaps that's not a good idea, but we have an attempts limit while (dropItemResult.TotalCreatedCount == 0 && --attemptRemains > 0); Server.Items.SetSlotsCount(itemsContainer, (byte)itemsContainer.OccupiedSlotsCount); character.ServerAddSkillExperience <SkillSearching>(SkillSearching.ExperienceAddWhenSearching); Server.World.EnterPrivateScope(character, worldObject); // register private scope exit on interaction cancel InteractionCheckerSystem.SharedRegister( character, worldObject, finishAction: isAbort => { if (worldObject.IsDestroyed) { return; } Server.World.ExitPrivateScope(character, worldObject); if (isAbort) { // notify client this.CallClient(character, _ => _.ClientRemote_FinishInteraction(worldObject)); } if (this.IsAutoDestroyWhenLooted) { // container was closed - destroy it Server.World.DestroyObject(worldObject); } }); Logger.Important($"Started object interaction with {worldObject} for {character}"); this.CallClient(character, _ => _.ClientRemote_OnContainerOpened(worldObject)); return(true); }
public bool SharedStartAction(TActionRequest request) { if (request is null) { return(false); } var character = request.Character; var characterPrivateState = PlayerCharacter.GetPrivateState(character); if (characterPrivateState.CurrentActionState is TActionState existingState && this.SharedIsSameAction(existingState, request)) { // the same action is already in process Logger.Info( $"Action cannot be started: {request} - already performing the same action", character); return(false); } try { this.SharedValidateRequest(request); } catch (Exception ex) { Logger.Info( $"Action cannot be started: {request} the request is not valid: {Environment.NewLine}{ex.Message}", character); return(false); } var state = this.SharedTryCreateState(request); if (state is null) { Logger.Info( "Action cannot be started: " + request, character); return(false); } state.Request = request; InteractionCheckerSystem.CancelCurrentInteraction(character); characterPrivateState.SetCurrentActionState(state); Logger.Info("Action started: " + request, character); if (IsClient) { this.ClientOnStartActionCompleted(request, state); } if (state.TargetWorldObject is not null) { InteractionCheckerSystem.SharedRegister( character, state.TargetWorldObject, finishAction: isAbort => { if (!isAbort) { return; } Logger.Warning( $"InteractionCheckerSystem interaction check failed - cancelling \"{this.ShortId}\" action: {state}", character); this.SharedAbortActionInternal(character, state.Request); }); } return(true); }
public bool ServerGather(IStaticWorldObject worldObject, ICharacter character) { var privateState = GetPrivateState(worldObject); if (privateState.IsDropListSpawned) { // this loot container was already search - drop list was already spawned return(true); } // spawn items accordingly to the droplist privateState.IsDropListSpawned = true; var skillExperienceToAdd = SkillSearching.ExperienceAddWhenSearching * this.SearchingSkillExperienceMultiplier; var lootDroplist = this.ServerGetLootDroplist(worldObject); var dropItemContext = new DropItemContext(character, worldObject); CreateItemResult dropItemResult; if (this.IsAutoTakeAll) { // try to simply pickup the content dropItemResult = lootDroplist.TryDropToCharacter(character, dropItemContext, sendNoFreeSpaceNotification: false); if (dropItemResult.IsEverythingCreated && dropItemResult.TotalCreatedCount > 0) { NotificationSystem.ServerSendItemsNotification(character, dropItemResult); Server.World.DestroyObject(worldObject); // destroy object after success pickup character.ServerAddSkillExperience <SkillSearching>(skillExperienceToAdd); ServerLootEventHelper.OnLootReceived(character, worldObject); return(true); } dropItemResult.Rollback(); } // create a container and drop items there var attemptRemains = 100; var itemsContainer = privateState.ItemsContainer; do { dropItemResult = lootDroplist.TryDropToContainer(itemsContainer, dropItemContext); } // ensure that at least something is spawned... // perhaps that's not a good idea, but we have an attempts limit while (dropItemResult.TotalCreatedCount == 0 && --attemptRemains > 0); Server.Items.SetSlotsCount(itemsContainer, itemsContainer.OccupiedSlotsCount); character.ServerAddSkillExperience <SkillSearching>(skillExperienceToAdd); ServerLootEventHelper.OnLootReceived(character, worldObject); Server.World.EnterPrivateScope(character, worldObject); // register private scope exit on interaction cancel InteractionCheckerSystem.SharedRegister( character, worldObject, finishAction: isAbort => { if (worldObject.IsDestroyed) { return; } Server.World.ExitPrivateScope(character, worldObject); if (isAbort) { // notify client this.CallClient(character, _ => _.ClientRemote_FinishInteraction(worldObject)); } if (this.IsAutoDestroyWhenLooted) { // container was closed - destroy it Server.World.DestroyObject(worldObject); } }); Logger.Important($"Started object interaction with {worldObject} for {character}"); this.CallClient(character, _ => _.ClientRemote_OnContainerOpened(worldObject)); return(true); }
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(); } }