diff --git a/EXILED/Exiled.API/Enums/BloodType.cs b/EXILED/Exiled.API/Enums/BloodType.cs
deleted file mode 100644
index 369793e2a..000000000
--- a/EXILED/Exiled.API/Enums/BloodType.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-// -----------------------------------------------------------------------
-//
-// Copyright (c) ExMod Team. All rights reserved.
-// Licensed under the CC BY-SA 3.0 license.
-//
-// -----------------------------------------------------------------------
-
-namespace Exiled.API.Enums
-{
- using System;
-
- ///
- /// Unique identifier for the different types of blood decals.
- ///
- ///
- ///
- [Obsolete("This blood decal are outdated now used DecalPoolType.Blood", true)]
- public enum BloodType
- {
- ///
- /// The default blood decal.
- ///
- Default,
-
- ///
- /// The blood decal placed after Scp106 sends someone to the pocket dimension.
- ///
- Scp106,
-
- ///
- /// The spreaded blood decal.
- ///
- Spreaded,
-
- ///
- /// The faded blood decal.
- ///
- Faded,
- }
-}
\ No newline at end of file
diff --git a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
index bbd325878..66452d24e 100644
--- a/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
+++ b/EXILED/Exiled.API/Extensions/MirrorExtensions.cs
@@ -22,7 +22,10 @@ namespace Exiled.API.Extensions
using CustomPlayerEffects;
+ using Decals;
+
using Exiled.API.Enums;
+ using Exiled.API.Features.Items;
using Exiled.API.Features.Items.Keycards;
using Exiled.API.Features.Pickups.Keycards;
@@ -56,6 +59,8 @@ namespace Exiled.API.Extensions
using Utils.Networking;
+ using Firearm = Features.Items.Firearm;
+
///
/// A set of extensions for Networking.
///
@@ -211,58 +216,245 @@ public static ReadOnlyDictionary RpcFullNames
///
/// Target to play.
/// Position to play on.
- /// Weapon' sound to play.
- /// Sound's volume to set.
- /// GunAudioMessage's audioClipId to set (default = 0).
- [Obsolete("This method is not working. Use PlayGunSound(Player, Vector3, FirearmType, float, int, bool) overload instead.")]
- public static void PlayGunSound(this Player player, Vector3 position, ItemType itemType, byte volume, byte audioClipId = 0)
- => PlayGunSound(player, position, itemType.GetFirearmType(), volume, audioClipId);
+ /// Weapon's sound to play.
+ /// Speed of sound.
+ /// Index of clip.
+ [Obsolete("This method is deprecated, use PlayGunSound(this Player, FirearmType, int, Vector3, MixerChannel, float, float) instead.")]
+ public static void PlayGunSound(this Player player, Vector3 position, FirearmType firearmType, float pitch = 1, int clipIndex = 0) => player.PlayGunSound(firearmType, clipIndex, position, pitch: pitch);
///
/// Plays a gun sound that only the can hear.
///
/// Target to play.
- /// Position to play on.
/// Weapon's sound to play.
- /// Speed of sound.
/// Index of clip.
- public static void PlayGunSound(this Player player, Vector3 position, FirearmType firearmType, float pitch = 1, int clipIndex = 0)
+ /// Position to play on.
+ /// Audio's mixer channel.
+ /// Max range of sound.
+ /// Speed of sound.
+ public static void PlayGunSound(this Player player, FirearmType firearmType, int clipIndex, Vector3 position, MixerChannel mixerChannel = MixerChannel.Weapons, float? range = null, float? pitch = null)
{
- if (firearmType is FirearmType.ParticleDisruptor or FirearmType.None)
+ if (firearmType is FirearmType.None)
+ {
+ Log.Error($"Failed to play gun sound for player {player.Nickname} because firearm type was None.");
return;
+ }
- Features.Items.Firearm firearm = Features.Items.Firearm.ItemTypeToFirearmInstance[firearmType];
+ if (!InventoryItemLoader.TryGetItem(firearmType.GetItemType(), out ItemBase itemBase))
+ {
+ Log.Error($"Failed to get ItemBase for firearm type {firearmType} when trying to play gun sound for player {player.Nickname}");
+ return;
+ }
+ Firearm firearm = Item.Get(itemBase);
if (firearm == null)
+ {
+ Log.Error($"Failed to get Firearm for firearm type {firearmType} when trying to play gun sound.");
return;
+ }
using (NetworkWriterPooled writer = NetworkWriterPool.Get())
{
writer.WriteUShort(NetworkMessageId.Id);
- new RoleSyncInfo(Server.Host.ReferenceHub, RoleTypeId.ClassD, player.ReferenceHub, null).Write(writer);
+ new RoleSyncInfo(Server.Host.ReferenceHub, RoleTypeId.Tutorial, player.ReferenceHub, null).Write(writer);
writer.WriteRelativePosition(new RelativePosition(0, 0, 0, 0, false));
writer.WriteUShort(0);
player.Connection.Send(writer);
}
- firearm.BarrelAmmo = 1;
- firearm.BarrelMagazine.IsCocked = true;
player.SendFakeSyncVar(Server.Host.Inventory.netIdentity, typeof(Inventory), nameof(Inventory.NetworkCurItem), firearm.Identifier);
- if (!firearm.Base.TryGetModule(out AudioModule audioModule))
- return;
-
- Timing.CallDelayed(0.1f, () => // due to selecting item we need to delay shot a bit
+ Timing.CallDelayed(0.1f, () =>
{
- audioModule.SendRpc(player.ReferenceHub, writer =>
- audioModule.ServerSend(writer, clipIndex, pitch, MixerChannel.Weapons, 12f, position, false));
+ if (!player.IsConnected)
+ return;
+ firearm.PlaySound(player, clipIndex, mixerChannel, position, shooterVisible: false, range, pitch);
player.SendFakeSyncVar(Server.Host.Inventory.netIdentity, typeof(Inventory), nameof(Inventory.NetworkCurItem), ItemIdentifier.None);
-
player.Connection.Send(new RoleSyncInfo(Server.Host.ReferenceHub, Server.Host.Role, player.ReferenceHub, null));
});
}
+ ///
+ /// Plays a gun sound to the specified player.
+ ///
+ /// The firearm whose to use.
+ /// The player to send the sound to.
+ /// The index of the audio clip to play.
+ /// The to play the sound on.
+ /// The world position the sound originates from.
+ /// Whether the shooter is visible to the target. If , the sound will be played at instead of on the firearm's transform.
+ /// The range of the sound.
+ /// The pitch of the sound.
+ /// if the sound was played successfully; if is .
+ public static bool PlaySound(this Firearm firearm, Player target, int index, MixerChannel channel, Vector3 position, bool shooterVisible, float? range = null, float? pitch = null)
+ {
+ AudioModule audioModule = firearm.AudioModule;
+ if (audioModule == null)
+ {
+ Log.Error($"Firearm {firearm} doesn't have an audio module.");
+ return false;
+ }
+
+ if (target == null)
+ {
+ Log.Error("Target player is null.");
+ return false;
+ }
+
+ if (!range.HasValue)
+ range = audioModule.FinalGunshotRange;
+
+ if (!pitch.HasValue)
+ pitch = audioModule.RandomPitch;
+
+ audioModule.SendRpc(target.ReferenceHub, writer => audioModule.ServerSend(writer, index, pitch.Value, channel, range.Value, position, shooterVisible));
+ return true;
+ }
+
+ ///
+ /// Plays a gun sound to the specified players.
+ ///
+ /// The firearm whose to use.
+ /// The players to send the sound to.
+ /// The index of the audio clip to play.
+ /// The to play the sound on.
+ /// The world position the sound originates from.
+ /// Whether the shooter is visible to the target. If , the sound will be played at instead of on the firearm's transform.
+ /// The range of the sound.
+ /// The pitch of the sound.
+ /// if the sound was played successfully; if is .
+ public static bool PlaySound(this Firearm firearm, IEnumerable targets, int index, MixerChannel channel, Vector3 position, bool shooterVisible, float? range = null, float? pitch = null)
+ {
+ AudioModule audioModule = firearm.AudioModule;
+ if (audioModule == null)
+ {
+ Log.Error($"Firearm {firearm} doesn't have an audio module.");
+ return false;
+ }
+
+ if (targets == null)
+ {
+ Log.Error("Failed to play sound, targets is null.");
+ return false;
+ }
+
+ if (!range.HasValue)
+ range = audioModule.FinalGunshotRange;
+
+ if (!pitch.HasValue)
+ pitch = audioModule.RandomPitch;
+
+ HashSet targetHubs = targets.Select(p => p.ReferenceHub).ToHashSet();
+
+ audioModule.SendRpc(targetHubs.Contains, writer => audioModule.ServerSend(writer, index, pitch.Value, channel, range.Value, position, shooterVisible));
+ return true;
+ }
+
+ ///
+ /// Spawns a blood decal for this player.
+ ///
+ /// Target to spawn blood decal for.
+ /// The position of the blood decal.
+ /// The raycast origin used to determine the decal's orientation.
+ /// if the blood decal was successfully spawned; otherwise, .
+ public static bool SpawnBlood(this Player player, Vector3 position, Vector3 sourcePosition) => SpawnDecal(player, position, sourcePosition, DecalPoolType.Blood);
+
+ ///
+ /// Spawns a blood decal for the specified players.
+ ///
+ /// The players for which to spawn the blood decal.
+ /// The position of the blood decal.
+ /// The raycast origin used to determine the decal's orientation.
+ /// if the blood decal was successfully spawned; otherwise, .
+ public static bool SpawnBlood(this IEnumerable players, Vector3 position, Vector3 sourcePosition) => SpawnDecal(players, position, sourcePosition, DecalPoolType.Blood, FirearmType.Com15);
+
+ ///
+ /// Spawns a decal for this player.
+ ///
+ /// Target to spawn decal for.
+ /// The position of the decal.
+ /// The raycast origin used to determine the decal's orientation.
+ /// The .
+ /// The to use.
+ /// if the decal was successfully spawned; otherwise, .
+ public static bool SpawnDecal(this Player player, Vector3 position, Vector3 sourcePosition, DecalPoolType decalType, FirearmType firearmType = FirearmType.Com15)
+ {
+ if (!InventoryItemLoader.TryGetItem(firearmType.GetItemType(), out ItemBase itemBase))
+ {
+ Log.Error($"Failed to spawn decal: Could not find a Firearm for {firearmType}.");
+ return false;
+ }
+
+ Firearm firearm = Item.Get(itemBase);
+ if (firearm == null)
+ {
+ Log.Error($"Failed to spawn decal: Could not find a Firearm for {firearmType}.");
+ return false;
+ }
+
+ ImpactEffectsModule impactEffectsModule = firearm.ImpactEffectsModule;
+ if (impactEffectsModule == null)
+ {
+ Log.Error($"Failed to spawn decal: Could not find an ImpactEffectsModule for {firearmType}.");
+ return false;
+ }
+
+ impactEffectsModule.SendRpc(player.ReferenceHub, writer =>
+ {
+ writer.WriteSubheader(ImpactEffectsModule.RpcType.ImpactDecal);
+ writer.WriteByte((byte)decalType);
+ writer.WriteRelativePosition(new RelativePosition(position));
+ writer.WriteRelativePosition(new RelativePosition(sourcePosition));
+ });
+
+ return true;
+ }
+
+ ///
+ /// Spawns a decal for the specified targets.
+ ///
+ /// The targets for which to spawn the decal.
+ /// The position of the decal.
+ /// The raycast origin used to determine the decal's orientation.
+ /// The .
+ /// The to use.
+ /// if the decal was successfully spawned; otherwise, .
+ public static bool SpawnDecal(this IEnumerable targets, Vector3 position, Vector3 sourcePosition, DecalPoolType decalType, FirearmType firearmType = FirearmType.Com15)
+ {
+ if (!InventoryItemLoader.TryGetItem(firearmType.GetItemType(), out ItemBase itemBase))
+ {
+ Log.Error($"Failed to spawn decal: Could not find a Firearm for {firearmType}.");
+ return false;
+ }
+
+ Firearm firearm = Item.Get(itemBase);
+ if (firearm == null)
+ {
+ Log.Error($"Failed to spawn decal: Could not find a Firearm for {firearmType}.");
+ return false;
+ }
+
+ ImpactEffectsModule impactEffectsModule = firearm.ImpactEffectsModule;
+ if (impactEffectsModule == null)
+ {
+ Log.Error($"Failed to spawn decal: Could not find an ImpactEffectsModule for {firearmType}.");
+ return false;
+ }
+
+ HashSet targetHubs = targets.Select(p => p.ReferenceHub).ToHashSet();
+
+ impactEffectsModule.SendRpc(targetHubs.Contains, writer =>
+ {
+ writer.WriteSubheader(ImpactEffectsModule.RpcType.ImpactDecal);
+ writer.WriteByte((byte)decalType);
+ writer.WriteRelativePosition(new RelativePosition(position));
+ writer.WriteRelativePosition(new RelativePosition(sourcePosition));
+ });
+
+ return true;
+ }
+
///
/// Place blood that only the can see.
///
@@ -271,6 +463,7 @@ public static void PlayGunSound(this Player player, Vector3 position, FirearmTyp
/// The direction of the blood decal.
/// The RoleTypeId from who blood come from.
/// The sound than player get when getting shot.
+ [Obsolete("Use Player::SpawnBlood(Vector3, Vector3) instead.")]
#pragma warning disable IDE0060 // TODO: Deleted the unused param
public static void PlaceBlood(this Player player, Vector3 position, Vector3 origin, RoleTypeId roleTypeId, int gettingShotSoundIndex)
#pragma warning restore IDE0060
diff --git a/EXILED/Exiled.API/Features/Items/Firearm.cs b/EXILED/Exiled.API/Features/Items/Firearm.cs
index 00630fad3..4aea76359 100644
--- a/EXILED/Exiled.API/Features/Items/Firearm.cs
+++ b/EXILED/Exiled.API/Features/Items/Firearm.cs
@@ -10,6 +10,8 @@ namespace Exiled.API.Features.Items
using System.Collections.Generic;
using System.Linq;
+ using AudioPooling;
+
using CameraShaking;
using Enums;
@@ -28,7 +30,10 @@ namespace Exiled.API.Features.Items
using InventorySystem.Items.Firearms.Attachments.Components;
using InventorySystem.Items.Firearms.Modules;
+ using UnityEngine;
+
using static InventorySystem.Items.Firearms.Modules.AnimatorReloaderModuleBase;
+ using static InventorySystem.Items.Firearms.Modules.AutomaticActionModule;
using BaseFirearm = InventorySystem.Items.Firearms.Firearm;
using FirearmPickup = Pickups.FirearmPickup;
@@ -67,6 +72,8 @@ public Firearm(BaseFirearm itemBase)
case IAmmoContainerModule ammoModule:
BarrelMagazine ??= (BarrelMagazine)Magazine.Get(ammoModule);
+ if (module is AutomaticActionModule automaticActionModule)
+ AutomaticActionModule = automaticActionModule;
break;
case HitscanHitregModuleBase hitregModule:
@@ -77,6 +84,14 @@ public Firearm(BaseFirearm itemBase)
AnimatorReloaderModule = animatorReloaderModule;
break;
+ case ImpactEffectsModule impactEffectsModule:
+ ImpactEffectsModule = impactEffectsModule;
+ break;
+
+ case AudioModule audioModule:
+ AudioModule = audioModule;
+ break;
+
default:
break;
}
@@ -152,6 +167,21 @@ public static IReadOnlyDictionary
public AnimatorReloaderModuleBase AnimatorReloaderModule { get; }
+ ///
+ /// Gets an impact effects module for the current firearm.
+ ///
+ public ImpactEffectsModule ImpactEffectsModule { get; }
+
+ ///
+ /// Gets an automatic action module for the current firearm.
+ ///
+ public AutomaticActionModule AutomaticActionModule { get; }
+
+ ///
+ /// Gets an audio module for the current firearm.
+ ///
+ public AudioModule AudioModule { get; }
+
///
/// Gets or sets the amount of ammo in the firearm magazine.
///
@@ -757,6 +787,64 @@ public void Unload()
AnimatorReloaderModule.SendRpcHeaderWithRandomByte(ReloaderMessageHeader.Unload);
}
+ ///
+ /// Plays a firearm sound to nearby players.
+ ///
+ /// The index of the audio clip to play.
+ /// The to play the sound on.
+ /// The range within which nearby players can hear the sound.
+ /// The pitch of the sound.
+ /// if the sound was played successfully; if is .
+ public bool PlaySound(int index, MixerChannel channel, float? range = null, float? pitch = null)
+ {
+ if (AudioModule == null)
+ {
+ Log.Error($"Failed to play sound, firearm {Type} does not have an AudioModule.");
+ return false;
+ }
+
+ if (!range.HasValue)
+ range = AudioModule.FinalGunshotRange;
+
+ if (!pitch.HasValue)
+ pitch = AudioModule.RandomPitch;
+
+ AudioModule.ServerSendToNearbyPlayers(index, channel, range.Value, pitch.Value);
+ return true;
+ }
+
+ ///
+ /// Simulates a fire.
+ ///
+ /// Rpc header for fire type like fire or dry fire.
+ /// The number of chambers fired.
+ /// The index of the sound to play. 0 is DryFire, 1 is default gunshot.
+ public void FakeFire(MessageHeader rpcHeader = MessageHeader.RpcFire, byte chambersFired = 1, byte soundIndex = 1)
+ {
+ PlaySound(soundIndex, MixerChannel.Weapons, AudioModule.FinalGunshotRange, AudioModule.RandomPitch);
+
+ if (AutomaticActionModule?.gameObject != null)
+ {
+ AutomaticActionModule.SendRpc(
+ writer =>
+ {
+ writer.WriteSubheader(rpcHeader);
+ if (rpcHeader == MessageHeader.RpcFire)
+ writer.WriteByte(chambersFired);
+ },
+ true);
+ }
+
+ if (ImpactEffectsModule != null)
+ {
+ Transform camera = Owner.CameraTransform;
+ float maxDist = HitscanHitregModule.FullDamageDistance + HitscanHitregModule.DamageFalloffDistance;
+
+ if (Physics.Raycast(camera.position, camera.forward, out RaycastHit hit, maxDist, HitscanHitregModuleBase.HitregMask))
+ ImpactEffectsModule.ServerProcessHit(hit, camera.position, true);
+ }
+ }
+
///
/// Clones current object.
///
diff --git a/EXILED/Exiled.API/Features/Map.cs b/EXILED/Exiled.API/Features/Map.cs
index 5f3205755..a7c59a1ee 100644
--- a/EXILED/Exiled.API/Features/Map.cs
+++ b/EXILED/Exiled.API/Features/Map.cs
@@ -27,6 +27,9 @@ namespace Exiled.API.Features
using Interactables.Interobjects;
using InventorySystem;
+ using InventorySystem.Items;
+ using InventorySystem.Items.Autosync;
+ using InventorySystem.Items.Firearms.Modules;
using InventorySystem.Items.Pickups;
using InventorySystem.Items.ThrowableProjectiles;
@@ -36,8 +39,12 @@ namespace Exiled.API.Features
using MapGeneration;
+ using Mirror;
+
using PlayerRoles.Ragdolls;
+ using RelativePositioning;
+
using RemoteAdmin;
using UnityEngine;
@@ -436,12 +443,64 @@ public static void CleanAllRagdolls(IEnumerable ragDolls)
public static void Clean(DecalPoolType decalType) => Clean(decalType, int.MaxValue);
///
- /// Places a blood decal.
+ /// Places a blood decal using a raycast.
+ ///
+ /// The origin position of the raycast.
+ /// The direction in which the raycast is fired to detect a surface.
+ public static void PlaceBlood(Vector3 position, Vector3 direction)
+ {
+ if (Physics.Raycast(position, direction, out RaycastHit hitInfo, ImpactEffectsModule.ReceivingLayers))
+ SpawnBlood(hitInfo.point + (hitInfo.normal * Decal.SurfaceDistance), -hitInfo.normal);
+ }
+
+ ///
+ /// Spawns a blood decal.
///
/// The position of the blood decal.
- /// The direction of the blood decal.
- [Obsolete("Use PlaceBlood(this Player, Vector3, Vector3, RoleTypeId, int) instead.")]
- public static void PlaceBlood(Vector3 position, Vector3 direction) => _ = 0;
+ /// The raycast origin used to determine the decal's orientation.
+ /// if the blood decal was successfully spawned; otherwise, .
+ public static bool SpawnBlood(Vector3 position, Vector3 sourcePosition) => SpawnDecal(position, sourcePosition, DecalPoolType.Blood, FirearmType.Com15);
+
+ ///
+ /// Spawns a decal.
+ ///
+ /// The position of the decal.
+ /// The raycast origin used to determine the decal's orientation.
+ /// The .
+ /// The to use.
+ /// if the decal was successfully spawned; otherwise, .
+ public static bool SpawnDecal(Vector3 position, Vector3 sourcePosition, DecalPoolType decalType, FirearmType firearmType = FirearmType.Com15)
+ {
+ if (!InventoryItemLoader.TryGetItem(firearmType.GetItemType(), out ItemBase itemBase))
+ {
+ Log.Error($"Failed to spawn decal: Could not find a Firearm for {firearmType}.");
+ return false;
+ }
+
+ Firearm firearm = Item.Get(itemBase);
+ if (firearm == null)
+ {
+ Log.Error($"Failed to spawn decal: Could not find a Firearm for {firearmType}.");
+ return false;
+ }
+
+ ImpactEffectsModule impactEffectsModule = firearm.ImpactEffectsModule;
+ if (impactEffectsModule == null)
+ {
+ Log.Error($"Failed to spawn decal: Could not find an ImpactEffectsModule for {firearmType}.");
+ return false;
+ }
+
+ impactEffectsModule.SendRpc(writer =>
+ {
+ writer.WriteSubheader(ImpactEffectsModule.RpcType.ImpactDecal);
+ writer.WriteByte((byte)decalType);
+ writer.WriteRelativePosition(new RelativePosition(position));
+ writer.WriteRelativePosition(new RelativePosition(sourcePosition));
+ });
+
+ return true;
+ }
///
/// Gets all the near cameras.
diff --git a/EXILED/Exiled.API/Features/Player.cs b/EXILED/Exiled.API/Features/Player.cs
index 936a82c4c..ef43a01eb 100644
--- a/EXILED/Exiled.API/Features/Player.cs
+++ b/EXILED/Exiled.API/Features/Player.cs
@@ -14,6 +14,8 @@ namespace Exiled.API.Features
using System.Reflection;
using System.Runtime.CompilerServices;
+ using AudioPooling;
+
using Core;
using CustomPlayerEffects;
@@ -49,6 +51,7 @@ namespace Exiled.API.Features
using InventorySystem.Items;
using InventorySystem.Items.Armor;
using InventorySystem.Items.Firearms.Attachments;
+ using InventorySystem.Items.Firearms.BasicMessages;
using InventorySystem.Items.Firearms.Modules;
using InventorySystem.Items.Firearms.ShotEvents;
using InventorySystem.Items.Usables;
@@ -3855,19 +3858,28 @@ public void Reconnect(ushort newPort = 0, float delay = 5, bool reconnect = true
Connection.Send(new RoundRestartMessage(roundRestartType, delay, newPort, reconnect, false));
}
- ///
- [Obsolete("Use PlayGunSound(Player, Vector3, FirearmType, byte, byte) instead.")]
- public void PlayGunSound(ItemType type, byte volume, byte audioClipId = 0)
- => PlayGunSound(type.GetFirearmType(), volume, audioClipId);
-
- ///
- public void PlayGunSound(FirearmType itemType, float pitch = 1, int clipIndex = 0) =>
- this.PlayGunSound(Position, itemType, pitch, clipIndex);
+ ///
+ [Obsolete("Use Player::PlayGunSound(FirearmType, int, Vector3, MixerChannel, float?, float?) instead of this.")]
+ public void PlayGunSound(FirearmType itemType, float pitch = 1, int clipIndex = 0) => this.PlayGunSound(itemType, clipIndex, Position, pitch: pitch);
///
- [Obsolete("Use PlaceBlood(this Player, Vector3, Vector3, RoleTypeId, int) instead.")]
public void PlaceBlood(Vector3 direction) => Map.PlaceBlood(Position, direction);
+ ///
+ /// Sends a damage indicator to player.
+ ///
+ /// The amount of damage dealt. Controls the size of the damage indicator.
+ /// The world position the damage originated from.
+ /// If true, spectators watching this player will also see the indicator.
+ public void SendHitEffect(float dmgDealt, Vector3 position, bool sendSpectatorsToo = true)
+ {
+ DamageIndicatorMessage damageIndicatorMessage = new(dmgDealt, position);
+ if (!sendSpectatorsToo)
+ Connection.Send(damageIndicatorMessage);
+ else
+ damageIndicatorMessage.SendToSpectatorsOf(ReferenceHub, true);
+ }
+
///
public IEnumerable GetNearCameras(float toleration = 15f) => Map.GetNearCameras(Position, toleration);
@@ -3881,8 +3893,7 @@ public void PlayGunSound(FirearmType itemType, float pitch = 1, int clipIndex =
/// Teleports the player to the given object, with no offset.
///
/// The object to teleport to.
- public void Teleport(object obj)
- => Teleport(obj, Vector3.zero);
+ public void Teleport(object obj) => Teleport(obj, Vector3.zero);
///
/// Teleports the player to the given object, offset by the defined offset value.