protected async void Spawn() { var characterSessions = await this.characterManager.ActiveCharacterSessions(); lock (SpawnLock) { var vehiclesToSpawn = this.ActiveVehicles.Where(v => v.Handle == null); foreach (var vehicle in vehiclesToSpawn) { var characterToSpawn = characterSessions .Where(c => c.IsConnected) .Select(s => new { Char = s.Character, Dist = Vector3.Distance(vehicle.Position.ToVector3().ToCitVector3(), s.Character.Position.ToVector3().ToCitVector3()) }) .Where(c => c.Dist < this.Configuration.DespawnDistance) .OrderBy(c => c.Dist) .FirstOrDefault(); if (characterToSpawn == null) { continue; } var characterSession = characterSessions.FirstOrDefault(s => s.Character.Id == characterToSpawn.Char.Id); if (characterSession == null) { continue; } // TODO: Await client response to prevent races. this.comms.Event(VehicleEvents.Spawn).ToClient(this.clientList.Clients.First(c => c.Handle == characterSession.Session.Handle)).Emit(vehicle); } } }
private async void OnClientDisconnected(ICommunicationMessage e, IClient client, Session session) { var characterSessions = await this.characterManager.ActiveCharacterSessions(); foreach (var vehicle in this.ActiveVehicles.Where(v => v.Handle != null).ToList()) { var nearestCharacter = characterSessions .Where(c => c.IsConnected && c.SessionId != session.Id) .Select(s => new { CharSession = s, Dist = Vector3.Distance(vehicle.Position.ToVector3().ToCitVector3(), s.Character.Position.ToVector3().ToCitVector3()) }) .OrderBy(c => c.Dist) .FirstOrDefault(); if (nearestCharacter == null) { this.Destroy(null, vehicle.NetId ?? 0); } else { this.Transfer(null, vehicle.Id, nearestCharacter.CharSession.Session.UserId); } } }
internal void Send(VoiceClient voiceClient, bool isSending) { if (!this.TryGetMember(voiceClient, out RadioChannelMember radioChannelMember)) { return; } bool stateChanged = radioChannelMember.IsSending != isSending; radioChannelMember.IsSending = isSending; RadioChannelMember[] channelMembers = this.Members; RadioChannelMember[] onSpeaker = channelMembers.Where(m => m.IsSpeakerEnabled && m.VoiceClient != voiceClient).ToArray(); CitizenFX.Core.Vector3 position = voiceClient.Player.GetPosition(); if (onSpeaker.Length > 0) { string[] channelMemberNames = onSpeaker.Select(m => m.VoiceClient.TeamSpeakName).ToArray(); foreach (VoiceClient remoteClient in VoiceManager.Instance.VoiceClients) { remoteClient.Player.TriggerEvent(Event.SaltyChat_IsSendingRelayed, voiceClient.Player.Handle, voiceClient.TeamSpeakName, this.Name, isSending, stateChanged, position, this.IsMember(remoteClient), channelMemberNames); } } else { foreach (RadioChannelMember member in channelMembers) { member.VoiceClient.Player.TriggerEvent(Event.SaltyChat_IsSending, voiceClient.Player.Handle, voiceClient.TeamSpeakName, this.Name, isSending, stateChanged, position); } } }
protected void OnClientDisconnect(ClientSessionEventArgs e) { var characterSessions = this.characterManager.ActiveCharacterSessions; foreach (var vehicle in this.ActiveVehicles.Where(v => v.Handle != null).ToList()) { var nearestCharacter = characterSessions .Where(c => c.IsConnected && c.SessionId != e.Session.Id) .Select(s => new { CharSession = s, Dist = Vector3.Distance(vehicle.Position.ToVector3(), s.Character.Position.ToVector3()) }) .OrderBy(c => c.Dist) .FirstOrDefault(); if (nearestCharacter == null) { this.Destroy(null, vehicle.NetId ?? 0); } else { this.Transfer(null, vehicle.Id, nearestCharacter.CharSession.Session.UserId); } } }
/// <summary> /// Used for <see cref="Command.PlayerStateUpdate"/> /// </summary> /// <param name="name"></param> /// <param name="position"></param> /// <param name="voiceRange"></param> /// <param name="isAlive"></param> public PlayerState(string name, CitizenFX.Core.Vector3 position, float voiceRange, bool isAlive) { this.Name = name; this.Position = position; this.VoiceRange = voiceRange; this.IsAlive = isAlive; }
/// <summary> /// Used for <see cref="Command.PlayerStateUpdate"/> /// </summary> /// <param name="name"></param> /// <param name="position"></param> /// <param name="voiceRange"></param> /// <param name="isAlive"></param> /// <param name="distanceCulled"></param> public PlayerState(string name, CitizenFX.Core.Vector3 position, float voiceRange, bool isAlive, bool distanceCulled = false) { this.Name = name; this.Position = position; this.VoiceRange = voiceRange; this.IsAlive = isAlive; this.DistanceCulled = distanceCulled; }
/// <summary> /// Used for <see cref="Command.PlayerStateUpdate"/> /// </summary> /// <param name="name"></param> /// <param name="position"></param> /// <param name="voiceRange"></param> /// <param name="isAlive"></param> /// <param name="distanceCulled"></param> /// <param name="muffleIntensity"></param> public PlayerState(string name, CitizenFX.Core.Vector3 position, float voiceRange, bool isAlive, bool distanceCulled = false, int?muffleIntensity = null) { this.Name = name; this.Position = new Vector3(position.X, position.Y, position.Z); this.VoiceRange = voiceRange; this.IsAlive = isAlive; this.MuffleIntensity = muffleIntensity; this.DistanceCulled = distanceCulled; }
/// <summary> /// Used for <see cref="Command.PlayerStateUpdate"/> /// </summary> /// <param name="name"></param> /// <param name="position"></param> /// <param name="voiceRange"></param> /// <param name="isAlive"></param> /// <param name="distanceCulled"></param> /// <param name="noLos"></param> public PlayerState(string name, CitizenFX.Core.Vector3 position, float voiceRange, bool isAlive, bool distanceCulled = false, bool noLos = false) { this.Name = name; this.Position = new Vector3(position.X, position.Y, position.Z); this.VoiceRange = voiceRange; this.IsAlive = isAlive; this.NoLoS = noLos; this.DistanceCulled = distanceCulled; }
public SelfState(CitizenFX.Core.Vector3 position, float rotation, bool echo = false) { this.Position = new Vector3(position.X, position.Y, position.Z); this.Rotation = rotation; this.IsAlive = true; if (echo) { this.Echo = new EchoEffect(); } }
public SelfState(CitizenFX.Core.Vector3 position, float rotation, float voiceRange, bool isAlive, bool echo = false) { this.Position = new TSVector(position.X, position.Y, position.Z); this.Rotation = rotation; this.VoiceRange = voiceRange; this.IsAlive = isAlive; if (echo) { this.Echo = new EchoEffect(); } }
protected void SpawnForPlayer(CharacterSessionEventArgs e) { lock (SpawnLock) { var vehiclesToSpawn = this.ActiveVehicles .Where(v => v.Handle == null && Vector3.Distance(v.Position.ToVector3().ToCitVector3(), e.CharacterSession.Character.Position.ToVector3().ToCitVector3()) < this.Configuration.DespawnDistance ); foreach (var vehicle in vehiclesToSpawn) { // TODO: Await client response to prevent races. this.comms.Event(VehicleEvents.Spawn).ToClient(this.clientList.Clients.First(c => c.Handle == e.CharacterSession.Session.Handle)).Emit(vehicle); } } }
/// <summary> /// Used for <see cref="Command.PlayerStateUpdate"/> with volume override /// </summary> /// <param name="name"></param> /// <param name="position"></param> /// <param name="voiceRange"></param> /// <param name="isAlive"></param> /// <param name="volumeOverride">Overrides the volume (phone, radio and proximity) - from 0 (0%) to 1.6 (160%)</param> public PlayerState(string name, CitizenFX.Core.Vector3 position, float voiceRange, bool isAlive, float volumeOverride) { this.Name = name; this.Position = new Vector3(position.X, position.Y, position.Z); this.VoiceRange = voiceRange; this.IsAlive = isAlive; if (volumeOverride > 1.6f) { this.VolumeOverride = 1.6f; } else if (volumeOverride < 0f) { this.VolumeOverride = 0f; } else { this.VolumeOverride = volumeOverride; } }
internal void RemoveMember(VoiceClient voiceClient) { lock (this._memberLock) { RadioChannelMember member = this._members.FirstOrDefault(m => m.VoiceClient == voiceClient); if (member != null) { if (member.IsSending) { CitizenFX.Core.Vector3 position = member.VoiceClient.Player.GetPosition(); if (member.VoiceClient.IsRadioSpeakerEnabled) { foreach (VoiceClient client in VoiceManager.Instance.VoiceClients) { client.TriggerEvent(Event.SaltyChat_IsSendingRelayed, voiceClient.Player.Handle, voiceClient.TeamSpeakName, this.Name, false, true, position, false, new string[0]); } } else { foreach (RadioChannelMember channelMember in this._members) { channelMember.VoiceClient.TriggerEvent(Event.SaltyChat_IsSending, voiceClient.Player.Handle, voiceClient.TeamSpeakName, this.Name, false, true, position); } } } this._members.Remove(member); foreach (RadioChannelMember channelMember in this._members.Where(m => m.IsSending)) { voiceClient.TriggerEvent(Event.SaltyChat_IsSending, channelMember.VoiceClient.Player.Handle, channelMember.VoiceClient.TeamSpeakName, this.Name, false, false, channelMember.VoiceClient.Player.GetPosition()); } voiceClient.TriggerEvent(Event.SaltyChat_SetRadioChannel, null, member.IsPrimary); this.BroadcastEvent(Event.SaltyChat_RadioChannelMemberUpdated, this.Name, this.Members.Select(m => m.VoiceClient.TeamSpeakName)); } } }
protected void Update() { var activeVehicles = this.ActiveVehicles.Where(v => v.Handle != null).ToList(); var characterSessions = this.characterManager.ActiveCharacterSessions; foreach (var vehicle in activeVehicles) { var nearestCharacter = characterSessions .Where(c => c.IsConnected) .Select(s => new { CharSession = s, Dist = Vector3.Distance(vehicle.Position.ToVector3(), s.Character.Position.ToVector3()) }) .OrderBy(c => c.Dist) .FirstOrDefault(); if (nearestCharacter == null) { continue; } if (nearestCharacter.Dist > this.Configuration.DespawnDistance) { Despawn(vehicle.NetId ?? 0, nearestCharacter.CharSession.Session.Handle); } else if (nearestCharacter.CharSession.Session.UserId != vehicle.TrackingUserId) { var trackingUser = characterSessions.FirstOrDefault(s => s.Session.UserId == vehicle.TrackingUserId); if (trackingUser == null) { continue; } this.Rpc.Event(VehicleEvents.Transfer) .Target(this.clientList.Clients.First(c => c.Handle == trackingUser.Session.Handle)) .Trigger(vehicle.Id, nearestCharacter.CharSession.Session.UserId); } } }
internal void SetSpeaker(VoiceClient voiceClient, bool isEnabled) { if (!this.TryGetMember(voiceClient, out RadioChannelMember radioChannelMember) || radioChannelMember.IsSpeakerEnabled == isEnabled) { return; } radioChannelMember.IsSpeakerEnabled = isEnabled; RadioChannelMember[] channelMembers = this.Members; IEnumerable <RadioChannelMember> sendingMembers = channelMembers.Where(m => m.IsSending); if (sendingMembers.Count() == 0) { return; } if (isEnabled || channelMembers.Any(m => m.IsSpeakerEnabled)) { foreach (RadioChannelMember sendingMember in sendingMembers) { this.Send(sendingMember.VoiceClient, true); } } else { foreach (RadioChannelMember sendingMember in sendingMembers) { CitizenFX.Core.Vector3 position = sendingMember.VoiceClient.Player.GetPosition(); foreach (VoiceClient remoteClient in VoiceManager.Instance.VoiceClients.Where(v => !channelMembers.Any(m => m.VoiceClient == v))) { remoteClient.TriggerEvent(Event.SaltyChat_IsSendingRelayed, sendingMember.VoiceClient.Player.Handle, sendingMember.VoiceClient.TeamSpeakName, this.Name, false, false, position, false, new string[0]); } } } }
public static Vector3 ToVector3(this CitizenFX.Core.Vector3 vector3) => new Vector3(vector3.X, vector3.Y, vector3.Z);
public VoiceClient(int serverId, string teamSpeakName, float voiceRange, bool isAlive, CitizenFX.Core.Vector3 lastPosition) { this.ServerId = serverId; this.TeamSpeakName = teamSpeakName; this.VoiceRange = voiceRange; this.IsAlive = isAlive; this.LastPosition = lastPosition; }
/// <summary> /// Used for <see cref="Command.SelfStateUpdate"/> /// </summary> /// <param name="position"></param> /// <param name="rotation"></param> public PlayerState(CitizenFX.Core.Vector3 position, float rotation) { this.Position = position; this.Rotation = rotation; }
/// <summary> /// Used for <see cref="Command.SelfStateUpdate"/> /// </summary> /// <param name="position"></param> /// <param name="rotation"></param> public PlayerState(CitizenFX.Core.Vector3 position, float rotation) { this.Position = new Vector3(position.X, position.Y, position.Z); this.Rotation = rotation; }