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);
}
}
}