完善snapshot

master
孙钦者 7 days ago
parent 5cf62f91cd
commit af72792875
  1. 7
      LocalPackages/com.nimin.lowlevel/Runtime/NativeDataContainer.cs
  2. 34
      LocalPackages/com.nimin.lowlevel/Runtime/UnsafeDataContainer.cs
  3. 8
      LocalPackages/com.nimin.network/Runtime/ClientAgent.cs
  4. 88
      LocalPackages/com.nimin.network/Runtime/NetDatabase.Snapshot.cs
  5. 65
      LocalPackages/com.nimin.network/Runtime/NetDatabase.cs
  6. 17
      LocalPackages/com.nimin.network/Runtime/Test/TestNetDatabase.cs

@ -9,6 +9,8 @@ namespace GameCore.LowLevel
[NativeDisableUnsafePtrRestriction]
internal UnsafeDataContainer* m_UnsafeDataPtr;
internal AllocatorManager.AllocatorHandle m_Allocator;
public int Length => m_UnsafeDataPtr->Length;
public bool IsCreated => m_UnsafeDataPtr != null;
@ -56,5 +58,10 @@ namespace GameCore.LowLevel
{
m_UnsafeDataPtr->Clear();
}
public void CopyFrom(NativeDataContainer<T> other)
{
m_UnsafeDataPtr->CopyFrom(*other.m_UnsafeDataPtr);
}
}
}

@ -2,6 +2,7 @@
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.Assertions;
namespace GameCore.LowLevel
{
@ -19,21 +20,23 @@ namespace GameCore.LowLevel
ClearNew = 1,
ClearAll = 2,
}
public readonly int elementSize;
private UnsafeList<FreeNode> m_Buffer;
private readonly int m_NodeNumPerElement;
public int Length => m_Buffer.Length;
public bool IsCreated => m_Buffer.IsCreated;
public UnsafeDataContainer(int elementSize, AllocatorManager.AllocatorHandle allocator)
{
if (elementSize <= 0)
throw new ArgumentException(nameof(elementSize));
this.elementSize = elementSize;
m_NodeNumPerElement = ComputeNodeNumPerElement(elementSize);
m_Buffer = new UnsafeList<FreeNode>(0, allocator);
m_Buffer.Resize(m_NodeNumPerElement, NativeArrayOptions.ClearMemory);
}
@ -54,7 +57,7 @@ namespace GameCore.LowLevel
ref var node = ref m_Buffer.ElementAt(index * m_NodeNumPerElement);
if (node.next >= 0)
return false;
ref var head = ref m_Buffer.ElementAt(0);
node.next = head.next;
head.next = index;
@ -68,11 +71,14 @@ namespace GameCore.LowLevel
if (index == 0)
{
index = m_Buffer.Length / m_NodeNumPerElement;
m_Buffer.Resize(m_Buffer.Length + m_NodeNumPerElement, options == AllocOptions.None ? NativeArrayOptions.UninitializedMemory : NativeArrayOptions.ClearMemory);
m_Buffer.Resize(m_Buffer.Length + m_NodeNumPerElement,
options == AllocOptions.None
? NativeArrayOptions.UninitializedMemory
: NativeArrayOptions.ClearMemory);
m_Buffer.ElementAt(index * m_NodeNumPerElement).next = -1;
return index;
}
ref var node = ref m_Buffer.ElementAt(index * m_NodeNumPerElement);
if (options == AllocOptions.ClearAll)
{
@ -89,8 +95,8 @@ namespace GameCore.LowLevel
{
ref var node = ref m_Buffer.ElementAt(index * m_NodeNumPerElement);
if (node.next >= 0)
throw new Exception("Index out of range");
throw new IndexOutOfRangeException();
return ref UnsafeUtility.As<FreeNode, T>(ref m_Buffer.ElementAt(index * m_NodeNumPerElement + 1));
}
@ -100,6 +106,16 @@ namespace GameCore.LowLevel
m_Buffer.ElementAt(0).next = 0;
}
public void CopyFrom(UnsafeDataContainer other)
{
if (elementSize != other.elementSize)
{
throw new InvalidOperationException();
}
m_Buffer.CopyFrom(other.m_Buffer);
}
internal static int ComputeNodeNumPerElement(int elementSize)
{
return (elementSize + UnsafeUtility.SizeOf<FreeNode>() - 1) / UnsafeUtility.SizeOf<FreeNode>() + 1;

@ -1,10 +1,18 @@
using System;
using Unity.Collections;
namespace GameCore.Network
{
public struct ClientAgent : IDisposable
{
private NativeList<int> dirtySet;
public void Dispose()
{
//TODO
}
public void UpdateDirtySet(NetDatabase.Snapshot netDatabase, int frameId)
{
}

@ -1,14 +1,100 @@
using System;
using GameCore.LowLevel;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
namespace GameCore.Network
{
public partial struct NetDatabase
{
public readonly struct Snapshot : IDisposable
public struct Snapshot : IDisposable
{
private NativeDataContainer<Entry> entries;
private NativeArray<UnsafeDataContainer> dataContainers;
private NativeList<FrameHistoryItem> frameHistoryList;
private NativeList<UnsafeList<int>> childrenList;
private readonly int maxHistoryCount;
public Snapshot(TypeMetaDatabase typeMetaDatabase, int maxHistoryCount,
AllocatorManager.AllocatorHandle allocator)
{
entries = new(allocator);
var typeCount = typeMetaDatabase.GetTotalTypeCount();
dataContainers = new NativeArray<UnsafeDataContainer>(typeCount, allocator.ToAllocator);
for (var i = 0; i < typeCount; i++)
{
if (typeMetaDatabase.IsValid(i))
{
dataContainers[i] = new UnsafeDataContainer(typeMetaDatabase.GetTypeSize(i), allocator);
}
}
frameHistoryList = new NativeList<FrameHistoryItem>(allocator);
childrenList = new NativeList<UnsafeList<int>>(allocator);
this.maxHistoryCount = maxHistoryCount;
}
public void Dispose()
{
entries.Dispose();
var typeCount = dataContainers.Length;
for (var i = 0; i < typeCount; i++)
{
if (dataContainers[i].IsCreated)
dataContainers[i].Dispose();
}
dataContainers.Dispose();
frameHistoryList.Dispose();
for (int i = 0, len = childrenList.Length; i < len; i++)
{
childrenList[i].Dispose();
}
childrenList.Dispose();
}
public void GatherNetDataIndex(NativeList<int> list)
{
for (int i = 1, len = entries.Length; i < len; ++i)
{
if (entries.HasValue(i))
list.Add(i);
}
}
public void CopyFrom(NetDatabase database)
{
entries.CopyFrom(database.entries);
var typeCount = dataContainers.Length;
for (var i = 0; i < typeCount; i++)
{
ref var dataContainer = ref dataContainers.GetRef(i);
if (dataContainer.IsCreated)
dataContainer.CopyFrom(database.dataContainers[i]);
}
frameHistoryList.CopyFrom(database.frameHistoryList);
var newLength = database.childrenList.Length;
var oldLength = childrenList.Length;
if (oldLength < newLength)
{
childrenList.Resize(newLength, NativeArrayOptions.UninitializedMemory);
for (var i = oldLength; i < newLength; ++i)
{
childrenList.ElementAt(i) = new UnsafeList<int>(0, database.allocator);
}
}
for (int i = 0, len = database.childrenList.Length; i < len; ++i)
{
childrenList.ElementAt(i).CopyFrom(database.childrenList[i]);
}
}
}
}

@ -16,12 +16,14 @@ namespace GameCore.Network
public ushort historyOffset;
public ushort historyCount;
public int parentIndex;
public int childrenListIndex;
}
private NativeDataContainer<Entry> entries;
private NativeHashMap<int, UnsafeList<int>> childrenIndexMap;
private NativeArray<UnsafeDataContainer> dataContainers;
private NativeList<FrameHistoryItem> frameHistoryList;
private NativeList<UnsafeList<int>> childrenList;
private NativeList<int> freeChildrenListIndexStack;
private readonly int maxHistoryCount;
private readonly AllocatorManager.AllocatorHandle allocator;
@ -30,7 +32,6 @@ namespace GameCore.Network
AllocatorManager.AllocatorHandle allocator)
{
entries = new(allocator);
childrenIndexMap = new(8, allocator);
var typeCount = typeMetaDatabase.GetTotalTypeCount();
dataContainers = new NativeArray<UnsafeDataContainer>(typeCount, allocator.ToAllocator);
@ -44,6 +45,9 @@ namespace GameCore.Network
frameHistoryList = new NativeList<FrameHistoryItem>(allocator);
childrenList = new NativeList<UnsafeList<int>>(allocator) {default};
freeChildrenListIndexStack = new NativeList<int>(allocator);
this.maxHistoryCount = maxHistoryCount;
this.allocator = allocator;
}
@ -52,20 +56,22 @@ namespace GameCore.Network
{
entries.Dispose();
foreach (var kvp in childrenIndexMap)
{
kvp.Value.Dispose();
}
childrenIndexMap.Dispose();
var typeCount = dataContainers.Length;
for (var i = 0; i < typeCount; i++)
{
if (dataContainers[i].IsCreated)
dataContainers[i].Dispose();
}
dataContainers.Dispose();
frameHistoryList.Dispose();
for (int i = 0, len = childrenList.Length; i < len; i++)
{
childrenList[i].Dispose();
}
childrenList.Dispose();
freeChildrenListIndexStack.Dispose();
}
public int Add<T>(T data, int frameId, int parentIndex, out int generation,
@ -87,14 +93,26 @@ namespace GameCore.Network
dataContainer.ElementAt<T>(dataIndex) = data;
entry.parentIndex = parentIndex;
entry.childrenListIndex = 0;
if (parentIndex > 0)
{
if (!childrenIndexMap.TryGetValue(parentIndex, out var list))
ref var parentEntry = ref entries.ElementAt(parentIndex);
if (parentEntry.childrenListIndex == 0)
{
list = new UnsafeList<int>(4, allocator);
if (freeChildrenListIndexStack.Length > 0)
{
parentEntry.childrenListIndex = freeChildrenListIndexStack[^1];
freeChildrenListIndexStack.RemoveAt(freeChildrenListIndexStack.Length - 1);
}
else
{
parentEntry.childrenListIndex = childrenList.Length;
childrenList.Add(new UnsafeList<int>(4, allocator));
}
}
ref var list = ref childrenList.ElementAt(parentEntry.childrenListIndex);
list.Add(entryIndex);
childrenIndexMap[parentIndex] = list;
}
entry.historyOffset = 0;
@ -178,25 +196,26 @@ namespace GameCore.Network
if (entry.parentIndex > 0)
{
if (removeFromParent && childrenIndexMap.TryGetValue(entry.parentIndex, out var list))
if (removeFromParent)
{
var i = list.IndexOf(index);
list.RemoveAtSwapBack(i);
childrenIndexMap[entry.parentIndex] = list;
var parentEntry = entries.ElementAt(entry.parentIndex);
ref var list = ref childrenList.ElementAt(parentEntry.childrenListIndex);
var selfIndex = list.IndexOf(index);
list.RemoveAtSwapBack(selfIndex);
}
}
if (entry.childrenListIndex > 0)
{
if (childrenIndexMap.TryGetValue(index, out var list))
ref var list = ref childrenList.ElementAt(entry.childrenListIndex);
for (int i = 0, len = list.Length; i < len; ++i)
{
for (int i = 0, len = list.Length; i < len; ++i)
{
RemoveInternal(list[i], false);
}
list.Dispose();
childrenIndexMap.Remove(index);
RemoveInternal(list[i], false);
}
list.Clear();
freeChildrenListIndexStack.Add(entry.childrenListIndex);
}
entries.Free(index);

@ -22,6 +22,7 @@ namespace GameCore.Network.Test
private TypeMetaDatabase typeMetaDatabase;
private NetDatabase netDatabase;
private NetDatabase.Snapshot snapshot;
private void OnEnable()
{
@ -30,11 +31,13 @@ namespace GameCore.Network.Test
typeMetaDatabase.RegisterType<Soldier>();
netDatabase = new NetDatabase(typeMetaDatabase, 16, Allocator.Persistent);
snapshot = new NetDatabase.Snapshot(typeMetaDatabase, 16, Allocator.Persistent);
var handle = new UpdateJob()
{
typeMetaDatabase = typeMetaDatabase,
netDatabase = netDatabase,
snapshot = snapshot,
frameId = 1,
}.Schedule();
handle.Complete();
@ -44,6 +47,7 @@ namespace GameCore.Network.Test
{
typeMetaDatabase.Dispose();
netDatabase.Dispose();
snapshot.Dispose();
}
[BurstCompile]
@ -51,6 +55,7 @@ namespace GameCore.Network.Test
{
public TypeMetaDatabase typeMetaDatabase;
public NetDatabase netDatabase;
public NetDatabase.Snapshot snapshot;
public int frameId;
public void Execute()
@ -69,11 +74,13 @@ namespace GameCore.Network.Test
var ok = netDatabase.Update(soldierIndex, soldier, frameId, typeMetaDatabase);
Debug.Log($"Soldier update: {ok}, id: {soldierData.id}, coord: {soldierData.coord}");
ok = netDatabase.Remove(troopIndex);
Debug.Log($"Troop removed: {ok}");
ok = netDatabase.Remove(soldierIndex);
Debug.Log($"Solider removed: {ok}");
// ok = netDatabase.Remove(troopIndex);
// Debug.Log($"Troop removed: {ok}");
//
// ok = netDatabase.Remove(soldierIndex);
// Debug.Log($"Solider removed: {ok}");
snapshot.CopyFrom(netDatabase);
}
}
}

Loading…
Cancel
Save