You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

187 lines
6.4 KiB

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