public override void SharedUpdate(double deltaTime) { // don't invoke the base SharedUpdate implementation as we don't advance the timer here if (!ReferenceEquals(this.ItemFishingRod, this.CharacterPublicState.SelectedItem)) { // player changed the selected item this.SetCompleted(isCancelled: true); this.AbortAction(); return; } if (FishingSystem.SharedIsTooFar(this.Character, this.FishingTargetPosition)) { if (Api.IsClient) { CannotInteractMessageDisplay.ClientOnCannotInteract(this.Character, CoreStrings.Notification_TooFar, isOutOfRange: true); } this.Cancel(); return; } if (this.SharedFishingSession != null && this.SharedFishingSession.IsDestroyed) { this.Complete(); } }
protected override void SharedValidateRequest(WorldActionRequest request) { var worldObject = request.WorldObject; if (!(worldObject?.ProtoWorldObject is IProtoObjectGatherable)) { throw new Exception("The world object must be gatherable"); } if (!worldObject.ProtoWorldObject.SharedCanInteract(request.Character, worldObject, true)) { throw new Exception("Cannot interact with " + worldObject); } if (!(worldObject.ProtoGameObject is IProtoObjectGatherable protoGatherable)) { throw new Exception("Not a gatherable resource: " + worldObject); } if (!protoGatherable.SharedIsCanGather((IStaticWorldObject)worldObject)) { Logger.Warning("Cannot gather now: " + worldObject, request.Character); if (Api.IsClient) { CannotInteractMessageDisplay.ShowOn(worldObject, NotificationNothingToHarvestYet); worldObject.ProtoWorldObject.SharedGetObjectSoundPreset() .PlaySound(ObjectSound.InteractFail); } throw new Exception("Cannot gather now: " + worldObject); } }
public static bool SharedIsTargetAlreadyScheduledForAnyActiveDrone( ICharacter character, Vector2Ushort worldPosition, bool logError) { foreach (var objectDrone in character.SharedGetCurrentlyControlledDrones()) { var droneTargetPosition = objectDrone.GetPublicState <DronePublicState>() .TargetObjectPosition; if (droneTargetPosition != worldPosition) { continue; } // the drone is already sent there if (logError) { if (IsServer) { Logger.Info("Drone already sent there: " + worldPosition, character); } else { CannotInteractMessageDisplay.ClientOnCannotInteract(ClientCurrentCharacterHelper.Character, Notification_DroneAlreadySent, isOutOfRange: false); } } return(true); } return(false); }
protected override async void ClientInteractStart(ClientObjectData data) { var bedObject = data.GameObject; var (isSuccess, name) = await this.CallServer(_ => _.ServerRemote_GetBedOwnerName(bedObject)); if (!isSuccess) { ClientOnCannotInteract(bedObject, CoreStrings.Notification_TooFar, isOutOfRange: true); return; } var isFree = string.IsNullOrEmpty(name); if (isFree) { DialogWindow.ShowDialog( DialogClaimBed_Title, DialogClaimBed_Message, okText: CoreStrings.Yes, okAction: () => this.ClientMakeCurrentBed(bedObject), hideCancelButton: false); return; } var message = name == Client.Characters.CurrentPlayerCharacter.Name ? MessageBedBelongsToCurrentPlayer : string.Format(MessageFormatBedBelongsToAnotherPlayer, name); CannotInteractMessageDisplay.ShowOn(bedObject, message); this.SoundPresetObject.PlaySound(ObjectSound.InteractSuccess); }
public static bool ClientTryStartDrone( IItem itemDrone, Vector2Ushort worldPosition, bool showErrorNotification) { var character = ClientCurrentCharacterHelper.Character; if (SharedIsMaxDronesToControlNumberExceeded(character, showErrorNotification) || SharedIsTargetAlreadyScheduledForAnyActiveDrone(character, worldPosition, showErrorNotification)) { return(false); } var targetObject = SharedGetCompatibleTarget(character, worldPosition, out var hasIncompatibleTarget, out var isPveActionForbidden); if (targetObject is null) { // nothing to mine there if (showErrorNotification) { if (isPveActionForbidden) { PveSystem.ClientShowNotificationActionForbidden(); } CannotInteractMessageDisplay.ClientOnCannotInteract( character, hasIncompatibleTarget ? Notification_CannotMineThat : Notification_NothingToMineThere, isOutOfRange: false); } return(false); } if (!SharedIsValidStartLocation(character, worldPosition, out var hasObstacles)) { if (showErrorNotification) { CannotInteractMessageDisplay.ClientOnCannotInteract( character, hasObstacles ? CoreStrings.Notification_ObstaclesOnTheWay : CoreStrings.Notification_TooFar, isOutOfRange: true); } return(false); } ClientDroneStartQueue.Add(itemDrone, worldPosition); return(true); }
protected BaseUserControlWithWindow ClientOpenUI(ClientObjectData data) { var worldObject = data.GameObject; var publicState = data.SyncPublicState; if (worldObject.ClientHasPrivateState && !Client.Input.IsKeyHeld(InputKey.Alt)) { // open admin window return(WindowTradingStationAdmin.Open( new ViewModelWindowTradingStationAdmin(worldObject, data.SyncPrivateState, publicState))); } // open user window (if has any lots) if (publicState.Lots.Any(l => l.State != TradingStationLotState.Disabled)) { return(WindowTradingStationUser.Open( new ViewModelWindowTradingStationUser(worldObject, publicState))); } CannotInteractMessageDisplay.ShowOn(worldObject, publicState.Mode == TradingStationMode.StationSelling ? NotificationNothingForSale : NotificationNoTradingLots); return(null); }
public static void ClientOnCannotInteract( IWorldObject worldObject, string message, bool isOutOfRange = false) { CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject, message, isOutOfRange); }
public static void ClientOnCannotInteractNotOwner(IWorldObject worldObject, bool isFactionAccess) { var message = isFactionAccess ? WorldObjectAccessModeSystem.NotificationDontHaveAccess : DialogCannotSetOwners_MessageNotOwner; CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject, message, isOutOfRange: false); }
private void RefreshAttachedComponent() { this.componentAttachedUIElement?.Destroy(); this.componentAttachedUIElement = null; var actionState = this.privateState.CurrentActionState; if (actionState is null || !actionState.IsDisplayingProgress) { return; } var targetWorldObject = actionState.TargetWorldObject; if (targetWorldObject is null) { // display over the character targetWorldObject = (IWorldObject)this.privateState.GameObject; } Vector2D offset = (0, 1.13); if (targetWorldObject == ClientCurrentCharacterHelper.Character && GeneralOptionDisplayHealthbarAboveCurrentCharacter.IsDisplay) { // adjust the offset so the circle will not overlap with the current character's name and healthbar offset += (0, 0.2); } switch (targetWorldObject.ProtoWorldObject) { case IProtoStaticWorldObject protoStaticWorldObject: offset += protoStaticWorldObject.SharedGetObjectCenterWorldOffset(targetWorldObject); break; case IProtoCharacter protoCharacter: offset += protoCharacter.SharedGetObjectCenterWorldOffset(targetWorldObject); break; } this.componentAttachedUIElement = Client.UI.AttachControl( targetWorldObject, new ActionProgressControl() { ActionState = actionState }, positionOffset: offset, isFocusable: false); CannotInteractMessageDisplay.Hide(); InteractionTooltip.Hide(); }
public virtual void ClientOnCannotInteract( TWorldObject worldObject, string message, bool isOutOfRange = false) { CannotInteractMessageDisplay.ShowOn(worldObject, message); var soundKey = isOutOfRange ? ObjectSound.InteractOutOfRange : ObjectSound.InteractFail; worldObject.ProtoWorldObject.SharedGetObjectSoundPreset() .PlaySound(soundKey); }
public static bool SharedCheckCanInteract( ICharacter character, IWorldObject worldObject, bool writeToLog) { if (worldObject == null || worldObject.IsDestroyed) { return(false); } // Can deconstruct only if the character can contact directly // with the object click area (if object has the click area) // or with the object collider (if object don't has the click area). var isObjectHasClickArea = worldObject.PhysicsBody .Shapes .Any(s => s.CollisionGroup == CollisionGroups.ClickArea); var result = worldObject.ProtoWorldObject.SharedIsInsideCharacterInteractionArea( character, worldObject, writeToLog: false, requiredCollisionGroup: isObjectHasClickArea ? CollisionGroups.ClickArea : CollisionGroups .DefaultWithCollisionToInteractionArea); if (result) { return(true); } if (writeToLog) { Logger.Warning( $"Cannot deconstruct - {character} cannot interact with the {worldObject} - there is no direct (physics) line of sight between them (the object click area or static/dynamic colliders must be inside the character interaction area)"); if (IsClient) { CannotInteractMessageDisplay.ShowOn(worldObject, CoreStrings.Notification_TooFar); worldObject.ProtoWorldObject.SharedGetObjectSoundPreset() .PlaySound(ObjectSound.InteractOutOfRange); } } return(false); }
private void RefreshAttachedComponent() { this.componentAttachedUIElement?.Destroy(); this.componentAttachedUIElement = null; var actionState = this.privateState.CurrentActionState; if (actionState is null || !actionState.IsDisplayingProgress) { return; } var targetWorldObject = actionState.TargetWorldObject; if (targetWorldObject is null) { // display over the character targetWorldObject = (IWorldObject)this.privateState.GameObject; } Vector2D offset = (0, 1.01); switch (targetWorldObject.ProtoWorldObject) { case IProtoStaticWorldObject protoStaticWorldObject: offset += protoStaticWorldObject.SharedGetObjectCenterWorldOffset(targetWorldObject); break; case IProtoCharacter protoCharacter: offset += protoCharacter.SharedGetObjectCenterWorldOffset(targetWorldObject); break; } this.componentAttachedUIElement = Client.UI.AttachControl( targetWorldObject, new ActionProgressControl() { ActionState = actionState }, positionOffset: offset, isFocusable: false); CannotInteractMessageDisplay.Hide(); InteractionTooltip.Hide(); }
protected override GatheringActionState SharedTryCreateState(WorldActionRequest request) { var worldObject = request.WorldObject; var character = request.Character; var staticWorldObject = (IStaticWorldObject)worldObject; if (!(worldObject.ProtoGameObject is IProtoObjectGatherable protoGatherable)) { throw new Exception("Not a gatherable resource: " + worldObject); } if (!protoGatherable.SharedIsCanGather(staticWorldObject)) { Logger.Warning("Cannot gather now: " + worldObject, character); if (Api.IsClient) { CannotInteractMessageDisplay.ShowOn(worldObject, NotificationNothingToHarvestYet); worldObject.ProtoWorldObject.SharedGetObjectSoundPreset() .PlaySound(ObjectSound.InteractFail); } return(null); } var durationSeconds = protoGatherable.DurationGatheringSeconds; var multiplier = protoGatherable.GetGatheringSpeedMultiplier(staticWorldObject, character); durationSeconds /= multiplier; if (CreativeModeSystem.SharedIsInCreativeMode(character)) { durationSeconds = 0.1; } return(new GatheringActionState( character, staticWorldObject, durationSeconds)); }
protected override void SharedValidateRequest(WorldActionRequest request) { var worldObject = (IStaticWorldObject)request.WorldObject; if (!(worldObject?.ProtoWorldObject is IProtoObjectGatherable protoGatherable)) { throw new Exception("The world object must be gatherable"); } if (!worldObject.ProtoWorldObject.SharedCanInteract(request.Character, worldObject, true)) { throw new Exception("Cannot interact with " + worldObject); } if (!WorldObjectClaimSystem.SharedIsAllowInteraction(request.Character, worldObject, showClientNotification: true)) { throw new Exception("Locked for another player: " + worldObject); } if (protoGatherable.SharedIsCanGather(worldObject)) { return; } Logger.Warning("Cannot gather now: " + worldObject, request.Character); if (Api.IsClient) { CannotInteractMessageDisplay.ShowOn(worldObject, NotificationNothingToHarvestYet); worldObject.ProtoWorldObject.SharedGetObjectSoundPreset() .PlaySound(ObjectSound.InteractFail); } throw new Exception("Cannot gather now: " + worldObject); }
protected override bool ClientItemUseFinish(ClientItemData data) { var character = ClientCurrentCharacterHelper.Character; var characterTilePosition = character.TilePosition; var mouseTilePosition = Client.Input.MousePointedTilePosition; var dronesNumberToLaunch = Api.Client.Input.IsKeyHeld(InputKey.Shift, evenIfHandled: true) ? this.MaxDronesToControl : 1; using var tempExceptDrones = Api.Shared.GetTempList <IItem>(); using var tempExceptTargets = Api.Shared.GetTempList <Vector2Ushort>(); for (var index = 0; index < dronesNumberToLaunch; index++) { var showErrorNotification = index == 0; var itemDrone = CharacterDroneControlSystem.ClientSelectNextDrone(tempExceptDrones.AsList()); if (itemDrone is null) { if (CharacterDroneControlSystem.SharedIsMaxDronesToControlNumberExceeded( character, clientShowErrorNotification: showErrorNotification)) { break; } if (showErrorNotification) { CannotInteractMessageDisplay.ClientOnCannotInteract( character, CharacterDroneControlSystem.Notification_ErrorNoDrones_Title, isOutOfRange: false); } break; } tempExceptDrones.Add(itemDrone); Vector2Ushort targetPosition; if (index == 0) { targetPosition = mouseTilePosition; var targetObject = CharacterDroneControlSystem .SharedGetCompatibleTarget(character, mouseTilePosition, out var hasIncompatibleTarget, out var isPveActionForbidden); if (targetObject is null) { if (showErrorNotification) { if (isPveActionForbidden) { PveSystem.ClientShowNotificationActionForbidden(); } CannotInteractMessageDisplay.ClientOnCannotInteract( character, hasIncompatibleTarget ? CharacterDroneControlSystem.Notification_CannotMineThat : CharacterDroneControlSystem.Notification_NothingToMineThere, isOutOfRange: false); } return(false); } if (!WorldObjectClaimSystem.SharedIsAllowInteraction(character, targetObject, showClientNotification: showErrorNotification)) { return(false); } if (CharacterDroneControlSystem.SharedIsTargetAlreadyScheduledForAnyActiveDrone( character, mouseTilePosition, logError: false)) { // already scheduled a drone mining there...try find another target of the same type targetPosition = TryGetNextTargetPosition(); if (targetPosition == default) { // no further targets CannotInteractMessageDisplay.ClientOnCannotInteract( character, CharacterDroneControlSystem.Notification_DroneAlreadySent, isOutOfRange: false); return(false); } } } else { targetPosition = TryGetNextTargetPosition(); if (targetPosition == default) { // no further targets break; } } if (!CharacterDroneControlSystem.ClientTryStartDrone(itemDrone, targetPosition, showErrorNotification: showErrorNotification)) { break; } tempExceptTargets.Add(targetPosition); } // always return false as we don't want to play any device sounds return(false); Vector2Ushort TryGetNextTargetPosition() { var targetObjectProto = CharacterDroneControlSystem .SharedGetCompatibleTarget(character, mouseTilePosition, out _, out _)? .ProtoWorldObject; if (targetObjectProto is null) { return(default);
public static bool SharedCheckCanInteract( ICharacter character, IWorldObject worldObject, bool writeToLog) { if (worldObject == null || worldObject.IsDestroyed) { return(false); } // Can build/repair only if the character can contact directly // with the object click area (if object has the click area) // or with the object collider (if object don't has the click area). var isObjectHasClickArea = worldObject.PhysicsBody.Shapes.Any(s => s.CollisionGroup == CollisionGroups.ClickArea); var result = worldObject.ProtoWorldObject.SharedIsInsideCharacterInteractionArea( character, worldObject, writeToLog: false, requiredCollisionGroup: isObjectHasClickArea ? CollisionGroups.ClickArea : CollisionGroups .DefaultWithCollisionToInteractionArea); if (!result) { if (writeToLog) { Logger.Warning( $"Cannot build/repair - {character} cannot interact with the {worldObject} - there is no direct (physics) line of sight between them (the object click area or static/dynamic colliders must be inside the character interaction area)"); if (IsClient) { CannotInteractMessageDisplay.ShowOn(worldObject, CoreStrings.Notification_TooFar); worldObject.ProtoWorldObject.SharedGetObjectSoundPreset() .PlaySound(ObjectSound.InteractOutOfRange); } } return(false); } if (worldObject is IStaticWorldObject staticWorldObject) { // ensure the building is not in an area under the raid var world = IsClient ? (IWorldService)Client.World : Server.World; var protoStaticWorldObject = staticWorldObject.ProtoStaticWorldObject; var validatorNoRaid = LandClaimSystem.ValidatorNoRaid; foreach (var tileOffset in protoStaticWorldObject.Layout.TileOffsets) { var occupiedTile = world.GetTile( worldObject.TilePosition.X + tileOffset.X, worldObject.TilePosition.Y + tileOffset.Y, logOutOfBounds: false); if (!occupiedTile.IsValidTile) { continue; } if (validatorNoRaid.Function( new ConstructionTileRequirements.Context( occupiedTile, character, protoStaticWorldObject, tileOffset))) { continue; } // raid is under way - cannot build/repair SharedShowCannotBuildNotification( character, validatorNoRaid.ErrorMessage, protoStaticWorldObject); return(false); } } return(true); }
public static void ClientStartRelocation(IStaticWorldObject objectStructure) { var protoStructure = objectStructure.ProtoStaticWorldObject; var character = Client.Characters.CurrentPlayerCharacter; if (IsInObjectPlacementMode || ConstructionPlacementSystem.IsInObjectPlacementMode) { // already relocating/placing something return; } if (!SharedIsRelocatable(objectStructure)) { return; } if (!CreativeModeSystem.SharedIsInCreativeMode(character) && !LandClaimSystem.SharedIsOwnedLand(objectStructure.TilePosition, character, requireFactionPermission: true, out var hasNoFactionPermission, out _)) { // the building location or destination is in an area that is not owned by the player SharedShowCannotRelocateNotification( character, protoStructure, hasNoFactionPermission); return; } var isPvEorWithinInteractionArea = PveSystem.SharedIsPve(false) || protoStructure.SharedIsInsideCharacterInteractionArea( Api.Client.Characters.CurrentPlayerCharacter, objectStructure, writeToLog: false); if (!isPvEorWithinInteractionArea) { CannotInteractMessageDisplay.ClientOnCannotInteract( character, CoreStrings.Notification_TooFar, isOutOfRange: true); return; } if (LandClaimSystem.SharedIsUnderRaidBlock(character, objectStructure)) { // the building is in an area under the raid ConstructionSystem.SharedShowCannotBuildNotification( character, LandClaimSystem.ErrorRaidBlockActionRestricted_Message, protoStructure); return; } if (LandClaimShieldProtectionSystem.SharedIsUnderShieldProtection(objectStructure)) { // the building is in an area under shield protection LandClaimShieldProtectionSystem.SharedSendNotificationActionForbiddenUnderShieldProtection( character); return; } ClientDisableConstructionRelocation(); var sceneObject = Client.Scene.CreateSceneObject("StructureRelocationHelper"); componentObjectPlacementHelper = sceneObject.AddComponent <ClientComponentObjectPlacementHelper>(); componentRelocationHelper = sceneObject.AddComponent <ClientComponentObjectRelocationHelper>(); componentObjectPlacementHelper .Setup(protoStructure, isCancelable: true, isRepeatCallbackIfHeld: false, isDrawConstructionGrid: true, isBlockingInput: true, validateCanPlaceCallback: ClientValidateCanRelocate, placeSelectedCallback: ClientConstructionPlaceSelectedCallback, delayRemainsSeconds: 0.1); componentObjectPlacementHelper.HideBlueprintOnOverlapWithTheSameObject = false; componentRelocationHelper.Setup(objectStructure); void ClientValidateCanRelocate( Vector2Ushort tilePosition, bool logErrors, out string errorMessage, out bool canPlace, out bool isTooFar) { if (tilePosition == objectStructure.TilePosition) { canPlace = true; isTooFar = false; errorMessage = null; return; } if (!SharedCheckTileRequirementsForRelocation(character, objectStructure, tilePosition, out errorMessage, logErrors: logErrors)) { // time requirements are not valid canPlace = false; isTooFar = false; return; } if (!SharedValidateCanCharacterRelocateStructure(character, objectStructure, tilePosition, out errorMessage, logErrors: logErrors)) { canPlace = true; isTooFar = true; return; } if (SharedHasObstacle( character, objectStructure, tilePosition.ToVector2D() + protoStructure.Layout.Center)) { if (logErrors) { CannotInteractMessageDisplay.ClientOnCannotInteract( character, CoreStrings.Notification_ObstaclesOnTheWay, isOutOfRange: true); } errorMessage = CoreStrings.Notification_ObstaclesOnTheWay; canPlace = true; isTooFar = true; return; } canPlace = true; isTooFar = false; } void ClientConstructionPlaceSelectedCallback(Vector2Ushort tilePosition) { if (SharedHasObstacle( character, objectStructure, tilePosition.ToVector2D() + protoStructure.Layout.Center)) { CannotInteractMessageDisplay.ClientOnCannotInteract( character, CoreStrings.Notification_ObstaclesOnTheWay, isOutOfRange: true); return; } ClientTimersSystem.AddAction(0.1, ClientDisableConstructionRelocation); if (tilePosition != objectStructure.TilePosition) { Instance.CallServer(_ => _.ServerRemote_RelocateStructure(objectStructure, tilePosition)); } } }
public static bool CheckCanInteractForConstruction( ICharacter character, IStaticWorldObject worldObject, bool writeToLog, bool checkRaidblock) { var characterPosition = character.Position; var canInteract = false; var staticWorldObjectProto = ProtoObjectConstructionSite.SharedGetConstructionProto(worldObject) ?? worldObject.ProtoStaticWorldObject; var startTilePosition = worldObject.TilePosition; foreach (var tileOffset in staticWorldObjectProto.Layout.TileOffsets) { var tilePosition = startTilePosition + tileOffset; if (characterPosition.DistanceSquaredTo( new Vector2D(tilePosition.X + 0.5, tilePosition.Y + 0.5)) <= MaxDistanceForBuildRepairAction * MaxDistanceForBuildRepairAction) { canInteract = true; break; } } if (!canInteract) { canInteract = CreativeModeSystem.SharedIsInCreativeMode(character); } if (!canInteract) { if (writeToLog) { Logger.Warning( $"Character cannot interact with {worldObject} for (de)construction - too far.", character); if (IsClient) { CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject, CoreStrings.Notification_TooFar, isOutOfRange: true); } } return(false); } if (checkRaidblock && LandClaimSystem.SharedIsUnderRaidBlock(character, worldObject)) { // the building is in an area under the raid if (writeToLog) { LandClaimSystem.SharedSendNotificationActionForbiddenUnderRaidblock(character); } return(false); } return(true); }
protected override void SharedValidateRequest(FishingActionRequest request) { var character = request.Character; var fishingTargetPosition = request.FishingTargetPosition; var itemRod = request.Item; if (itemRod is null || itemRod != character.SharedGetPlayerSelectedHotbarItem() || !(itemRod.ProtoItem is IProtoItemToolFishing)) { throw new Exception("The fishing rod is not selected"); } var fishingRodPublicState = itemRod.GetPublicState <ItemFishingRodPublicState>(); if (fishingRodPublicState.CurrentProtoBait is null || SharedFindBaitItem(character, fishingRodPublicState.CurrentProtoBait) is null) { // no bait available throw new Exception("There is no bait available of the required type"); } var world = IsServer ? (IWorldService)Server.World : (IWorldService)Client.World; var tile = world.GetTile(fishingTargetPosition.ToVector2Ushort()); if (!(tile.ProtoTile is IProtoTileWater protoTileWater) || !protoTileWater.IsFishingAllowed) { if (IsClient) { CannotInteractMessageDisplay.ClientOnCannotInteract(character, Notification_CannotFishHere, isOutOfRange: false); } throw new Exception("Cannot fish here"); } // check obstacle objects (such as bridges) using var testResults = world.GetPhysicsSpace() .TestPoint(fishingTargetPosition, CollisionGroups.Default, sendDebugEvent: false); foreach (var testResult in testResults.AsList()) { if (testResult.PhysicsBody.AssociatedWorldObject is null) { continue; } // an obstacle found if (IsClient) { CannotInteractMessageDisplay.ClientOnCannotInteract(character, Notification_CannotFishHere, isOutOfRange: false); } throw new Exception("Cannot fish here"); } if (SharedIsTooFar(character, fishingTargetPosition)) { if (IsClient) { CannotInteractMessageDisplay.ClientOnCannotInteract(character, CoreStrings.Notification_TooFar, isOutOfRange: true); } throw new Exception("Too far"); } }
public static bool SharedCheckCanInteract( ICharacter character, IDynamicWorldObject vehicle, bool writeToLog) { if (vehicle is null || vehicle.IsDestroyed) { return(false); } // it's possible to repair any vehicle within a certain distance to the character var canInteract = character.Position.DistanceSquaredTo(vehicle.Position) <= MaxDistanceForRepairAction * MaxDistanceForRepairAction; if (!canInteract) { if (writeToLog) { Logger.Warning( $"Character cannot interact with {vehicle} for repair - too far", character); if (IsClient) { CannotInteractMessageDisplay.ClientOnCannotInteract(vehicle, CoreStrings.Notification_TooFar, isOutOfRange: true); } } return(false); } var physicsSpace = character.PhysicsBody.PhysicsSpace; var characterCenter = character.Position + character.PhysicsBody.CenterOffset; if (ObstacleTestHelper.SharedHasObstaclesInTheWay(characterCenter, physicsSpace, vehicle, sendDebugEvents: writeToLog)) { if (writeToLog) { Logger.Warning( $"Character cannot interact with {vehicle} for repair - obstacles in the way", character); if (IsClient) { CannotInteractMessageDisplay.ClientOnCannotInteract(vehicle, CoreStrings.Notification_ObstaclesOnTheWay, isOutOfRange: true); } } return(false); } using var tempCharactersNearby = Api.Shared.GetTempList <ICharacter>(); if (IsClient) { Client.Characters.GetKnownPlayerCharacters(tempCharactersNearby); } else { Server.World.GetScopedByPlayers(vehicle, tempCharactersNearby); } foreach (var otherPlayerCharacter in tempCharactersNearby.AsList()) { if (ReferenceEquals(character, otherPlayerCharacter)) { continue; } if (PlayerCharacter.GetPublicState(otherPlayerCharacter).CurrentPublicActionState is VehicleRepairActionState.PublicState repairActionState && ReferenceEquals(repairActionState.TargetWorldObject, vehicle)) { // already repairing by another player if (!writeToLog) { return(false); } Logger.Important($"Cannot start repairing {vehicle} - already repairing by another player", character); if (IsClient) { NotificationSystem.ClientShowNotification( CoreStrings.Notification_ErrorCannotInteract, CoreStrings.Notification_ErrorObjectUsedByAnotherPlayer, NotificationColor.Bad, icon: ((IProtoVehicle)vehicle.ProtoGameObject).Icon); } return(false); } } return(true); }
public static void ClientOnCannotInteractNotOwner(IWorldObject worldObject) { CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject, DialogCannotSetOwners_MessageNotOwner, isOutOfRange: false); }
private void ClientRemote_OnCannotInteractNoAccess(IStaticWorldObject worldObject) { CannotInteractMessageDisplay.ClientOnCannotInteract(worldObject, NotificationDontHaveAccess, isOutOfRange: false); }