using System; using Unity.Burst; using Unity.Collections; using Unity.Entities; using Unity.Jobs; using Unity.NetCode; using Unity.NetCode.Extensions; using static Unity.Entities.SystemAPI; using Random = Unity.Mathematics.Random; namespace Unity.MegaCity.Gameplay { /// /// System to set the player info. /// [BurstCompile] [WorldSystemFilter(WorldSystemFilterFlags.ServerSimulation)] public partial struct SetPlayerInfoSystem : ISystem { #region Jobs [BurstCompile] private partial struct FindAvailableNameJob : IJob { public NativeArray Names; public NativeList UsedNames; public Random Random; [BurstCompile] public void Execute() { var availablePlayerNames = GetAvailableNames(); if (availablePlayerNames.Length == 0) { UsedNames.Clear(); availablePlayerNames = GetAvailableNames(); } // Choose a random player name from the list of available player names var randomIndex = Random.NextInt(0, availablePlayerNames.Length); var botName = availablePlayerNames[randomIndex]; UsedNames.Add(botName); } private NativeList GetAvailableNames() { var availablePlayerNames = new NativeList(Allocator.TempJob); // Get a list of player names that have not been used foreach (var name in Names) { if (!UsedNames.Contains(name.Name)) { availablePlayerNames.Add(name.Name); } } return availablePlayerNames; } } #endregion private NativeList m_UsedNames; private Random m_Random; private EntityQuery m_ConnectedPlayers; public void OnCreate(ref SystemState state) { state.RequireForUpdate(); state.RequireForUpdate(); m_UsedNames = new NativeList(Allocator.Persistent); var seed = DateTime.Now.Ticks / (DateTime.Now.Second + DateTime.Now.Day); m_Random = new Random((uint)seed); m_ConnectedPlayers = state.GetEntityQuery(ComponentType.ReadOnly()); state.RequireForUpdate(); state.RequireForUpdate(); UnityEngine.Debug.Log("SetPlayerInfoSystem has been loaded and initialized!"); } //TODO : Optimize for DOTS? public void OnUpdate(ref SystemState state) { var playersConnected = GetSingletonBuffer(); var commandBuffer = new EntityCommandBuffer(Allocator.TempJob); var names = GetSingletonBuffer().ToNativeArray(Allocator.TempJob); foreach (var (info, request, requestEntity) in Query().WithEntityAccess()) { var entityNetwork = request.SourceConnection; var networkId = GetComponent(entityNetwork); foreach (var (ghostOwner, entity) in Query>() .WithEntityAccess()) { if (ghostOwner.ValueRO.NetworkId == networkId.Value) { var findANewNameJob = new FindAvailableNameJob { Names = names, UsedNames = m_UsedNames, Random = m_Random }; state.Dependency = findANewNameJob.Schedule(state.Dependency); state.Dependency.Complete(); // If the requester is not a client should use one from the bank of names. var name = info.IsClient ? info.Name : m_UsedNames[m_UsedNames.Length - 1]; var playerID = info.PlayerId; commandBuffer.SetComponent(entity, new PlayerName { Name = name }); commandBuffer.AddComponent(entity, new MultiversePlayerID { PlayerId = playerID }); playersConnected.Add(new PlayerConnectedElement { Name = name, PlayerId = playerID, Value = entity }); UnityEngine.Debug.Log($"Client: {name} ({playerID}) has joined the game! (Thin = {!info.IsClient})\nConnected Players: {m_ConnectedPlayers.CalculateEntityCount()}"); // If any players are connected, cancel the auto shutdown task MultiverseSDKWrapper.Instance.CancelShutdown(); break; } } commandBuffer.DestroyEntity(requestEntity); } commandBuffer.Playback(state.EntityManager); } } }