using System.Diagnostics;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using Unity.NetCode;
namespace Unity.MegaCity.Gameplay
{
///
/// System to handle input for the thin client
///
[UpdateInGroup(typeof(GhostInputSystemGroup))]
[WorldSystemFilter(WorldSystemFilterFlags.ThinClientSimulation)]
public partial struct MegaCityThinInputSystem : ISystem
{
private NativeReference m_Rand;
public void OnCreate(ref SystemState state)
{
state.RequireForUpdate();
state.RequireForUpdate();
state.RequireForUpdate();
m_Rand = new NativeReference(Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
m_Rand.Value = Random.CreateFromIndex((uint) Stopwatch.GetTimestamp());
}
[BurstCompile]
public void OnDestroy(ref SystemState state)
{
m_Rand.Dispose();
}
[BurstCompile]
public void OnUpdate(ref SystemState state)
{
if (!SystemAPI.TryGetSingletonRW(out var commandTargetRw))
return;
// Ensure AI has input entity:
if (commandTargetRw.ValueRO.targetEntity == Entity.Null || !state.EntityManager.HasComponent(commandTargetRw.ValueRO.targetEntity))
{
var inputEntity = state.EntityManager.CreateEntity();
commandTargetRw.ValueRW.targetEntity = inputEntity;
var connectionId = SystemAPI.GetSingleton().Value;
state.EntityManager.SetName(inputEntity, $"{nameof(MegaCityThinInputSystem)}-RandInput");
state.EntityManager.AddComponent(inputEntity);
// NOTE: The buffer type might not be recognized in your IDE but it will be generated and Unity will recognize it.
// TODO : verify this buffer
//state.EntityManager.AddBuffer(inputEntity);
state.EntityManager.AddComponentData(inputEntity, new GhostOwner { NetworkId = connectionId });
return; // Return as the EntityManager has now had a structural change, invalidating `commandTargetRw`.
}
// Recalculate AI action every x ticks:
var networkTime = SystemAPI.GetSingleton();
if (networkTime.ServerTick.TickIndexForValidTick % 30 == 0)
{
var input = state.EntityManager.GetComponentData(commandTargetRw.ValueRO.targetEntity);
var rand = m_Rand.Value;
// Movement:
input.ControlDirection = (rand.NextFloat3() * 2) - new float3(1);
input.GamepadDirection = (rand.NextFloat3() * 2) - new float3(1);
// Drive:
input.Acceleration = rand.NextInt() < 0.8f ? 1 : 0;
input.Brake = rand.NextInt() < 0.1f ? 1 : 0;
// Roll:
input.LeftRoll = rand.NextInt() < 0.1f ? 1 : 0;
input.RightRoll = input.LeftRoll <= 0f && rand.NextInt() < 0.1f ? 1 : 0;
// Shooting:
input.Shoot = rand.NextInt() < 0.3f;
m_Rand.Value = rand;
state.EntityManager.SetComponentData(commandTargetRw.ValueRO.targetEntity, input);
}
}
}
}