public virtual bool WillInteract(AimApply interaction, NetworkSide side) { if (!DefaultWillInteract.Default(interaction, side)) { return(false); } if (CurrentMagazine == null) { PlayEmptySFX(); if (side == NetworkSide.Server) { Logger.LogTrace("Server rejected shot - No magazine being loaded", Category.Firearms); } return(false); } //note: fire count down is only checked local player side, as server processes all the shots in a queue //anyway so client cannot exceed that firing rate no matter what. If we validate firing rate server //side at the moment of interaction, it will reject client's shots because of lag between server / client //firing countdown if (side == NetworkSide.Server || FireCountDown <= 0) { if (CurrentMagazine.ClientAmmoRemains <= 0) { if (SmartGun && allowMagazineRemoval) // smartGun is forced off when using an internal magazine { RequestUnload(CurrentMagazine); OutOfAmmoSFX(); } else { PlayEmptySFX(); } if (side == NetworkSide.Server) { Logger.LogTrace("Server rejected shot - out of ammo", Category.Firearms); } return(false); } if (CurrentMagazine.containedBullets[0] != null) { if (interaction.MouseButtonState == MouseButtonState.PRESS) { return(true); } else { //being held, only can shoot if this is an automatic return(WeaponType == WeaponType.FullyAutomatic); } } } if (side == NetworkSide.Server) { Logger.LogTraceFormat("Server rejected shot - unknown reason. MouseButtonState {0} ammo remains {1} weapon type {2}", Category.Firearms, interaction.MouseButtonState, CurrentMagazine.ClientAmmoRemains, WeaponType); } return(false); }
/// <summary> /// Default WIllInteract logic for PositionalHandApply interactions /// </summary> public static bool PositionalHandApply(PositionalHandApply interaction, NetworkSide side) { return(Validations.CanApply(interaction, side)); }
/// <summary> /// Determines if the interaction request for uncuffing is valid clientside and if true, then serverside /// </summary> public bool WillInteract(ContextMenuApply interaction, NetworkSide side) { return(DefaultWillInteract.Default(interaction, side) && IsCuffed); }
//shorthand for calling GetAt at the targeted object's position public static List <T> GetAt <T>(GameObject targetObject, NetworkSide side) where T : MonoBehaviour { return(GetAt <T>((Vector3Int)targetObject.TileWorldPosition(), side == NetworkSide.Server)); }
/// <summary> /// Default WillInteract logic for MouseDrop /// </summary> public static bool MouseDrop(MouseDrop interaction, NetworkSide side) { return(Validations.CanApply(interaction, side)); }
public bool StartNetworking(NetworkSide _side, bool clientDefaultReconnect = false, bool dontUseNetworkStream = false) { if (supposedToBeConnected && !(side == NetworkSide.DISCONNECTED || side == NetworkSide.CONNECTIONLOST)) { return(false); } //if (side != NetworkSide.CONNECTIONLOST) //{ // CommandQueue.Clear(); // PeerCommandQueue.Clear(); //} if (CommandQueueProcessorTimer == null) { CommandQueueProcessorTimer = new System.Windows.Forms.Timer(); CommandQueueProcessorTimer.Interval = 5; CommandQueueProcessorTimer.Tick += CommandQueueProcessorTimer_Tick; CommandQueueProcessorTimer.Start(); } if (_side == NetworkSide.CLIENT) { side = NetworkSide.CLIENT; expectedSide = NetworkSide.CLIENT; if (!StartClient(clientDefaultReconnect)) { return(false); } OnClientConnecting(null); } else if (_side == NetworkSide.SERVER) { side = NetworkSide.SERVER; expectedSide = NetworkSide.SERVER; StartServer(dontUseNetworkStream); OnServerStarted(null); } else { return(false); } KeepAliveCounter = DefaultKeepAliveCounter; if (KeepAliveTimer == null) { KeepAliveTimer = new System.Windows.Forms.Timer(); KeepAliveTimer.Interval = 666; KeepAliveTimer.Tick += KeepAliveTimer_Tick; KeepAliveTimer.Start(); } if (_side == NetworkSide.SERVER) { expectingSomeone = false; } supposedToBeConnected = true; return(true); }
/// <summary> /// Decides if interaction logic should proceed. On client side, the interaction /// request will only be sent to the server if this returns true. On server side, /// the interaction will only be performed if this returns true. /// /// Each interaction has a default implementation of this which should apply for most cases. /// By overriding this and adding more specific logic, you can reduce the amount of messages /// sent by the client to the server, decreasing overall network load. /// </summary> /// <param name="interaction">interaction to validate</param> /// <param name="side">which side of the network this is being invoked on</param> /// <returns>True/False based on whether the interaction logic should proceed as described above.</returns> protected virtual bool WillInteract(HandApply interaction, NetworkSide side) { return(DefaultWillInteract.Default(interaction, side)); }
/// <summary> /// Allow honking when barely conscious /// </summary> public bool WillInteract(HandActivate interaction, NetworkSide side) { return(Validations.CanInteract(interaction.Performer, side, true) && allowUse); }
/// <summary> /// Starts the cooldown if it's not currently on. /// </summary> /// <param name="cooldown">cooldown to try</param> /// <param name="side">indicates which side's cooldown should be started</param> /// <param name="secondsOverride">custom cooldown time in seconds</param> /// <returns>true if cooldown was successfully started, false if cooldown was already on.</returns> public bool TryStart(ICooldown cooldown, NetworkSide side, float secondsOverride = float.NaN) { return(TryStart(CooldownID.Asset(cooldown, side), float.IsNaN(secondsOverride) ? cooldown.DefaultTime : secondsOverride)); }
public NetworkState ReadPacket(PacketByteBuf packet, NetworkState state, NetworkSide side) { compressionThreshold = packet.ReadVarInt(); Debug.LogWarning($"JDJDDJJDDJJD {compressionThreshold}"); return(state); }
public NetworkState WritePacket(PacketByteBuf packet, NetworkState state, NetworkSide side) { packet.WriteVarInt(compressionThreshold); return(state); }
private static bool CanInteractByConsciousState(PlayerHealth playerHealth, bool allowSoftCrit, NetworkSide side) { if (side == NetworkSide.Client) { //we only know our own conscious state, so assume true if it's not our local player if (playerHealth.gameObject != PlayerManager.LocalPlayer) { return(true); } } return(playerHealth.ConsciousState == ConsciousState.CONSCIOUS || playerHealth.ConsciousState == ConsciousState.BARELY_CONSCIOUS && allowSoftCrit); }
/// <summary> /// A cooldown which is identified by a particular TYPE of interactable component. Useful for /// creating interactable components with their own specific cooldown without needing to create /// an actual cooldown asset. The specific instance /// doesn't matter - this cooldown is shared by all instances of that type. For example, you'd always get /// the same CooldownIdentifier regardless of which object's Meleeable component you passed to this. /// </summary> /// <param name="interactable"></param> /// <param name="side">network side this cooldown is for</param> /// <returns></returns> public static CooldownID Interaction <T>(IInteractable <T> interactable, NetworkSide side) where T : Interaction { return(new CooldownID(null, interactable.GetType(), side, CooldownType.Interaction)); }
/// <summary> /// Cooldown identified by a particular cooldown asset. /// </summary> /// <param name="cooldownAsset"></param> /// <param name="side">network side this cooldown is for</param> /// <returns></returns> public static CooldownID Asset(Cooldown cooldownAsset, NetworkSide side) { return(new CooldownID(cooldownAsset, null, side, CooldownType.Asset)); }
public void StoreCommands(NetworkStream providedStream, bool dontCreateNetworkStream = false) { var binaryFormatter = new BinaryFormatter(); TcpListener server = null; Socket socket = null; NetworkStream networkStream = null; if (providedStream != null) { networkStream = providedStream; } try { if (networkStream == null && !dontCreateNetworkStream) { server = new TcpListener(IPAddress.Any, port); server.Start(); socket = KillableAcceptSocket(server); networkStream = new NetworkStream(socket); server.Stop(); } networkStream.ReadTimeout = DefaultNetworkStreamTimeout; networkStream.WriteTimeout = DefaultNetworkStreamTimeout; if (side == NetworkSide.CLIENT) { SendCommand(new RTC_Command(CommandType.HI), false, true); } while (true) { if (networkStream != null && networkStream.DataAvailable) { RTC_Command cmd; try { cmd = (RTC_Command)binaryFormatter.Deserialize(networkStream); } catch (Exception ex) { throw ex; } if (cmd != null) { if (cmd.Type == CommandType.RETURNVALUE) { ReturnWatch.SyncReturns.Add((Guid)cmd.requestGuid, cmd.objectValue); } else { CommandQueue.AddLast(cmd); } } } while (PeerCommandQueue.Count > 0) { RTC_Command backCmd; lock (CommandQueueLock) { backCmd = PeerCommandQueue.First.Value; PeerCommandQueue.RemoveFirst(); } try { binaryFormatter.Serialize(networkStream, backCmd); } catch (Exception ex) { throw ex; } if (backCmd.Type == CommandType.BYE) { CommandQueue.AddFirst(new RTC_Command(CommandType.SAIDBYE)); PeerCommandQueue.Clear(); throw new Exception("SAIDBYE"); } if (side == NetworkSide.DISCONNECTED || side == NetworkSide.CONNECTIONLOST) { if (side == NetworkSide.DISCONNECTED) { CommandQueue.Clear(); PeerCommandQueue.Clear(); } throw new Exception(side.ToString()); } } Thread.Sleep(5); } } catch (Exception ex) { OutputException(ex); if (side == NetworkSide.CLIENT || side == NetworkSide.SERVER) { side = NetworkSide.CONNECTIONLOST; } } finally { if (networkStream != null) { try { networkStream.Close(); networkStream.Dispose(); } catch (Exception ex2) { OutputException(ex2); } } if (socket != null) { //socket.Close(); try { socket.Shutdown(SocketShutdown.Both); socket.Dispose(); } catch (Exception ex2) { OutputException(ex2); } } if (server != null) { try { server.Stop(); } catch (Exception ex2) { OutputException(ex2); } } isStreamReadingThreadAlive = false; } }
/// <summary> /// Starts a cooldown (if it's not already on) which is identified by a particular TYPE of interactable component. The specific instance /// doesn't matter - this cooldown is shared by all instances of that type. For example, you'd always start /// the same cooldown regardless of which object's Meleeable component you passed to this (this is /// usually the intended behavior for interactable components - you don't care which object's interaction /// you are triggering - you should still have the same cooldown for melee regardless of who you are hitting). /// Intended for convenience / one-off usage in small interactable components so you don't need /// to create an asset. /// </summary> /// <param name="cooldown">interactable component whose cooldown should be started</param> /// <param name="seconds">how many seconds the cooldown should take</param> /// <param name="side">indicates which side's cooldown should be started</param> /// <returns>true if cooldown was successfully started, false if cooldown was already on.</returns> public bool TryStart <T>(IInteractable <T> interactable, float seconds, NetworkSide side) where T : Interaction { return(TryStart(CooldownID.Interaction(interactable, side), seconds)); }
public void StopNetworking(bool fromBye = false, bool stayConnected = false) { //if ((side == NetworkSide.CONNECTIONLOST || side == NetworkSide.DISCONNECTED) && stayConnected) // return; //supposedToBeConnected = stayConnected; if (!fromBye) { SendCommand(new RTC_Command(CommandType.SAYBYE), true, true); return; } if (!stayConnected) { expectingSomeone = false; } if (expectedSide == NetworkSide.CLIENT) { if (stayConnected) { OnClientConnectionLost(null); } else { OnClientDisconnected(null); } } else if (expectedSide == NetworkSide.SERVER) { if (!stayConnected) { OnServerDisconnected(null); } } side = (stayConnected ? NetworkSide.CONNECTIONLOST : NetworkSide.DISCONNECTED); if (side == NetworkSide.DISCONNECTED) { CommandQueue.Clear(); PeerCommandQueue.Clear(); } if (streamReadingThread != null) { streamReadingThread.Abort(); streamReadingThread = null; } if (clientStream != null) { clientStream.Close(); clientStream = null; } if (client != null) { client.Close(); client = null; } /* * if (CommandQueueProcessorTimer != null) * { * CommandQueueProcessorTimer.Stop(); * CommandQueueProcessorTimer = null; * } */ if (!stayConnected) { if (KeepAliveTimer != null) { KeepAliveTimer.Stop(); KeepAliveTimer = null; } } if (!stayConnected) { supposedToBeConnected = false; } }
/// <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) { if (player == null) { return(false); } 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); }
/// <summary> /// Decides if interaction logic should proceed. On client side, the interaction /// request will only be sent to the server if this returns true. On server side, /// the interaction will only be performed if this returns true. /// /// Each interaction has a default implementation of this which should apply for most cases. /// By overriding this and adding more specific logic, you can reduce the amount of messages /// sent by the client to the server, decreasing overall network load. /// </summary> /// <param name="interaction">interaction to validate</param> /// <param name="side">which side of the network this is being invoked on</param> /// <returns>True/False based on whether the interaction logic should proceed as described above.</returns> protected virtual bool WillInteract(MouseDrop interaction, NetworkSide side) { return(DefaultWillInteract.Default(interaction, side)); }
/// <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);
public bool WillInteract(HandActivate interaction, NetworkSide side) { return(DefaultWillInteract.Default(interaction, side)); }
/// <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> /// Default WillInteract logic for Activate /// </summary> public static bool HandActivate(HandActivate interaction, NetworkSide side) { return(Validations.CanInteract(interaction.Performer, side)); }
/// <summary> /// Checks if the player can currently put the indicated item in this slot. Correctly handles logic for client / server side, so is /// recommended to use in WillInteract rather than other ways of checking fit. /// </summary> /// <param name="player">player to check</param> /// <param name="itemSlot">slot to check</param> /// <param name="toCheck">item to check for fit</param> /// <param name="side">network side check is happening on</param> /// <param name="ignoreOccupied">if true, does not check if an item is already in the slot</param> /// <param name="examineRecipient">if not null, when validation fails, will output an appropriate examine message to this recipient</param> /// <returns></returns> public static bool CanPutItemToSlot(PlayerScript playerScript, ItemSlot itemSlot, Pickupable toCheck, NetworkSide side, bool ignoreOccupied = false, GameObject examineRecipient = null) { if (toCheck == null || itemSlot.Item != null) { Logger.LogTrace("Cannot put item to slot because the item or slot are null", Category.Inventory); return(false); } if (playerScript.canNotInteract()) { Logger.LogTrace("Cannot put item to slot because the player cannot interact", Category.Inventory); return(false); } if (!CanFit(itemSlot, toCheck, side, ignoreOccupied, examineRecipient)) { Logger.LogTraceFormat("Cannot put item to slot because the item {0} doesn't fit in the slot {1}", Category.Inventory, toCheck.name, itemSlot); return(false); } return(true); }
/// <summary> /// Default WillInteract logic for AimApply /// </summary> public static bool AimApply(AimApply interaction, NetworkSide side) { return(Validations.CanInteract(interaction.Performer, side)); }
/// <summary> /// Client: /// Allow items to be stored by clicking on bags with item in hand /// and clicking items with bag in hand if CanClickPickup is enabled /// </summary> public bool WillInteract(PositionalHandApply interaction, NetworkSide side) { if (allowedToInteract == false) { return(false); } // Use default interaction checks if (DefaultWillInteract.Default(interaction, side) == false) { return(false); } // See which item needs to be stored if (Validations.IsTarget(gameObject, interaction)) { // We're the target // If player's hands are empty let Pickupable handle the interaction if (interaction.HandObject == null) { return(false); } // There's something in the player's hands // Check if item from the hand slot fits in this storage sitting in the world if (Validations.CanPutItemToStorage(interaction.PerformerPlayerScript, itemStorage, interaction.HandObject, side, examineRecipient: interaction.Performer) == false) { Chat.AddExamineMsgToClient($"The {interaction.HandObject.ExpensiveName()} doesn't fit!"); return(false); } return(true); } else if (canClickPickup) { // If we can click pickup then try to store the target object switch (pickupMode) { case PickupMode.Single: // See if there's an item to pickup if (interaction.TargetObject == null || interaction.TargetObject.Item() == null) { Chat.AddExamineMsgToClient("There's nothing to pickup!"); return(false); } if (!Validations.CanPutItemToStorage(interaction.PerformerPlayerScript, itemStorage, interaction.TargetObject, side, examineRecipient: interaction.Performer)) { // In Single pickup mode if the target item doesn't // fit then don't interact Chat.AddExamineMsgToClient($"The {interaction.TargetObject.ExpensiveName()} doesn't fit!"); return(false); } break; case PickupMode.Same: if (interaction.TargetObject == null) { // If there's nothing to compare then don't interact Chat.AddExamineMsgToClient("There's nothing to pickup!"); return(false); } break; } // In Same and All pickup modes other items on the // tile could still be picked up, so we interact return(true); } else { // We're not the target and we can't click pickup so don't do anything return(false); } }
public NetworkState WritePacket(PacketByteBuf packet, NetworkState state, NetworkSide side) { return(state); }
public bool WillInteract(HandApply interaction, NetworkSide side) { return(DefaultWillInteract.Default(interaction, side) && (interaction.HandObject == null || (interaction.Intent == Intent.Help || interaction.Intent == Intent.Grab))); }
/// <summary> /// Gets the interactable tiles for the matrix at the indicated world position. Never returns null - always /// returns the interactable tiles for the appropriate matrix. /// </summary> /// <param name="worldPos"></param> /// <returns></returns> public static InteractableTiles GetAt(Vector2 worldPos, NetworkSide side) { return(GetAt(worldPos, side == NetworkSide.Server)); }
public bool WillInteract(HandApply interaction, NetworkSide side) { if (!DefaultWillInteract.Default(interaction, side)) { return(false); } if (!Validations.IsTarget(gameObject, interaction)) { return(false); } //Anchor or disassemble if (CurrentState == initialState) { return(Validations.HasUsedItemTrait(interaction, CommonTraits.Instance.Wrench) || Validations.HasUsedItemTrait(interaction, CommonTraits.Instance.Crowbar)); } //Adding metal or unanchor if (CurrentState == anchoredState) { return(Validations.HasUsedItemTrait(interaction, CommonTraits.Instance.MetalSheet) || Validations.HasUsedItemTrait(interaction, CommonTraits.Instance.Wrench)); } //Wrench or remove metal if (CurrentState == metalAddedState) { return(Validations.HasUsedItemTrait(interaction, CommonTraits.Instance.Wrench) || Validations.HasUsedActiveWelder(interaction)); } //Add gun or unwrench if (CurrentState == wrenchState) { return(Validations.HasUsedItemTrait(interaction, gunTrait) || Validations.HasUsedItemTrait(interaction, CommonTraits.Instance.Wrench)); } //Add prox or remove gun if (CurrentState == gunAddedState) { return(Validations.HasUsedItemTrait(interaction, CommonTraits.Instance.ProximitySensor) || interaction.HandObject == null); } //Screw or remove prox if (CurrentState == proxAddedState) { return(Validations.HasUsedItemTrait(interaction, CommonTraits.Instance.Screwdriver) || interaction.HandObject == null); } //Add metal or unscrew if (CurrentState == screwState) { return(Validations.HasUsedItemTrait(interaction, CommonTraits.Instance.MetalSheet) || Validations.HasUsedItemTrait(interaction, CommonTraits.Instance.Screwdriver)); } //Finish construction or remove metal if (CurrentState == secondMetalAddedState) { return(Validations.HasUsedActiveWelder(interaction) || Validations.HasUsedItemTrait(interaction, CommonTraits.Instance.Crowbar)); } return(false); }