|
|
|
|
|
using System;
|
|
|
|
|
|
using GameCore.LowLevel;
|
|
|
|
|
|
using Unity.Collections;
|
|
|
|
|
|
using Unity.Collections.LowLevel.Unsafe;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
|
|
namespace GameCore.Network
|
|
|
|
|
|
{
|
|
|
|
|
|
public partial struct NetDatabase : IDisposable
|
|
|
|
|
|
{
|
|
|
|
|
|
private struct Entry
|
|
|
|
|
|
{
|
|
|
|
|
|
public int generation;
|
|
|
|
|
|
public int typeIndex;
|
|
|
|
|
|
public int dataIndex;
|
|
|
|
|
|
public ushort historyOffset;
|
|
|
|
|
|
public ushort historyCount;
|
|
|
|
|
|
public int parentIndex;
|
|
|
|
|
|
public int childrenIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private NativeDataContainer<Entry> entries;
|
|
|
|
|
|
private NativeArray<UnsafeDataContainer> dataContainers;
|
|
|
|
|
|
private NativeList<FrameHistoryItem> frameHistoryList;
|
|
|
|
|
|
|
|
|
|
|
|
private readonly int maxHistoryCount;
|
|
|
|
|
|
private readonly AllocatorManager.AllocatorHandle allocator;
|
|
|
|
|
|
|
|
|
|
|
|
public NetDatabase(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);
|
|
|
|
|
|
|
|
|
|
|
|
this.maxHistoryCount = maxHistoryCount;
|
|
|
|
|
|
this.allocator = allocator;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public int Add<T>(T data, int frameId, int parentIndex, out int generation,
|
|
|
|
|
|
TypeMetaDatabase typeMetaDatabase) where T : unmanaged
|
|
|
|
|
|
{
|
|
|
|
|
|
var typeIndex = typeMetaDatabase.TypeIndexOf<T>();
|
|
|
|
|
|
|
|
|
|
|
|
var childrenIndex = 0;
|
|
|
|
|
|
generation = 0;
|
|
|
|
|
|
// if (parentIndex > 0)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if (parentIndex >= entryList.Length)
|
|
|
|
|
|
// return 0;
|
|
|
|
|
|
//
|
|
|
|
|
|
// ref var parentEntry = ref entryList.ElementAt(parentIndex);
|
|
|
|
|
|
// if (parentEntry.childrenIndex > 0)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// childrenIndex = parentEntry.childrenIndex;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// else
|
|
|
|
|
|
// {
|
|
|
|
|
|
// //TODO
|
|
|
|
|
|
// }
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
var entryIndex = entries.Alloc(UnsafeDataContainer.AllocOptions.ClearNew);
|
|
|
|
|
|
ref var entry = ref entries.ElementAt(entryIndex);
|
|
|
|
|
|
generation = entry.generation + 1;
|
|
|
|
|
|
entry.generation = generation;
|
|
|
|
|
|
entry.typeIndex = typeIndex;
|
|
|
|
|
|
|
|
|
|
|
|
ref var dataContainer = ref dataContainers.GetRef(typeIndex);
|
|
|
|
|
|
var dataIndex = dataContainer.Alloc();
|
|
|
|
|
|
entry.dataIndex = dataIndex;
|
|
|
|
|
|
dataContainer.ElementAt<T>(dataIndex) = data;
|
|
|
|
|
|
|
|
|
|
|
|
//TODO
|
|
|
|
|
|
//entry.parentIndex = parentIndex;
|
|
|
|
|
|
|
|
|
|
|
|
entry.historyOffset = 0;
|
|
|
|
|
|
var fieldSizeArray = typeMetaDatabase.GetFieldSizeArray(typeIndex);
|
|
|
|
|
|
var frameHistoryItem = FrameHistoryItem.Make(default, data, fieldSizeArray, frameId);
|
|
|
|
|
|
var minLength = (entryIndex + 1) * maxHistoryCount;
|
|
|
|
|
|
if (frameHistoryList.Length < minLength)
|
|
|
|
|
|
{
|
|
|
|
|
|
frameHistoryList.Resize(minLength, NativeArrayOptions.UninitializedMemory);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
frameHistoryList.ElementAt(entryIndex * maxHistoryCount) = frameHistoryItem;
|
|
|
|
|
|
entry.historyCount = 1;
|
|
|
|
|
|
|
|
|
|
|
|
return entryIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public ref readonly T Get<T>(int index, TypeMetaDatabase typeMetaDatabase) where T : unmanaged
|
|
|
|
|
|
{
|
|
|
|
|
|
var typeIndex = typeMetaDatabase.TypeIndexOf<T>();
|
|
|
|
|
|
|
|
|
|
|
|
ref var entry = ref entries.ElementAt(index);
|
|
|
|
|
|
if (entry.typeIndex != typeIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new Exception("Type mismatch");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ref var dataContainer = ref dataContainers.GetRef(typeIndex);
|
|
|
|
|
|
return ref dataContainer.ElementAt<T>(entry.dataIndex);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool Update<T>(int index, T data, int frameId, TypeMetaDatabase typeMetaDatabase) where T : unmanaged
|
|
|
|
|
|
{
|
|
|
|
|
|
var typeIndex = typeMetaDatabase.TypeIndexOf<T>();
|
|
|
|
|
|
|
|
|
|
|
|
ref var entry = ref entries.ElementAt(index);
|
|
|
|
|
|
if (entry.typeIndex != typeIndex)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new Exception("Type mismatch");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ref var dataContainer = ref dataContainers.GetRef(typeIndex);
|
|
|
|
|
|
ref var dataRef = ref dataContainer.ElementAt<T>(entry.dataIndex);
|
|
|
|
|
|
var baseData = dataRef;
|
|
|
|
|
|
|
|
|
|
|
|
var fieldSizeArray = typeMetaDatabase.GetFieldSizeArray(typeIndex);
|
|
|
|
|
|
var frameHistoryItem = FrameHistoryItem.Make(baseData, data, fieldSizeArray, frameId);
|
|
|
|
|
|
if (!frameHistoryItem.IsDirty)
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
dataRef = data;
|
|
|
|
|
|
|
|
|
|
|
|
var startIndex = (entry.historyOffset + entry.historyCount) % maxHistoryCount;
|
|
|
|
|
|
frameHistoryList.ElementAt(index * maxHistoryCount + startIndex) = frameHistoryItem;
|
|
|
|
|
|
if (entry.historyCount == maxHistoryCount)
|
|
|
|
|
|
{
|
|
|
|
|
|
entry.historyOffset = (ushort) ((entry.historyOffset + 1) % maxHistoryCount);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
entry.historyCount++;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public bool Remove(int index)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!entries.Free(index))
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
|
|
ref var entry = ref entries.ElementAt(index);
|
|
|
|
|
|
ref var dataContainer = ref dataContainers.GetRef(entry.dataIndex);
|
|
|
|
|
|
if (!dataContainer.Free(entry.dataIndex))
|
|
|
|
|
|
throw new Exception("Data mismatch");
|
|
|
|
|
|
|
|
|
|
|
|
//TODO
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public int GetGeneration(int index)
|
|
|
|
|
|
{
|
|
|
|
|
|
ref var entry = ref entries.ElementAt(index);
|
|
|
|
|
|
return entry.generation;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|