/// <summary> /// Validates if the performer is in range and capable of interaction - all the typical requirements for all /// various interactions. Works properly even if player is hidden in a ClosetControl. Can also optionally allow soft crit. /// /// </summary> /// <param name="player">player performing the interaction</param> /// <param name="target">target object</param> /// <param name="side">side of the network this is being checked on</param> /// <param name="allowSoftCrit">whether to allow interaction while in soft crit</param> /// <param name="reachRange">range to allow</param> /// <param name="targetVector">target vector pointing from performer to the position they are trying to click, /// if specified will use this to determine if in range rather than target object position.</param> /// <param name="targetRegisterTile">target's register tile component. If you specify this it avoids garbage. Please provide this /// if you can do so without using GetComponent, especially if you are calling this frequently. /// This is an optimization so GetComponent call can be avoided to avoid /// creating garbage.</param> /// <returns></returns> public static bool CanApply(GameObject player, GameObject target, NetworkSide side, bool allowSoftCrit = false, ReachRange reachRange = ReachRange.Standard, Vector2?targetVector = null, RegisterTile targetRegisterTile = null, bool isPlayerClick = false) { if (player == null) { return(false); } return(CanApply(player.GetComponent <PlayerScript>(), target, side, allowSoftCrit, reachRange, targetVector, targetRegisterTile, isPlayerClick)); }
/// <summary> /// Validates if the performer is in range and capable of interaction - all the typical requirements for all /// various interactions. Works properly even if player is hidden in a ClosetControl. Can also optionally allow soft crit. /// /// </summary> /// <param name="playerScript">player script performing the interaction</param> /// <param name="target">target object. Might be null if it's empty space</param> /// <param name="side">side of the network this is being checked on</param> /// <param name="allowSoftCrit">whether to allow interaction while in soft crit</param> /// <param name="reachRange">range to allow</param> /// <param name="targetVector">target vector pointing from performer to the position they are trying to click, /// if specified will use this to determine if in range rather than target object position.</param> /// <param name="targetRegisterTile">target's register tile component. If you specify this it avoids garbage. Please provide this /// if you can do so without using GetComponent, this is an optimization so GetComponent call can be avoided to avoid /// creating garbage.</param> /// <returns></returns> public static bool CanApply( PlayerScript playerScript, GameObject target, NetworkSide side, bool allowSoftCrit = false, ReachRange reachRange = ReachRange.Standard, Vector2?TargetPosition = null, Vector2?targetVector = null, RegisterTile targetRegisterTile = null ) { if (playerScript == null) { return(false); } var playerObjBehavior = playerScript.pushPull; if (CanInteract(playerScript, side, allowSoftCrit) == false) { return(false); } //no matter what, if player is in closet, they can only reach the closet if (playerScript.IsHidden) { //Client does not seem to know what they are hidden in (playerObjBehavior.parentContianer is not set clientside), //so in this case they simply validate this and defer to the server to decide if it's valid //TODO: Correct this if there is a way for client to know their container. if (side == NetworkSide.Client) { return(true); } else { //server checks if player is trying to click the container they are in. var parentObj = playerObjBehavior.parentContainer != null ? playerObjBehavior.parentContainer.gameObject : null; return(parentObj == target); } } var result = false; // Check if target is in player's inventory. // This was added so NetTabs (NetTab.ValidatePeepers()) can be used on items in an inventory. if (target != null && target.TryGetComponent(out Pickupable pickupable) && pickupable.ItemSlot != null) { if (pickupable.ItemSlot.RootPlayer().OrNull()?.gameObject == playerScript.gameObject) { result = true; } }
public static bool CanApply(ContextMenuApply toValidate, NetworkSide side, bool allowSoftCrit = false, ReachRange reachRange = ReachRange.Standard, bool isPlayerClick = false) => CanApply(toValidate.Performer, toValidate.TargetObject, side, allowSoftCrit, reachRange, isPlayerClick: isPlayerClick);
/// <summary> /// Validates if the performer is in range and not in crit for a TileApply interaction. /// Range check is based on the target vector of toValidate, not the distance to the object. /// </summary> /// <param name="toValidate">interaction to validate</param> /// <param name="side">side of the network this is being checked on</param> /// <param name="allowSoftCrit">whether to allow interaction while in soft crit</param> /// <param name="reachRange">range to allow</param> /// <returns></returns> public static bool CanApply(TileApply toValidate, NetworkSide side, bool allowSoftCrit = false, ReachRange reachRange = ReachRange.Standard, bool isPlayerClick = false) => CanApply(toValidate.Performer, toValidate.TargetInteractableTiles.gameObject, side, allowSoftCrit, reachRange, toValidate.TargetVector, isPlayerClick: isPlayerClick);
/// <summary> /// Validates if the performer is in range and capable of interaction - all the typical requirements for all /// various interactions. Works properly even if player is hidden in a ClosetControl. Can also optionally allow soft crit. /// /// </summary> /// <param name="playerScript">player script performing the interaction</param> /// <param name="target">target object. Might be null if it's empty space</param> /// <param name="side">side of the network this is being checked on</param> /// <param name="allowSoftCrit">whether to allow interaction while in soft crit</param> /// <param name="reachRange">range to allow</param> /// <param name="targetVector">target vector pointing from performer to the position they are trying to click, /// if specified will use this to determine if in range rather than target object position.</param> /// <param name="targetRegisterTile">target's register tile component. If you specify this it avoids garbage. Please provide this /// if you can do so without using GetComponent, this is an optimization so GetComponent call can be avoided to avoid /// creating garbage.</param> /// <returns></returns> public static bool CanApply(PlayerScript playerScript, GameObject target, NetworkSide side, bool allowSoftCrit = false, ReachRange reachRange = ReachRange.Standard, Vector2?targetVector = null, RegisterTile targetRegisterTile = null, bool isPlayerClick = false) { if (playerScript == null) { return(false); } var playerObjBehavior = playerScript.pushPull; if (!CanInteract(playerScript, side, allowSoftCrit, isPlayerClick: isPlayerClick)) { return(false); } //no matter what, if player is in closet, they can only reach the closet if (playerScript.IsHidden) { //Client does not seem to know what they are hidden in (playerObjBehavior.parentContianer is not set clientside), //so in this case they simply validate this and defer to the server to decide if it's valid //TODO: Correct this if there is a way for client to know their container. if (side == NetworkSide.Client) { return(true); } else { //server checks if player is trying to click the container they are in. var parentObj = playerObjBehavior.parentContainer != null ? playerObjBehavior.parentContainer.gameObject : null; return(parentObj == target); } } var result = false; if (reachRange == ReachRange.Unlimited) { result = true; } else if (reachRange == ReachRange.Standard) { result = IsInReachInternal(playerScript, target, side, targetVector, targetRegisterTile); } else if (reachRange == ReachRange.ExtendedServer) { //we don't check range client-side for this case. if (side == NetworkSide.Client) { result = true; } else { CustomNetTransform cnt = (target == null) ? null : target.GetComponent <CustomNetTransform>(); if (cnt == null) { result = IsInReachInternal(playerScript, target, side, targetVector, targetRegisterTile); } else { result = ServerCanReachExtended(playerScript, cnt.ServerState); } } } if (!result && side == NetworkSide.Server && Logger.LogLevel >= LogLevel.Trace) { Vector3 worldPosition = Vector3.zero; bool isFloating = false; string targetName = string.Empty; // Client tried to do something out of range, report it // Note : it can be a security incident, but it might also be caused by bugs. // TODO: verify after a few rounds in multi-player, if this happens too often, // with this log information, try to find the cause and fix it (or fine tune it for less frequent logs). if (target != null) { targetName = target.name; if (target.TryGetComponent(out CustomNetTransform cnt)) { worldPosition = cnt.ServerState.WorldPosition; isFloating = cnt.IsFloatingServer; } else if (target.TryGetComponent(out PlayerSync playerSync)) { worldPosition = playerSync.ServerState.WorldPosition; isFloating = playerSync.IsWeightlessServer; } } Logger.LogTraceFormat($"Not in reach! Target: {targetName} server pos:{worldPosition} " + $"Player Name: {playerScript.playerName} Player pos:{playerScript.registerTile.WorldPositionServer} " + $"(floating={isFloating})", Category.Security); } return(result); }
/// <summary> /// Validates if the performer is in range and not in crit for a MouseDrop interaction. /// </summary> /// <param name="toValidate">interaction to validate</param> /// <param name="side">side of the network this is being checked on</param> /// <param name="allowSoftCrit">whether to allow interaction while in soft crit</param> /// <param name="reachRange">range to allow</param> /// <returns></returns> public static bool CanApply(MouseDrop toValidate, NetworkSide side, bool allowSoftCrit = false, ReachRange reachRange = ReachRange.Standard) => CanApply(toValidate.Performer, toValidate.TargetObject, side, allowSoftCrit, reachRange);
/// <summary> /// Validates if the performer is in range and not in crit for a PositionalHandApply interaction. /// Range check is based on the target vector of toValidate, not the distance to the object. /// </summary> /// <param name="toValidate">interaction to validate</param> /// <param name="side">side of the network this is being checked on</param> /// <param name="allowSoftCrit">whether to allow interaction while in soft crit</param> /// <param name="reachRange">range to allow</param> /// <returns></returns> public static bool CanApply(PositionalHandApply toValidate, NetworkSide side, bool allowSoftCrit = false, ReachRange reachRange = ReachRange.Standard) => CanApply(toValidate.Performer, toValidate.TargetObject, side, allowSoftCrit, reachRange, toValidate.TargetVector);
/// <summary> /// Validates if the performer is in range and not in crit, which are typical requirements for all /// various interactions. Works properly even if player is hidden in a ClosetControl. Can also optionally allow soft crit. /// /// For PositionalHandApply, reach range is based on how far away they are clicking from themselves /// </summary> /// <param name="player">player performing the interaction</param> /// <param name="target">target object</param> /// <param name="side">side of the network this is being checked on</param> /// <param name="allowSoftCrit">whether to allow interaction while in soft crit</param> /// <param name="reachRange">range to allow</param> /// <param name="targetVector">target vector pointing from performer to the position they are trying to click, /// if specified will use this to determine if in range rather than target object position.</param> /// <returns></returns> public static bool CanApply(GameObject player, GameObject target, NetworkSide side, bool allowSoftCrit = false, ReachRange reachRange = ReachRange.Standard, Vector2?targetVector = null) { var playerScript = player.GetComponent <PlayerScript>(); var playerObjBehavior = player.GetComponent <ObjectBehaviour>(); if (!CanInteract(player, side, allowSoftCrit)) { return(false); } //no matter what, if player is in closet, they can only reach the closet if (playerScript.IsHidden) { //Client does not seem to know what they are hidden in (playerObjBehavior.parentContianer is not set clientside), //so in this case they simply validate this and defer to the server to decide if it's valid //TODO: Correct this if there is a way for client to know their container. if (side == NetworkSide.Client) { return(true); } else { //server checks if player is trying to click the container they are in. var parentObj = playerObjBehavior.parentContainer != null ? playerObjBehavior.parentContainer.gameObject : null; return(parentObj == target); } } var result = false; if (reachRange == ReachRange.Unlimited) { result = true; } else if (reachRange == ReachRange.Standard) { var targetWorldPosition = targetVector != null ? player.transform.position + targetVector : target.transform.position; result = playerScript.IsInReach((Vector3)targetWorldPosition, side == NetworkSide.Server); } else if (reachRange == ReachRange.ExtendedServer) { //we don't check range client-side for this case. if (side == NetworkSide.Client) { result = true; } else { var cnt = target.GetComponent <CustomNetTransform>(); if (cnt == null) { var targetWorldPosition = targetVector != null ? player.transform.position + targetVector : target.transform.position; //fallback to standard range check if there is no CNT result = playerScript.IsInReach((Vector3)targetWorldPosition, side == NetworkSide.Server); } else { result = ServerCanReachExtended(playerScript, cnt.ServerState); } } } if (!result && side == NetworkSide.Server) { //client tried to do something out of range, report it var cnt = target.GetComponent <CustomNetTransform>(); Logger.LogTraceFormat("Not in reach! server pos:{0} player pos:{1} (floating={2})", Category.Security, cnt.ServerState.WorldPosition, player.transform.position, cnt.IsFloatingServer); } return(result); }