//for internal IF2 usages only, does server side logic for processing tileapply public void ServerProcessInteraction(int tileInteractionIndex, GameObject performer, Vector2 targetVector, GameObject processorObj, ItemSlot usedSlot, GameObject usedObject, Intent intent) { //find the indicated tile interaction var success = false; var worldPosTarget = (Vector2)performer.transform.position + targetVector; //pass the interaction down to the basic tile LayerTile tile = LayerTileAt(worldPosTarget); if (tile is BasicTile basicTile) { if (tileInteractionIndex >= basicTile.TileInteractions.Count) { //this sometimes happens due to lag, so bumping it down to trace Logger.LogTraceFormat("Requested TileInteraction at index {0} does not exist on this tile {1}.", Category.Interaction, tileInteractionIndex, basicTile.name); return; } var tileInteraction = basicTile.TileInteractions[tileInteractionIndex]; var tileApply = new TileApply(performer, usedObject, intent, (Vector2Int)WorldToCell(worldPosTarget), this, basicTile, usedSlot, targetVector); if (tileInteraction.WillInteract(tileApply, NetworkSide.Server) && Cooldowns.TryStartServer(tileApply, CommonCooldowns.Instance.Interaction)) { //perform tileInteraction.ServerPerformInteraction(tileApply); } else { tileInteraction.ServerRollbackClient(tileApply); } } }
public override void ServerPerformInteraction(TileApply interaction) { if (!interaction.UsedObject.RegisterTile().Matrix.IsPassableAt(interaction.TargetCellPos, true, true, null, excludeTiles)) { return; } StandardProgressActionConfig cfg = new StandardProgressActionConfig(StandardProgressActionType.Construction, false, false, false); var x = StandardProgressAction.Create(cfg, () => { PlayerScript playerScript; if (interaction.UsedObject.TryGetComponent(out playerScript)) { List <TileType> excludeTiles = new List <TileType>() { TileType.Table }; if (playerScript.registerTile.Matrix.IsPassableAt(interaction.TargetCellPos, true, true, null, excludeTiles)) { playerScript.PlayerSync.SetPosition(interaction.WorldPositionTarget); } } else { var transformComp = interaction.UsedObject.GetComponent <CustomNetTransform>(); if (transformComp != null) { transformComp.AppearAtPositionServer(interaction.WorldPositionTarget); } } }).ServerStartProgress(interaction.UsedObject.RegisterTile(), 3.0f, interaction.Performer); }
public override void ServerPerformInteraction(TileApply interaction) { ToolUtils.ServerUseToolWithActionMessages(interaction, seconds, performerStartActionMessage, Chat.ReplacePerformer(othersStartActionMessage, interaction.Performer), performerFinishActionMessage, Chat.ReplacePerformer(othersFinishActionMessage, interaction.Performer), () => { interaction.TileChangeManager.RemoveTile(interaction.TargetCellPos, interaction.BasicTile.LayerType); interaction.TileChangeManager.RemoveFloorWallOverlaysOfType(interaction.TargetCellPos, TileChangeManager.OverlayType.Cleanable); //spawn things that need to be spawned if (interaction.BasicTile.SpawnOnDeconstruct != null && interaction.BasicTile.SpawnAmountOnDeconstruct > 0) { Spawn.ServerPrefab(interaction.BasicTile.SpawnOnDeconstruct, interaction.WorldPositionTarget, count: interaction.BasicTile.SpawnAmountOnDeconstruct); } if (objectsToSpawn != null) { objectsToSpawn.SpawnAt(SpawnDestination.At(interaction.WorldPositionTarget)); } interaction.TileChangeManager.SubsystemManager.UpdateAt(interaction.TargetCellPos); }); }
public override void ServerPerformInteraction(TileApply interaction) { string othersMessage = Chat.ReplacePerformer(othersStartActionMessage, interaction.Performer); Chat.AddActionMsgToChat(interaction.Performer, performerStartActionMessage, othersMessage); if (interaction.BasicTile.LayerType != LayerType.Underfloor) { return; } var PipeTile = interaction.BasicTile as PipeTile; var matrix = interaction.TileChangeManager.MetaTileMap.Layers[LayerType.Underfloor].matrix; var metaDataNode = matrix.GetMetaDataNode(interaction.TargetCellPos); for (var i = 0; i < metaDataNode.PipeData.Count; i++) { if (metaDataNode.PipeData[i].RelatedTile != PipeTile) { continue; } // var Transform = matrix.UnderFloorLayer.GetMatrix4x4(metaDataNode.PipeData[i].NodeLocation, metaDataNode.PipeData[i].RelatedTile); // var pipe = Spawn.ServerPrefab(PipeTile.SpawnOnDeconstruct, interaction.WorldPositionTarget, localRotation : QuaternionFromMatrix(Transform)).GameObject; // var itempipe = pipe.GetComponent<PipeItemTile>(); // itempipe.Colour = matrix.UnderFloorLayer.GetColour(metaDataNode.PipeData[i].NodeLocation, metaDataNode.PipeData[i].RelatedTile); // itempipe.Setsprite(); // matrix.RemoveUnderFloorTile( metaDataNode.PipeData[i].NodeLocation, metaDataNode.PipeData[i].RelatedTile); // var savedpipe = metaDataNode.PipeData[i].pipeData; // metaDataNode.PipeData.RemoveAt(i); metaDataNode.PipeData[i].pipeData.DestroyThis(); return; } }
public bool Interact(PositionalHandApply interaction) { //translate to the tile interaction system //pass the interaction down to the basic tile LayerTile tile = LayerTileAt(interaction.WorldPositionTarget); if (tile is BasicTile basicTile) { var tileApply = new TileApply(interaction.Performer, interaction.UsedObject, interaction.Intent, (Vector2Int)WorldToCell(interaction.WorldPositionTarget), this, basicTile, interaction.HandSlot, interaction.TargetVector); var i = 0; foreach (var tileInteraction in basicTile.TileInteractions) { if (tileInteraction == null) { continue; } if (tileInteraction.WillInteract(tileApply, NetworkSide.Client) && Cooldowns.TryStartClient(interaction, CommonCooldowns.Instance.Interaction)) { //request the tile interaction with this index RequestInteractMessage.SendTileApply(tileApply, this, tileInteraction, i); return(true); } i++; } } return(false); }
//only intended to be used by core if2 classes public static void SendTileApply(TileApply tileApply, InteractableTiles interactableTiles, TileInteraction tileInteraction, int tileInteractionIndex) { //if we are client and the interaction has client prediction, trigger it. //Note that client prediction is not triggered for server player. if (!CustomNetworkManager.IsServer) { Logger.LogTraceFormat("Predicting TileApply interaction {0}", Category.Interaction, tileApply); tileInteraction.ClientPredictInteraction(tileApply); } if (!tileApply.Performer.Equals(PlayerManager.LocalPlayer)) { Logger.LogError("Client attempting to perform an interaction on behalf of another player." + " This is not allowed. Client can only perform an interaction as themselves. Message" + " will not be sent.", Category.NetMessage); return; } var msg = new RequestInteractMessage() { ComponentType = typeof(InteractableTiles), InteractionType = typeof(TileApply), ProcessorObject = interactableTiles.GetComponent <NetworkIdentity>().netId, Intent = tileApply.Intent, TargetVector = tileApply.TargetVector, TileInteractionIndex = tileInteractionIndex }; msg.Send(); }
//only intended to be used by core if2 classes public static void SendTileApply(TileApply tileApply, InteractableTiles interactableTiles, TileInteraction tileInteraction) { //if we are client and the interaction has client prediction, trigger it. //Note that client prediction is not triggered for server player. if (!CustomNetworkManager.IsServer) { Logger.LogTraceFormat("Predicting TileApply interaction {0}", Category.Interaction, tileApply); tileInteraction.ClientPredictInteraction(tileApply); } if (!tileApply.Performer.Equals(PlayerManager.LocalPlayer)) { Logger.LogError("Client attempting to perform an interaction on behalf of another player." + " This is not allowed. Client can only perform an interaction as themselves. Message" + " will not be sent.", Category.Exploits); return; } var msg = new NetMessage() { ComponentType = typeof(InteractableTiles), InteractionType = typeof(TileApply), ProcessorObject = GetNetId(interactableTiles.gameObject), Intent = tileApply.Intent, TargetPosition = tileApply.TargetPosition }; Send(msg); }
private void DeconstructPipe(TileApply interaction) { DisposalPipe pipe = interaction.BasicTile as DisposalPipe; // Despawn pipe tile var matrix = MatrixManager.AtPoint(interaction.WorldPositionTarget.NormalizeTo3Int(), true).Matrix; matrix.RemoveUnderFloorTile(interaction.TargetCellPos, pipe); // Spawn pipe GameObject if (interaction.BasicTile.SpawnOnDeconstruct == null) { return; } var spawn = Spawn.ServerPrefab(interaction.BasicTile.SpawnOnDeconstruct, interaction.WorldPositionTarget); if (spawn.Successful == false) { return; } if (spawn.GameObject.TryGetComponent <Directional>(out var directional)) { directional.FaceDirection(Orientation.FromEnum(pipe.DisposalPipeObjectOrientation)); } if (spawn.GameObject.TryGetComponent <ObjectBehaviour>(out var behaviour)) { behaviour.ServerSetPushable(false); } }
private void PerformTileInteract(TileApply interaction) { foreach (var tileInteraction in interaction.BasicTile.TileInteractions) { if (tileInteraction == null) { continue; } if (tileInteraction.WillInteract(interaction, NetworkSide.Server)) { //perform if not on cooldown if (Cooldowns.TryStartServer(interaction, CommonCooldowns.Instance.Interaction)) { tileInteraction.ServerPerformInteraction(interaction); } else { //hit a cooldown, rollback in case client tried to predict it tileInteraction.ServerRollbackClient(interaction); } // interaction should've triggered and did or we hit a cooldown, so we're // done processing this request. break; } else { tileInteraction.ServerRollbackClient(interaction); } } }
private bool VerboseDisposalMachineExists(TileApply interaction) { Matrix matrix = interaction.TileChangeManager.MetaTileMap.Layers[LayerType.Underfloor].matrix; if ((interaction.BasicTile as DisposalPipe).PipeType == DisposalPipeType.Terminal) { DisposalMachine disposalMachine = matrix.GetFirst <DisposalMachine>(interaction.TargetCellPos, true); if (disposalMachine != null && disposalMachine.MachineAttachedOrGreater) { string machineName = disposalMachine.name; if (disposalMachine.TryGetComponent <ObjectAttributes>(out var attributes) && string.IsNullOrWhiteSpace(attributes.InitialName) == false) { machineName = attributes.InitialName; } Chat.AddExamineMsgFromServer( interaction.Performer, $"The {machineName} must be removed before you can cut the disposal pipe welds!"); return(true); } } return(false); }
public bool Interact(MouseDrop interaction) { Logger.Log("Interaction detected on InteractableTiles."); LayerTile tile = LayerTileAt(interaction.ShadowWorldLocation, true); if (tile is BasicTile basicTile) { var tileApply = new TileApply(interaction.Performer, interaction.UsedObject, interaction.Intent, (Vector2Int)WorldToCell(interaction.ShadowWorldLocation), this, basicTile, null, -((Vector2)interaction.Performer.transform.position - interaction.ShadowWorldLocation), TileApply.ApplyType.MouseDrop); var tileMouseDrop = new TileMouseDrop(interaction.Performer, interaction.UsedObject, interaction.Intent, (Vector2Int)WorldToCell(interaction.ShadowWorldLocation), this, basicTile, -((Vector2)interaction.Performer.transform.position - interaction.ShadowWorldLocation)); foreach (var tileInteraction in basicTile.TileInteractions) { if (tileInteraction == null) { continue; } if (tileInteraction.WillInteract(tileApply, NetworkSide.Client) && Cooldowns.TryStartClient(interaction, CommonCooldowns.Instance.Interaction)) { //request the tile interaction because we think one will happen RequestInteractMessage.SendTileMouseDrop(tileMouseDrop, this); return(true); } } } return(false); }
public override bool WillInteract(TileApply interaction, NetworkSide side) { if (!DefaultWillInteract.Default(interaction, side)) { return(false); } return(interaction.HandObject != null); }
public override void ServerPerformInteraction(TileApply interaction) { if (VerboseDisposalMachineExists(interaction)) { return; } Weld(interaction); }
/// <summary> /// Performs common tool usage logic and also sends start / end action messages, and invokes a callback on success. /// </summary> /// <param name="tileApply">interaction causing the tool use</param> /// <param name="seconds">seconds taken to perform the action, 0 if it should be instant</param> /// <param name="performerStartActionMessage">message to show performer when action begins.</param> /// <param name="othersStartActionMessage">message to show others when action begins.</param> /// <param name="performerFinishActionMessage">message to show performer when action completes successfully.</param> /// <param name="othersFinishActionMessage">message to show others when action completes successfully.</param> /// <param name="onSuccessfulCompletion">called when action is completed</param> public static void ServerUseToolWithActionMessages(TileApply tileApply, float seconds, string performerStartActionMessage, string othersStartActionMessage, string performerFinishActionMessage, string othersFinishActionMessage, Action onSuccessfulCompletion) { ServerUseToolWithActionMessages(tileApply.Performer, tileApply.HandObject, ActionTarget.Tile(tileApply.WorldPositionTarget), seconds, performerStartActionMessage, othersStartActionMessage, performerFinishActionMessage, othersFinishActionMessage, onSuccessfulCompletion); }
public override bool WillInteract(TileApply interaction, NetworkSide side) { if (DefaultWillInteract.Default(interaction, side) == false) { return(false); } return(Validations.HasUsedActiveWelder(interaction)); }
private void Weld(TileApply interaction) { ToolUtils.ServerUseToolWithActionMessages( interaction, seconds, "You start slicing the welds that secure the disposal pipe...", $"{interaction.Performer.ExpensiveName()} starts cutting the disposal pipe welds...", "You cut the disposal pipe welds.", $"{interaction.Performer.ExpensiveName()} cuts the disposal pipe welds.", () => DeconstructPipe(interaction) ); }
/// <summary> /// Performs common tool usage logic and also sends start / end action messages, and invokes a callback on success. /// </summary> /// <param name="tileApply">interaction causing the tool use</param> /// <param name="seconds">seconds taken to perform the action, 0 if it should be instant</param> /// <param name="performerStartActionMessage">message to show performer when action begins.</param> /// <param name="othersStartActionMessage">message to show others when action begins.</param> /// <param name="performerFinishActionMessage">message to show performer when action completes successfully.</param> /// <param name="othersFinishActionMessage">message to show others when action completes successfully.</param> /// <param name="onSuccessfulCompletion">called when action is completed</param> /// <param name="performerFailMessage">message to show performer when action completes unsuccessfully.</param> /// <param name="othersFailMessage">message to show others when action completes unsuccessfully.</param> /// <param name="onFailComplete">called when action is completed unsuccessfully.</param> /// <param name="playSound">Whether to play default tool sound</param> public static void ServerUseToolWithActionMessages(TileApply tileApply, float seconds, string performerStartActionMessage, string othersStartActionMessage, string performerFinishActionMessage, string othersFinishActionMessage, Action onSuccessfulCompletion, string performerFailMessage = "", string othersFailMessage = "", Action onFailComplete = null, bool playSound = true) { ServerUseToolWithActionMessages(tileApply.Performer, tileApply.HandObject, ActionTarget.Tile(tileApply.WorldPositionTarget), seconds, performerStartActionMessage, othersStartActionMessage, performerFinishActionMessage, othersFinishActionMessage, onSuccessfulCompletion, performerFailMessage, othersFailMessage, onFailComplete, playSound); }
/// <summary> /// Interaction callback to attempt to interact with tiles using a HandApply /// interaction. We check for both basic tiles and under floor tiles and /// attempt to apply its interaction. In the event that an electric cable /// tile is encountered, we open the cable cutting window. /// </summary> /// <param name="interaction">Position of interaction with a hand</param> public bool Interact(PositionalHandApply interaction) { // translate to the tile interaction system Vector3Int localPosition = WorldToCell(interaction.WorldPositionTarget); // pass the interaction down to the basic tile LayerTile tile = LayerTileAt(interaction.WorldPositionTarget, true); // If the tile we're looking at is a basic tile... if (tile is BasicTile basicTile) { // If the the tile is something that's supposed to be underneath floors... if (basicTile.LayerType == LayerType.Underfloor) { // Then we loop through each under floor layer in the matrix until we // can find an interaction. foreach (BasicTile underFloorTile in matrix.MetaTileMap.GetAllTilesByType <BasicTile>(localPosition, LayerType.Underfloor)) { // If pointing at electrical cable tile and player is holding // Wirecutter in hand, we enable the cutting window and return false // to indicate that we will not be interacting with anything... yet. // TODO: Check how many cables we have first. Only open the cable // cutting window when the number of cables exceeds 2. if (underFloorTile is ElectricalCableTile && Validations.HasItemTrait(PlayerManager.LocalPlayerScript.DynamicItemStorage.GetActiveHandSlot().ItemObject, CommonTraits.Instance.Wirecutter)) { // open cable cutting ui window instead of cutting cable EnableCableCuttingWindow(); // return false to not cut the cable return(false); } // Else, we attempt to interact with the tile with whatever is in our // at the target. else { var underFloorApply = new TileApply(interaction.Performer, interaction.UsedObject, interaction.Intent, (Vector2Int)localPosition, this, underFloorTile, interaction.HandSlot, interaction.TargetVector); if (TryInteractWithTile(underFloorApply)) { return(true); } } } } else { var tileApply = new TileApply(interaction.Performer, interaction.UsedObject, interaction.Intent, (Vector2Int)localPosition, this, basicTile, interaction.HandSlot, interaction.TargetVector); return(TryInteractWithTile(tileApply)); } } return(false); }
public override void ServerPerformInteraction(TileApply interaction) { ToolUtils.ServerUseToolWithActionMessages(interaction, seconds, performerStartActionMessage, Chat.ReplacePerformer(othersStartActionMessage, interaction.Performer), performerFinishActionMessage, Chat.ReplacePerformer(othersFinishActionMessage, interaction.Performer), () => { interaction.TileChangeManager.UpdateTile(interaction.TargetCellPos, toTile); interaction.TileChangeManager.SubsystemManager.UpdateAt(interaction.TargetCellPos); }); }
// Start is called before the first frame update public override bool WillInteract(TileApply interaction, NetworkSide side) { if (!DefaultWillInteract.Default(interaction, side)) { return(false); } if (requiredTrait == CommonTraits.Instance.Welder) { return(Validations.HasUsedActiveWelder(interaction)); } return(Validations.HasItemTrait(interaction.HandObject, requiredTrait)); }
//for internal IF2 usages only, does server side logic for processing tileapply public void ServerProcessInteraction(GameObject performer, Vector2 targetVector, GameObject processorObj, ItemSlot usedSlot, GameObject usedObject, Intent intent, TileApply.ApplyType applyType) { //find the indicated tile interaction var worldPosTarget = (Vector2)performer.transform.position + targetVector; Vector3Int localPosition = WorldToCell(worldPosTarget); //pass the interaction down to the basic tile LayerTile tile = LayerTileAt(worldPosTarget, true); if (tile is BasicTile basicTile) { // check which tile interaction occurs in the correct order Logger.LogTraceFormat( "Server checking which tile interaction to trigger for TileApply on tile {0} at worldPos {1}", Category.Interaction, tile.name, worldPosTarget); if (basicTile.LayerType == LayerType.Underfloor) { foreach (var underFloorTile in matrix.UnderFloorLayer.GetAllTilesByType <BasicTile>(localPosition)) { var underFloorApply = new TileApply( performer, usedObject, intent, (Vector2Int)localPosition, this, underFloorTile, usedSlot, targetVector, applyType); foreach (var tileInteraction in underFloorTile.TileInteractions) { if (tileInteraction == null) { continue; } if (tileInteraction.WillInteract(underFloorApply, NetworkSide.Server)) { PerformTileInteract(underFloorApply); break; } } } } else { var tileApply = new TileApply( performer, usedObject, intent, (Vector2Int)localPosition, this, basicTile, usedSlot, targetVector, applyType); PerformTileInteract(tileApply); } } }
public override bool WillInteract(TileApply interaction, NetworkSide side) { if (!DefaultWillInteract.Default(interaction, side)) { return(false); } if (interaction.TileApplyType != TileApply.ApplyType.HandApply) { return(false); } if (interaction.Intent == Intent.Harm) { return(false); } return(interaction.HandObject != null); }
public override void ServerPerformInteraction(TileApply interaction) { if (!interaction.UsedObject.RegisterTile().Matrix.IsPassableAtOneMatrixOneTile(interaction.TargetCellPos, true, true, null, excludeTiles)) { return; } StandardProgressActionConfig cfg = new StandardProgressActionConfig(StandardProgressActionType.Construction, false, false, false); var x = StandardProgressAction.Create(cfg, () => { PlayerScript playerScript; if (interaction.UsedObject.TryGetComponent(out playerScript)) { List <TileType> excludeTiles = new List <TileType>() { TileType.Table }; if (playerScript.registerTile.Matrix.IsPassableAtOneMatrixOneTile(interaction.TargetCellPos, true, true, null, excludeTiles)) { playerScript.PlayerSync.SetPosition(interaction.WorldPositionTarget); } } else { var transformComp = interaction.UsedObject.GetComponent <CustomNetTransform>(); if (transformComp != null) { transformComp.AppearAtPositionServer(interaction.WorldPositionTarget); } } if (canBreakOnClimb == false) { return; } if (DMMath.Prob(breakChance) && interaction.UsedObject.TryGetComponent <RegisterPlayer>(out var victim)) { interaction.BasicTile.SpawnOnDestroy.SpawnAt(SpawnDestination.At(interaction.WorldPositionTarget)); victim.ServerStun(stunTimeOnBreak); _ = SoundManager.PlayNetworkedAtPosAsync(soundOnBreak, interaction.WorldPositionTarget); Chat.AddActionMsgToChat(interaction.UsedObject, $"Your weight pushes onto the {interaction.BasicTile.DisplayName} and you break it and fall through it", $"{interaction.UsedObject.ExpensiveName()} falls through the {interaction.BasicTile.DisplayName} as it breaks from their weight."); victim.PlayerScript.playerHealth.ApplyDamageAll(interaction.Performer, damageOnBreak, AttackType.Melee, DamageType.Brute); interaction.TileChangeManager.MetaTileMap.RemoveTileWithlayer(interaction.TargetCellPos, interaction.BasicTile.LayerType); } }).ServerStartProgress(interaction.UsedObject.RegisterTile(), 3.0f, interaction.Performer);
private void DeconstructPipe(TileApply interaction) { DisposalPipe pipeTile = interaction.BasicTile as DisposalPipe; // Despawn pipe tile var matrix = MatrixManager.AtPoint(interaction.WorldPositionTarget.NormalizeTo3Int(), true).Matrix; MetaDataNode metaDataNode = matrix.GetMetaDataNode(interaction.TargetCellPos, false); DisposalPipeNode disPipeNode = null; for (var i = 0; i < metaDataNode.DisposalPipeData.Count; i++) { if (metaDataNode.DisposalPipeData[i].DisposalPipeTile == pipeTile) { disPipeNode = metaDataNode.DisposalPipeData[i]; } } if (disPipeNode == null) { Logger.LogError($"Impossible to deconstruct the disposal pipe at {interaction.TargetCellPos} in {matrix.gameObject.scene.name} - {matrix.name}. Disposal pipe node wasn't found", Category.Pipes); return; } matrix.TileChangeManager.RemoveTile(disPipeNode.NodeLocation, LayerType.Underfloor); // Spawn pipe GameObject if (interaction.BasicTile.SpawnOnDeconstruct == null) { return; } var spawn = Spawn.ServerPrefab(interaction.BasicTile.SpawnOnDeconstruct, interaction.WorldPositionTarget); if (spawn.Successful == false) { return; } if (spawn.GameObject.TryGetComponent <Directional>(out var directional)) { directional.FaceDirection(Orientation.FromEnum(pipeTile.DisposalPipeObjectOrientation)); } if (spawn.GameObject.TryGetComponent <ObjectBehaviour>(out var behaviour)) { behaviour.ServerSetPushable(false); } }
public override void ServerPerformInteraction(TileApply interaction) { ToolUtils.ServerUseToolWithActionMessages(interaction, seconds, performerStartActionMessage, Chat.ReplacePerformer(othersStartActionMessage, interaction.Performer), performerFinishActionMessage, Chat.ReplacePerformer(othersFinishActionMessage, interaction.Performer), () => { interaction.TileChangeManager.UpdateTile(interaction.TargetCellPos, toTile); if (objectsToSpawn != null) { objectsToSpawn.SpawnAt(SpawnDestination.At(interaction.WorldPositionTarget)); } interaction.TileChangeManager.SubsystemManager.UpdateAt(interaction.TargetCellPos); }); }
public override bool WillInteract(TileApply interaction, NetworkSide side) { if (!DefaultWillInteract.Default(interaction, side)) { return(false); } if (interaction.Intent == Intent.Harm) { return(false); } if (interaction.HandObject != null) { return(false); } //don't allow spamming window knocks really fast return(Cooldowns.TryStart(interaction, this, 1, side)); }
//for internal IF2 usages only, does server side logic for processing tileapply public void ServerProcessInteraction(GameObject performer, Vector2 targetVector, GameObject processorObj, ItemSlot usedSlot, GameObject usedObject, Intent intent, TileApply.ApplyType applyType) { //find the indicated tile interaction var worldPosTarget = (Vector2)performer.transform.position + targetVector; //pass the interaction down to the basic tile LayerTile tile = LayerTileAt(worldPosTarget, true); if (tile is BasicTile basicTile) { // check which tile interaction occurs in the correct order Logger.LogTraceFormat("Server checking which tile interaction to trigger for TileApply on tile {0} at worldPos {1}", Category.Interaction, tile.name, worldPosTarget); var tileApply = new TileApply(performer, usedObject, intent, (Vector2Int)WorldToCell(worldPosTarget), this, basicTile, usedSlot, targetVector, applyType); foreach (var tileInteraction in basicTile.TileInteractions) { if (tileInteraction == null) { continue; } if (tileInteraction.WillInteract(tileApply, NetworkSide.Server)) { //perform if not on cooldown if (Cooldowns.TryStartServer(tileApply, CommonCooldowns.Instance.Interaction)) { tileInteraction.ServerPerformInteraction(tileApply); } else { //hit a cooldown, rollback in case client tried to predict it tileInteraction.ServerRollbackClient(tileApply); } // interaction should've triggered and did or we hit a cooldown, so we're // done processing this request. break; } else { tileInteraction.ServerRollbackClient(tileApply); } } } }
// We electrocute the performer in WillInteract() instead of ServerPerformInteraction() // because we would like for the performer to be able to perform other interactions // if the electrocution was merely mild. public override bool WillInteract(TileApply interaction, NetworkSide side) { this.interaction = interaction; if (!DefaultWillInteract.Default(interaction, side)) { return(false); } // Let only the server continue, as ServerGetGrilleVoltage() depends on the server-side-only electrical system. if (side == NetworkSide.Client) { return(true); } bool othersWillInteract = false; foreach (var otherInteraction in interaction.BasicTile.TileInteractions) { if (otherInteraction == this) { continue; } if (otherInteraction.WillInteract(interaction, side)) { othersWillInteract = true; break; } } // If no other grille interactions were available, and the performer intends to harm: attack! // This is somewhat of a hack; other interactions should be handled by InteractionUtils, // however the server will not process other interactions (only other tile interactions) if this WillInteract() // returns true on the client (which it must, as the electrical system runs server-side only). // This means attack interactions would be incorrectly ignored. if (!othersWillInteract && (interaction.Intent == Intent.Harm || interaction.HandObject != null)) { var matrix = interaction.TileChangeManager.MetaTileMap.Layers[LayerType.Grills].matrix; var weaponNA = interaction.Performer.GetComponent <WeaponNetworkActions>(); weaponNA.ServerPerformMeleeAttack( matrix.transform.parent.gameObject, interaction.TargetVector, BodyPartType.None, interaction.BasicTile.LayerType); } return(Electrocute(ServerGetGrilleVoltage())); }
public override void ServerPerformInteraction(TileApply interaction) { string othersMessage = Chat.ReplacePerformer(othersStartActionMessage, interaction.Performer); Chat.AddActionMsgToChat(interaction.Performer, performerStartActionMessage, othersMessage); if (interaction.BasicTile.LayerType != LayerType.Underfloor) { return; } var ElectricalCable = interaction.BasicTile as ElectricalCableTile; if (ElectricalCable == null) { return; } var matrix = interaction.TileChangeManager.MetaTileMap.Layers[LayerType.Underfloor].matrix; var metaDataNode = matrix.GetMetaDataNode(interaction.TargetCellPos); foreach (var ElectricalData in metaDataNode.ElectricalData) { if (ElectricalData.RelatedTile != ElectricalCable) { continue; } // Electrocute the performer. If shock is painful enough, cancel the interaction. ElectricityFunctions.WorkOutActualNumbers(ElectricalData.InData); float voltage = ElectricalData.InData.Data.ActualVoltage; var electrocution = new Electrocution(voltage, interaction.WorldPositionTarget, "cable"); var performerLHB = interaction.Performer.GetComponent <LivingHealthMasterBase>(); var severity = performerLHB.Electrocute(electrocution); if (severity > LivingShockResponse.Mild) { return; } ElectricalData.InData.DestroyThisPlease(); Spawn.ServerPrefab(ElectricalCable.SpawnOnDeconstruct, interaction.WorldPositionTarget, count: ElectricalCable.SpawnAmountOnDeconstruct); return; } }
public override void ServerPerformInteraction(TileApply interaction) { if (interaction.HandObject == null) { Chat.AddActionMsgToChat(interaction.Performer, $"You knock on the {interaction.BasicTile.DisplayName}.", $"{interaction.Performer.ExpensiveName()} knocks on the {interaction.BasicTile.DisplayName}."); SoundManager.GlassknockAtPosition(interaction.WorldPositionTarget, interaction.Performer); } else { ToolUtils.ServerUseToolWithActionMessages(interaction, 4f, $"You begin repairing the {interaction.BasicTile.DisplayName}...", $"{interaction.Performer.ExpensiveName()} begins to repair the {interaction.BasicTile.DisplayName}...", $"You repair the {interaction.BasicTile.DisplayName}.", $"{interaction.Performer.ExpensiveName()} repairs the {interaction.BasicTile.DisplayName}.", () => RepairWindow(interaction)); } }