Hello Community,
can anyone help me with this error ?
im stuck in this error from 5 hours and i feel like it’s a bug.
using System.Net;
using UnityEngine;
using Unity.Networking.Transport;
using Unity.Collections;
using Unity.Jobs;
using CWBR.ClientAndServer.Components;
using Unity.Entities;
using System;
using UdpCNetworkDriver = Unity.Networking.Transport.GenericNetworkDriver<Unity.Networking.Transport.IPv4UDPSocket, Unity.Networking.Transport.DefaultPipelineStageCollection>;
using CWBR.ClientAndServer.Enums;
struct HandleConnectionsRequestsJob : IJob
{
public UdpCNetworkDriver driver;
public NativeList<NetworkConnection> unidentifiedConnections;
public NativeArray<NetworkConnection> m_Connections;
public BufferFromEntity<OutgoingReliableMessages> outgoingReliableMessagesFromEntity;
public BufferFromEntity<OutgoingUnreliableMessages> outgoingUnreliableMessages;
[ReadOnly] public NativeArray<Entity> playersEntities;
[ReadOnly] public EntityCommandBuffer commandBuffer;
public void Execute()
{
// CleanUpConnections !!!
for (int i = 0; i < unidentifiedConnections.Length; i++)
{
if (!unidentifiedConnections[i].IsCreated)
{
unidentifiedConnections.RemoveAtSwapBack(i);
--i;
}
}
for (int i = 0; i < m_Connections.Length; i++)
{
if (!m_Connections[i].IsCreated )
{
if (m_Connections[i] != default)
{
Debug.Log($"Connection index : {i} is Cleaned");
//TODO: Remove Connected and Add Disconnected to the Right Entity
m_Connections[i] = default;
commandBuffer.RemoveComponent<ConnectedPlayer>(playersEntities[i]);
commandBuffer.AddComponent<DisconnectedPlayer>(playersEntities[i]);
outgoingReliableMessagesFromEntity[playersEntities[i]].Clear();
outgoingUnreliableMessages[playersEntities[i]].Clear();
}
}
}
// Accept New Connections ( added as unidentified Connection )
NetworkConnection c;
while ((c = driver.Accept()) != default)
{
unidentifiedConnections.Add(c);
Debug.Log("Accepted a connection");
}
}
}
/// <summary>
/// Handle Identification Messaged from
/// </summary>
struct HandleIdentificationsJob : IJob
{
[ReadOnly] public UdpCNetworkDriver driver;
[ReadOnly] public EntityCommandBuffer commandBuffer;
[ReadOnly] public ComponentDataFromEntity<DisconnectedPlayer> disconnectedPlayerLookup;
[ReadOnly] public NativeArray<Entity> playersEntities;
[ReadOnly] public NativeArray<uint> players_SecretKey;
[ReadOnly] public NetworkPipeline reliablePipeline;
public NativeList<NetworkConnection> unidentifiedConnections;
public NativeArray<NetworkConnection> m_Connections;
public void Execute()
{
// check for Identification Messages
for (var i = 0; i < unidentifiedConnections.Length; i++)
{
// Remove if Connection has been Canceled before the Identification
if (!unidentifiedConnections[i].IsCreated)
{
Debug.Log("TODO: Handle Disconnected Players From ReceiveStreamsJob");
unidentifiedConnections.RemoveAtSwapBack(i);
--i;
continue;
}
NetworkEvent.Type cmd;
while ((cmd = driver.PopEventForConnection(unidentifiedConnections[i], out var stream)) != NetworkEvent.Type.Empty)
{
// Data Received
if (cmd == NetworkEvent.Type.Data)
{
// This Context should be used for All Operations concerning this Stream
var readerCtx = default(DataStreamReader.Context);
var messageId = stream.ReadByte(ref readerCtx);
// TODO: Implement a more Elegant way to read Messages
if (messageId == MessageBufferIndexes.IdentificationId)
{
var secretKey = stream.ReadUInt(ref readerCtx);
// Player Identified
int playerIndex = NativeArrayExtensions.IndexOf(players_SecretKey, secretKey);
if (playerIndex >= 0)
{
// Set Connection in Connections Array
m_Connections[playerIndex] = unidentifiedConnections[i];
// Add ConnectedPlayer Component to the Player Entity
commandBuffer.AddComponent(playersEntities[playerIndex], new ConnectedPlayer { Id = (byte)playerIndex });
// Check if This player entity is containing the DisconnectedPlayer Component
if (disconnectedPlayerLookup.Exists(playersEntities[playerIndex]))
commandBuffer.RemoveComponent<DisconnectedPlayer>(playersEntities[playerIndex]);
// Notify Player that his identified
using (var writer = new DataStreamWriter(1, Allocator.Temp))
{
writer.Write(MessageBufferIndexes.IdentificationSuccess);
driver.Send(reliablePipeline, m_Connections[playerIndex], writer);
Debug.Log("Player Successfully Identified");
}
}
// Player Failed his identification
else
{
Debug.Log("Player Failed the Identification");
//TODO: Handle Fake Identification
// Close this Connection
// unidentifiedConnections[i].Close(driver);
// Notify Player that he Failed the identification
using (var writer = new DataStreamWriter(1, Allocator.Temp))
{
writer.Write(MessageBufferIndexes.IdentificationFailed);
driver.Send(reliablePipeline, m_Connections[playerIndex], writer);
Debug.Log("Player Successfully Identified");
}
}
// Remove this Connection from the Unidentified Connections List
unidentifiedConnections.RemoveAtSwapBack(i);
--i;
break;
}
else
{
// TODO: Handle Messages From UnIdentified Players
Debug.Log("Unexpected Message from UnIdentified Player");
}
}
// in Case the Client Request For disconnection before the Identification
else if (cmd == NetworkEvent.Type.Disconnect)
{
unidentifiedConnections.RemoveAtSwapBack(i);
--i;
break;
}
}// While end!
}// for end!
}
}
/// <summary>
/// Send Streams to Clients
/// </summary>
//[BurstCompile] // Disabled only when testing
[RequireComponentTag(typeof(OutgoingUnreliableMessages))]
public struct SendUnreliableMessagesJob : IJobForEachWithEntity<ConnectedPlayer>
{
public UdpCNetworkDriver.Concurrent driver;
[ReadOnly] public NetworkPipeline unreliablePipeline;
[NativeDisableParallelForRestriction] public BufferFromEntity<OutgoingUnreliableMessages> outGoingBufferFromEntity;
[ReadOnly] [NativeDisableParallelForRestriction] public NativeArray<NetworkConnection> connections;
public void Execute(Entity entity, int index, ref ConnectedPlayer connectionId)
{
var connection = connections[connectionId.Id];
if (!connection.IsCreated)
{
Debug.Log("connection is not Created");
return;
}
var ouGoingDynamicBuffer = outGoingBufferFromEntity[entity];
if (ouGoingDynamicBuffer.Length == 0)
{
Debug.Log("Empty OutgoingUnreliableMessages buffer");
return;
}
using(var tmp = new DataStreamWriter(ouGoingDynamicBuffer.Length, Allocator.Temp))
{
unsafe
{
tmp.WriteBytes((byte*)ouGoingDynamicBuffer.GetUnsafePtr(), ouGoingDynamicBuffer.Length);
}
driver.Send(unreliablePipeline, connection, tmp);
ouGoingDynamicBuffer.Clear();
}
/*
IntPtr pointer;
unsafe
{
pointer = (IntPtr) NativeSliceUnsafeUtility.GetUnsafeReadOnlyPtr(ouGoingBufferFromEntity[entity].AsNativeArray().Slice().SliceConvert<byte>());
}
driver.Send(unreliablePipeline, connection, pointer, ouGoingDynamicBuffer.Capacity);
ouGoingDynamicBuffer.Clear();*/
}
}
/// <summary>
/// Send RPCs to Clients
/// </summary>
//[BurstCompile] // Disabled only when testing
[RequireComponentTag(typeof(OutgoingReliableMessages))]
public struct SendReliableMessagesJob : IJobForEachWithEntity<ConnectedPlayer>
{
public UdpCNetworkDriver.Concurrent driver;
[NativeDisableParallelForRestriction] public BufferFromEntity<OutgoingReliableMessages> outGoingBufferFromEntity;
[ReadOnly] public NetworkPipeline ReliablePipeline;
[ReadOnly] [NativeDisableParallelForRestriction] public NativeArray<NetworkConnection> connections;
public void Execute(Entity entity, int index, ref ConnectedPlayer connectionId)
{
var connection = connections[connectionId.Id];
if (!connection.IsCreated)
{
Debug.Log("SendReliableMessagesJob connection is Unexpectedly disconnected");
return;
}
var outGoingDynamicBuffer = outGoingBufferFromEntity[entity];
if (outGoingDynamicBuffer.Length == 0)
{
// Debug.Log("Empty OutgoingUnreliableMessages buffer");
return;
}
using (var tmp = new DataStreamWriter(outGoingDynamicBuffer.Length, Allocator.Temp))
{
unsafe
{
tmp.WriteBytes((byte*)outGoingDynamicBuffer.GetUnsafePtr(), outGoingDynamicBuffer.Length);
}
driver.Send(ReliablePipeline, connection, tmp);
outGoingDynamicBuffer.Clear();
}
}
}
/// <summary>
/// Send RPCs to Clients
/// </summary>
//[BurstCompile] // Disabled only when testing
struct ReceiveMessagesPacketsJob : IJobForEachWithEntity<ConnectedPlayer>
{
public UdpCNetworkDriver.Concurrent driver;
[ReadOnly] [NativeDisableParallelForRestriction] public NativeArray<NetworkConnection> connections;
public void Execute(Entity entity, int index, ref ConnectedPlayer connectedPlayer)
{
if (!connections[connectedPlayer.Id].IsCreated)
{
Debug.Log("TODO: Handle Disconnected Players From ReceiveStreamsJob");
return;
}
NetworkEvent.Type cmd;
while ((cmd = driver.PopEventForConnection(connections[connectedPlayer.Id], out var stream)) != NetworkEvent.Type.Empty)
{
// Data Received
if (cmd == NetworkEvent.Type.Data)
{
// This Context should be used for All Operations concerning this Stream
var readerCtx = default(DataStreamReader.Context);
var messageId = stream.ReadByte(ref readerCtx);
// TODO: Implement an Elegant way to read Messages
Debug.Log($"Message Received From playerId {connectedPlayer.Id} with MessageId : {messageId}");
/*
uint number = stream.ReadUInt(ref readerCtx);
Debug.Log("Got " + number + " from the Client adding + 2 to it.");
number += 2;
driver.Send();
using (var writer = new DataStreamWriter(4, Allocator.Temp))
{
writer.Write(number);
}*/
}
else if (cmd == NetworkEvent.Type.Disconnect)
{
Debug.Log("Client disconnected from server");
//connections[connectedPlayer.Id] = default(NetworkConnection);
}
}
}
}
/// <summary>
/// Manage Connection Requests Comming From Clients.
/// Send/Receive RPCs, Streams From Server to Clients.
/// </summary>
public class ServerManagerSystem : JobComponentSystem
{
public NativeList<NetworkConnection> unidentifiedConnections;
public NativeArray<uint> players_SecretKey; // these kays are generated From Nakama
public NativeArray<NetworkConnection> m_Connections; // this array is holding all Players EndPoints (used to Identify Which Connection relies on which player + Sending Messages)
public NativeArray<Entity> playersEntities;
public BeginInitializationEntityCommandBufferSystem beginInitializationEntityCommandBufferSystem;
public UdpCNetworkDriver m_Driver;
public UdpCNetworkDriver.Concurrent m_ConcurentDriver;
private NetworkPipeline unreliablePipeline;
private NetworkPipeline reliablePipeline;
string IP = "127.0.0.1";
ushort Port = 9000;
protected override void OnCreate()
{
Debug.Log("=========== Server Started! ==============");
unidentifiedConnections = new NativeList<NetworkConnection>(32, Allocator.Persistent);
m_Connections = new NativeArray<NetworkConnection>(32, Allocator.Persistent);
players_SecretKey = new NativeArray<uint>(32, Allocator.Persistent);
playersEntities = new NativeArray<Entity>(32, Allocator.Persistent);
//Test
m_Connections[0] = default;
players_SecretKey[0] = 10101;
playersEntities[0] = EntityManager.CreateEntity();
var rnd = new Unity.Mathematics.Random((uint)DateTime.Now.Millisecond);
for (var i=1; i < 32; i++)
{
m_Connections[i] = default;
players_SecretKey[i] = rnd.NextUInt();
playersEntities[i] = EntityManager.CreateEntity();
}
//EndTest
// m_Driver = new UdpNetworkDriver(new SimulatorUtility.Parameters {MaxPacketSize = packetSize, MaxPacketCount = 30, PacketDelayMs = 25, PacketDropPercentage = 10 /*PacketDropInterval = 100*/}, new ReliableUtility.Parameters { WindowSize = 32 });
m_Driver = new UdpCNetworkDriver(new INetworkParameter[0]);
unreliablePipeline = m_Driver.CreatePipeline(typeof(UnreliableSequencedPipelineStage), typeof(SimulatorPipelineStage));
//unreliablePipeline = m_Driver.CreatePipeline(typeof(UnreliableSequencedPipelineStage));
reliablePipeline = m_Driver.CreatePipeline(typeof(ReliableSequencedPipelineStage), typeof(SimulatorPipelineStage));
//reliablePipeline = m_Driver.CreatePipeline(typeof(ReliableSequencedPipelineStage));
//TODO: The Server should start Listening after Getting the Port from Console
StartListening(IP , Port);
m_ConcurentDriver = m_Driver.ToConcurrent();
beginInitializationEntityCommandBufferSystem = World.Active.GetOrCreateSystem<BeginInitializationEntityCommandBufferSystem>();
}
/// <summary>
/// This Function should be used when the server is ready to accept Players
/// </summary>
/// <param name="IP"></param>
/// <param name="Port"></param>
public void StartListening(string IP, ushort Port)
{
if (m_Driver.Bind(NetworkEndPoint.Parse(IP, Port)) != 0)
Debug.Log($"Failed to bind to port {Port}");
else
{
m_Driver.Listen();
Debug.Log("Server Listening!");
}
}
protected override void OnDestroy()
{
// Make sure we run our jobs to completion before exiting.
unidentifiedConnections.Dispose();
players_SecretKey.Dispose();
m_Connections.Dispose();
playersEntities.Dispose();
m_Driver.Dispose();
}
protected override JobHandle OnUpdate(JobHandle inputDeps)
{
inputDeps = m_Driver.ScheduleUpdate(inputDeps);
var commandBuffer = beginInitializationEntityCommandBufferSystem.CreateCommandBuffer();
// Check Connections (Fill Unidentified Connections)
var connectionJob = new HandleConnectionsRequestsJob
{
driver = m_Driver,
unidentifiedConnections = unidentifiedConnections,
commandBuffer = commandBuffer,
m_Connections = m_Connections,
playersEntities = playersEntities,
outgoingReliableMessagesFromEntity = GetBufferFromEntity<OutgoingReliableMessages>(),
outgoingUnreliableMessages = GetBufferFromEntity<OutgoingUnreliableMessages>(),
}.Schedule(inputDeps);
// Handle Identifications Job
var identificationJobHandle = new HandleIdentificationsJob
{
driver = m_Driver,
commandBuffer = commandBuffer,
unidentifiedConnections = unidentifiedConnections,
disconnectedPlayerLookup = GetComponentDataFromEntity<DisconnectedPlayer>(true),
playersEntities = playersEntities,
m_Connections = m_Connections,
players_SecretKey = players_SecretKey,
reliablePipeline = reliablePipeline,
}.Schedule(connectionJob);
// Sending Messages
var SendReliableMessagesJobHandle = new SendReliableMessagesJob
{
driver = m_Driver.ToConcurrent(),
ReliablePipeline = reliablePipeline,
outGoingBufferFromEntity = GetBufferFromEntity<OutgoingReliableMessages>(isReadOnly: false),
connections = m_Connections,
}.Schedule(this, identificationJobHandle);
var SendUnreliableMessagesJobHandle = new SendUnreliableMessagesJob
{
driver = m_Driver.ToConcurrent(),
unreliablePipeline = unreliablePipeline,
outGoingBufferFromEntity = GetBufferFromEntity<OutgoingUnreliableMessages>(isReadOnly: false),
connections = m_Connections,
}.Schedule(this, identificationJobHandle);
var ReceiveMessagesPacketsJobHandle = new ReceiveMessagesPacketsJob
{
driver = m_Driver.ToConcurrent(),
connections = m_Connections,
}.Schedule(this, identificationJobHandle);
var finalHandle = JobHandle.CombineDependencies(SendUnreliableMessagesJobHandle, SendReliableMessagesJobHandle, ReceiveMessagesPacketsJobHandle);
beginInitializationEntityCommandBufferSystem.AddJobHandleForProducer(finalHandle);
return finalHandle;
}
}
StackTraces:
InvalidOperationException: The previously scheduled job HandleConnectionsRequestsJob writes to the NativeArray HandleConnectionsRequestsJob.driver.m_EventQueue.m_ConnectionEventHeadTail. You must call JobHandle.Complete() on the job HandleConnectionsRequestsJob, before you can write to the NativeArray safely.
Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndThrowNoEarlyOut (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) <0x28b181d8240 + 0x00052> in <c254d6bddee24edb8742cd1c78b0db19>:0
Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndThrow (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) (at C:/buildslave/unity/build/Runtime/Export/Jobs/AtomicSafetyHandle.bindings.cs:158)
Unity.Networking.Transport.NetworkEventQueue+Concurrent+ConcurrentConnectionQueue..ctor (Unity.Collections.NativeList`1[T] queue) (at Packages/com.unity.transport/Runtime/NetworkEventQueue.cs:186)
Unity.Networking.Transport.NetworkEventQueue.ToConcurrent () (at Packages/com.unity.transport/Runtime/NetworkEventQueue.cs:162)
Unity.Networking.Transport.GenericNetworkDriver`2[T,TNetworkPipelineStageCollection].ToConcurrent () (at Packages/com.unity.transport/Runtime/NetworkDriver.cs:33)
ServerManagerSystem.OnUpdate (Unity.Jobs.JobHandle inputDeps) (at Assets/Scripts/ServerManagerSystem.cs:513)
Unity.Entities.JobComponentSystem.InternalUpdate () (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystem.cs:933)
Unity.Entities.ComponentSystemBase.Update () (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystem.cs:284)
Unity.Entities.ComponentSystemGroup.OnUpdate () (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystemGroup.cs:602)
UnityEngine.Debug:LogException(Exception)
Unity.Debug:LogException(Exception) (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/Stubs/Unity/Debug.cs:25)
Unity.Entities.ComponentSystemGroup:OnUpdate() (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystemGroup.cs:606)
Unity.Entities.ComponentSystem:InternalUpdate() (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystem.cs:800)
Unity.Entities.ComponentSystemBase:Update() (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystem.cs:284)
Unity.Entities.DummyDelegateWrapper:TriggerUpdate() (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ScriptBehaviourUpdateOrder.cs:144)
ArgumentException: The previously scheduled job HandleIdentificationsJob writes to the NativeArray HandleIdentificationsJob.commandBuffer. You must call JobHandle.Complete() on the job HandleIdentificationsJob, before you can write to the NativeArray safely.
EntityCommandBuffer was recorded in ServerManagerSystem and played back in Unity.Entities.BeginInitializationEntityCommandBufferSystem.
at (wrapper managed-to-native) Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndThrowNoEarlyOut_Injected(Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle&)
at Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndThrowNoEarlyOut (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) <0x28b181d8240 + 0x00052> in <c254d6bddee24edb8742cd1c78b0db19>:0
at Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckWriteAndThrow (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) [0x0002e] in C:\buildslave\unity\build\Runtime\Export\Jobs\AtomicSafetyHandle.bindings.cs:158
at Unity.Entities.EntityCommandBuffer.EnforceSingleThreadOwnership () [0x0001a] in C:\Unity_Projects\UnityTransport\Library\PackageCache\com.unity.entities@0.1.1-preview\Unity.Entities\EntityCommandBuffer.cs:756
at Unity.Entities.EntityCommandBuffer.Playback (Unity.Entities.EntityManager mgr) [0x00014] in C:\Unity_Projects\UnityTransport\Library\PackageCache\com.unity.entities@0.1.1-preview\Unity.Entities\EntityCommandBuffer.cs:1080
at Unity.Entities.EntityCommandBufferSystem.FlushPendingBuffers (System.Boolean playBack) [0x00061] in C:\Unity_Projects\UnityTransport\Library\PackageCache\com.unity.entities@0.1.1-preview\Unity.Entities\ComponentSystem.cs:1243
Unity.Entities.EntityCommandBufferSystem.FlushPendingBuffers (System.Boolean playBack) (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystem.cs:1304)
Unity.Entities.EntityCommandBufferSystem.OnUpdate () (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystem.cs:1211)
Unity.Entities.ComponentSystem.InternalUpdate () (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystem.cs:800)
Unity.Entities.ComponentSystemBase.Update () (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystem.cs:284)
Unity.Entities.ComponentSystemGroup.OnUpdate () (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystemGroup.cs:602)
UnityEngine.Debug:LogException(Exception)
Unity.Debug:LogException(Exception) (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/Stubs/Unity/Debug.cs:25)
Unity.Entities.ComponentSystemGroup:OnUpdate() (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystemGroup.cs:606)
Unity.Entities.ComponentSystem:InternalUpdate() (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystem.cs:800)
Unity.Entities.ComponentSystemBase:Update() (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ComponentSystem.cs:284)
Unity.Entities.DummyDelegateWrapper:TriggerUpdate() (at Library/PackageCache/com.unity.entities@0.1.1-preview/Unity.Entities/ScriptBehaviourUpdateOrder.cs:144)