Compare commits
10
Commits
5c4c25664d
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8075c6f622 | ||
|
|
5e956f5989 | ||
|
|
af72792875 | ||
|
|
5cf62f91cd | ||
|
|
88125fc128 | ||
|
|
098cbfb696 | ||
|
|
d9b66edd89 | ||
|
|
6c8108e3ea | ||
|
|
6d912005a5 | ||
|
|
6256dcb52b |
No files matched your search
@@ -12,7 +12,8 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: b79190dcfae6a2f4fbdfc9deccf00ef7, type: 3}
|
||||
m_Name: NetworkDriverAsset
|
||||
m_EditorClassIdentifier:
|
||||
useSimulator: 0
|
||||
port: 7777
|
||||
useSimulator: 1
|
||||
packetDelayMs: 500
|
||||
packetJitterMs: 300
|
||||
packetDropPercentage: 10
|
||||
+149
-10
@@ -38,7 +38,6 @@ RenderSettings:
|
||||
m_ReflectionIntensity: 1
|
||||
m_CustomReflection: {fileID: 0}
|
||||
m_Sun: {fileID: 705507994}
|
||||
m_IndirectSpecularColor: {r: 0.44657815, g: 0.49641192, b: 0.57481617, a: 1}
|
||||
m_UseRadianceAmbientProbe: 0
|
||||
--- !u!157 &3
|
||||
LightmapSettings:
|
||||
@@ -104,7 +103,7 @@ NavMeshSettings:
|
||||
serializedVersion: 2
|
||||
m_ObjectHideFlags: 0
|
||||
m_BuildSettings:
|
||||
serializedVersion: 2
|
||||
serializedVersion: 3
|
||||
agentTypeID: 0
|
||||
agentRadius: 0.5
|
||||
agentHeight: 2
|
||||
@@ -117,7 +116,7 @@ NavMeshSettings:
|
||||
cellSize: 0.16666667
|
||||
manualTileSize: 0
|
||||
tileSize: 256
|
||||
accuratePlacement: 0
|
||||
buildHeightMesh: 0
|
||||
maxJobWorkers: 0
|
||||
preserveTilesOutsideBounds: 0
|
||||
debug:
|
||||
@@ -209,13 +208,13 @@ Transform:
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 705507993}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
|
||||
m_LocalPosition: {x: 0, y: 3, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 1
|
||||
m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
|
||||
--- !u!1 &963194225
|
||||
GameObject:
|
||||
@@ -228,7 +227,6 @@ GameObject:
|
||||
- component: {fileID: 963194228}
|
||||
- component: {fileID: 963194227}
|
||||
- component: {fileID: 963194226}
|
||||
- component: {fileID: 963194229}
|
||||
m_Layer: 0
|
||||
m_Name: Main Camera
|
||||
m_TagString: MainCamera
|
||||
@@ -258,9 +256,17 @@ Camera:
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_Iso: 200
|
||||
m_ShutterSpeed: 0.005
|
||||
m_Aperture: 16
|
||||
m_FocusDistance: 10
|
||||
m_FocalLength: 50
|
||||
m_BladeCount: 5
|
||||
m_Curvature: {x: 2, y: 11}
|
||||
m_BarrelClipping: 0.25
|
||||
m_Anamorphism: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_FocalLength: 50
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
@@ -294,23 +300,156 @@ Transform:
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 963194225}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 1, z: -10}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &963194229
|
||||
--- !u!1 &1613085077
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1613085078}
|
||||
- component: {fileID: 1613085079}
|
||||
m_Layer: 0
|
||||
m_Name: ClientMain
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 0
|
||||
--- !u!4 &1613085078
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1613085077}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &1613085079
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 963194225}
|
||||
m_GameObject: {fileID: 1613085077}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 694d8256118344eb2b130fceb1a11b7f, type: 3}
|
||||
m_Script: {fileID: 11500000, guid: d126d712307544dd89716677e730aa93, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
address: 127.0.0.1
|
||||
driverAsset: {fileID: 11400000, guid: a8a5562854ecf4cc1a49700e8bd93c19, type: 2}
|
||||
--- !u!1 &1633746920
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1633746922}
|
||||
- component: {fileID: 1633746921}
|
||||
m_Layer: 0
|
||||
m_Name: Tests
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &1633746921
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1633746920}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: dae5c80c53134e4689ce1b03af81f96e, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!4 &1633746922
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1633746920}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &1936170114
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1936170116}
|
||||
- component: {fileID: 1936170115}
|
||||
m_Layer: 0
|
||||
m_Name: ServerMain
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &1936170115
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1936170114}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 1da32d64fdd4d41778db4fd91607ac27, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
address: 127.0.0.1
|
||||
driverAsset: {fileID: 11400000, guid: a8a5562854ecf4cc1a49700e8bd93c19, type: 2}
|
||||
--- !u!4 &1936170116
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1936170114}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1660057539 &9223372036854775807
|
||||
SceneRoots:
|
||||
m_ObjectHideFlags: 0
|
||||
m_Roots:
|
||||
- {fileID: 963194228}
|
||||
- {fileID: 705507995}
|
||||
- {fileID: 1936170116}
|
||||
- {fileID: 1613085078}
|
||||
- {fileID: 1633746922}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48c265b50587429a9a7555df18d64661
|
||||
timeCreated: 1765786522
|
||||
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using GameCore.Network;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Networking.Transport;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECSTest
|
||||
{
|
||||
public class ClientMain : MonoBehaviour
|
||||
{
|
||||
public string address = "127.0.0.1";
|
||||
public NetworkDriverAsset driverAsset;
|
||||
|
||||
private NetworkDriver driver;
|
||||
private NetworkPipeline unreliablePipeline;
|
||||
private NetworkPipeline reliablePipeline;
|
||||
private NativeReference<NetworkConnection> connection;
|
||||
private JobHandle jobHandle;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
driver = driverAsset.CreateClientDriver(address, out var c, out unreliablePipeline, out reliablePipeline);
|
||||
connection = new NativeReference<NetworkConnection>(c, Allocator.Persistent);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
jobHandle.Complete();
|
||||
|
||||
if (connection.IsCreated)
|
||||
{
|
||||
driver.Disconnect(connection.Value);
|
||||
driver.ScheduleUpdate().Complete();
|
||||
}
|
||||
|
||||
connection.Dispose();
|
||||
driver.Dispose();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
jobHandle.Complete();
|
||||
|
||||
//TODO Render()
|
||||
|
||||
jobHandle = driver.ScheduleUpdate();
|
||||
jobHandle = new ClientUpdateJob()
|
||||
{
|
||||
driver = driver,
|
||||
unreliablePipeline = unreliablePipeline,
|
||||
reliablePipeline = reliablePipeline,
|
||||
connection = connection,
|
||||
}.Schedule(jobHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d126d712307544dd89716677e730aa93
|
||||
timeCreated: 1765786534
|
||||
@@ -0,0 +1,43 @@
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Networking.Transport;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECSTest
|
||||
{
|
||||
[BurstCompile]
|
||||
public struct ClientUpdateJob : IJob
|
||||
{
|
||||
public NetworkDriver driver;
|
||||
public NetworkPipeline unreliablePipeline;
|
||||
public NetworkPipeline reliablePipeline;
|
||||
public NativeReference<NetworkConnection> connection;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
if (connection.Value == default)
|
||||
return;
|
||||
|
||||
NetworkEvent.Type cmd;
|
||||
while ((cmd = connection.Value.PopEvent(driver, out var stream, out var networkPipeline)) !=
|
||||
NetworkEvent.Type.Empty)
|
||||
{
|
||||
if (cmd == NetworkEvent.Type.Data)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
else if (cmd == NetworkEvent.Type.Connect)
|
||||
{
|
||||
Debug.Log("[Client] Connected to server");
|
||||
//TODO
|
||||
}
|
||||
else if (cmd == NetworkEvent.Type.Disconnect)
|
||||
{
|
||||
connection.Value = default;
|
||||
Debug.Log("[Client] Disconnected to server");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ffb4af76205e4a638c5343a82b13ce08
|
||||
timeCreated: 1765789910
|
||||
@@ -1,7 +1,7 @@
|
||||
using GameCore.TinyECS;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace GameCore.Test
|
||||
namespace ECSTest
|
||||
{
|
||||
using Entity = Entity<EntityType>;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
namespace GameCore.Test
|
||||
namespace ECSTest
|
||||
{
|
||||
public enum EntityType
|
||||
{
|
||||
Unit,
|
||||
Monster,
|
||||
Cannon,
|
||||
Bullet,
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using GameCore.Test;
|
||||
using UnityEngine;
|
||||
|
||||
public class Main : MonoBehaviour
|
||||
{
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
TestEntityDataBlock.Run();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using Unity.Jobs;
|
||||
|
||||
namespace ECSTest.Server
|
||||
{
|
||||
public class GameLogic
|
||||
{
|
||||
public JobHandle Simulate(int beginFrameId, int frameCount, JobHandle dependency)
|
||||
{
|
||||
//TODO
|
||||
return dependency;
|
||||
}
|
||||
|
||||
private JobHandle Step(int frameId, JobHandle dependency)
|
||||
{
|
||||
return dependency;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51ab02ddeb9e4cdbb736075b2c7b43a8
|
||||
timeCreated: 1765871132
|
||||
@@ -1,17 +1,18 @@
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Networking.Transport;
|
||||
using UnityEngine;
|
||||
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Networking.Transport;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECSTest.Server
|
||||
{
|
||||
[BurstCompile]
|
||||
public struct ServerConnectionJob : IJob
|
||||
{
|
||||
public NetworkDriver driver;
|
||||
public NativeList<NetworkConnection> connectionList;
|
||||
public NativeList<int> disconnectIndexList;
|
||||
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
// disconnect
|
||||
@@ -21,6 +22,7 @@
|
||||
var index = disconnectIndexList[i];
|
||||
connectionList.RemoveAtSwapBack(index);
|
||||
}
|
||||
|
||||
disconnectIndexList.Clear();
|
||||
|
||||
// connect
|
||||
@@ -28,7 +30,12 @@
|
||||
while ((c = driver.Accept()) != default)
|
||||
{
|
||||
connectionList.Add(c);
|
||||
Debug.Log("Accepted a connection");
|
||||
Debug.Log("[Server] Accepted a connection");
|
||||
}
|
||||
|
||||
if (connectionList.Length > disconnectIndexList.Capacity)
|
||||
disconnectIndexList.SetCapacity(connectionList.Length);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace ECSTest.Server
|
||||
{
|
||||
public struct CannonData
|
||||
{
|
||||
public float2 position;
|
||||
public float2 velocity;
|
||||
public float direction;
|
||||
public int cooldownFrameId;
|
||||
public int health;
|
||||
public int deathFrameId;
|
||||
}
|
||||
|
||||
public struct BulletData
|
||||
{
|
||||
public float2 position;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8e44ed253ab647b3910794e124e6402e
|
||||
timeCreated: 1766030729
|
||||
@@ -0,0 +1,87 @@
|
||||
using GameCore.TinyECS;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using Random = Unity.Mathematics.Random;
|
||||
|
||||
namespace ECSTest.Server
|
||||
{
|
||||
|
||||
[BurstCompile]
|
||||
public struct TestWorldJob : IJob
|
||||
{
|
||||
public World world;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
// var componentId = ComponentId<BulletData>.Get();
|
||||
// Debug.LogError($"XXXX bulletData id: {componentId}");
|
||||
// var componentId2 = ComponentId<CannonData>.Get();
|
||||
// Debug.LogError($"xxxx2222 CannonData id: {componentId2}");
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct GetDeferred : IJob
|
||||
{
|
||||
public World world;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
// var componentId = ComponentId<BulletData>.Get();
|
||||
// Debug.LogError($"XXXX bulletData id: {componentId}");
|
||||
// var componentId2 = ComponentId<CannonData>.Get();
|
||||
// Debug.LogError($"xxxx2222 CannonData id: {componentId2}");
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct SpawnCannonJob : IJob
|
||||
{
|
||||
public World world;
|
||||
public NativeList<bool> deferList;
|
||||
|
||||
public uint seed;
|
||||
public int maxCount;
|
||||
public int spawnCountPerFrame;
|
||||
public Rect rect;
|
||||
public int initHealth;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
ref var database = ref world.cannonDatabase;
|
||||
if (database.Count >= maxCount)
|
||||
return;
|
||||
|
||||
var random = new Random(seed);
|
||||
for (int i = 0; i < spawnCountPerFrame; i++)
|
||||
{
|
||||
var pos = random.NextFloat2(rect.min, rect.max);
|
||||
var dir = random.NextFloat(math.PI2);
|
||||
math.sincos(dir, out var s, out var c);
|
||||
var velocity = new float2(c, s);
|
||||
|
||||
var entity = database.AddEntity();
|
||||
ref var cannonData = ref database.GetDataRef<CannonData>(entity);
|
||||
cannonData.position = pos;
|
||||
cannonData.velocity = velocity;
|
||||
cannonData.direction = dir;
|
||||
cannonData.health = initHealth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[BurstCompile]
|
||||
public struct SpawnBulletJob : IJob
|
||||
{
|
||||
public World World;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cfef090e4d64e91bf319abd48fe7e18
|
||||
timeCreated: 1765877986
|
||||
@@ -2,57 +2,88 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using GameCore.Network;
|
||||
using GameCore.TinyECS;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Networking.Transport;
|
||||
using UnityEngine;
|
||||
|
||||
public class ServerMain : MonoBehaviour
|
||||
namespace ECSTest.Server
|
||||
{
|
||||
public string address = "127.0.0.1";
|
||||
public NetworkDriverAsset driverAsset;
|
||||
|
||||
private NetworkDriver driver;
|
||||
private JobHandle networkJobHandle;
|
||||
private NativeList<NetworkConnection> connectionList;
|
||||
private NativeList<int> disconnectIndexList;
|
||||
|
||||
private void OnEnable()
|
||||
public class ServerMain : MonoBehaviour
|
||||
{
|
||||
driver = driverAsset.CreateServerDriver(address);
|
||||
|
||||
connectionList = new NativeList<NetworkConnection>(16,Allocator.Persistent);
|
||||
disconnectIndexList = new NativeList<int>(16, Allocator.Persistent);
|
||||
}
|
||||
public string address = "127.0.0.1";
|
||||
public NetworkDriverAsset driverAsset;
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
networkJobHandle.Complete();
|
||||
private NetworkDriver driver;
|
||||
private NetworkPipeline unreliablePipeline;
|
||||
private NetworkPipeline reliablePipeline;
|
||||
private JobHandle networkJobHandle;
|
||||
private NativeList<NetworkConnection> connectionList;
|
||||
private NativeList<int> disconnectIndexList;
|
||||
|
||||
driver.Dispose();
|
||||
|
||||
connectionList.Dispose();
|
||||
disconnectIndexList.Dispose();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
networkJobHandle.Complete();
|
||||
private World world;
|
||||
private JobHandle gameLogicJobHandle;
|
||||
|
||||
var concurrentDriver = driver.ToConcurrent();
|
||||
|
||||
networkJobHandle = driver.ScheduleUpdate();
|
||||
networkJobHandle = new ServerConnectionJob()
|
||||
private void OnEnable()
|
||||
{
|
||||
driver = driver,
|
||||
connectionList = connectionList,
|
||||
disconnectIndexList = disconnectIndexList,
|
||||
}.Schedule(networkJobHandle);
|
||||
|
||||
networkJobHandle = new ServerReceiveJob()
|
||||
{
|
||||
driver = concurrentDriver,
|
||||
}.Schedule(connectionList, 16, networkJobHandle);
|
||||
driver = driverAsset.CreateServerDriver(address, out unreliablePipeline, out reliablePipeline);
|
||||
|
||||
connectionList = new NativeList<NetworkConnection>(16, Allocator.Persistent);
|
||||
disconnectIndexList = new NativeList<int>(16, Allocator.Persistent);
|
||||
|
||||
var cannonMeta = EntityDataBlockMeta.Create<CannonData>();
|
||||
var cannonDataBlockChain = new EntityDataBlockChain(cannonMeta, Allocator.Persistent);
|
||||
world.cannonDatabase = cannonDataBlockChain.CreateEntityDatabase(EntityType.Cannon, 16);
|
||||
|
||||
var bulletMeta = EntityDataBlockMeta.Create<BulletData>();
|
||||
var bulletDataBlockChain = new EntityDataBlockChain(bulletMeta, Allocator.Persistent);
|
||||
world.bulletDatabase = bulletDataBlockChain.CreateEntityDatabase(EntityType.Bullet, 16);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
networkJobHandle.Complete();
|
||||
gameLogicJobHandle.Complete();
|
||||
|
||||
driver.Dispose();
|
||||
|
||||
connectionList.Dispose();
|
||||
disconnectIndexList.Dispose();
|
||||
|
||||
world.Dispose();
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
networkJobHandle.Complete();
|
||||
|
||||
var concurrentDriver = driver.ToConcurrent();
|
||||
|
||||
networkJobHandle = driver.ScheduleUpdate();
|
||||
networkJobHandle = new ServerConnectionJob()
|
||||
{
|
||||
driver = driver,
|
||||
connectionList = connectionList,
|
||||
disconnectIndexList = disconnectIndexList,
|
||||
}.Schedule(networkJobHandle);
|
||||
|
||||
networkJobHandle = new ServerReceiveJob()
|
||||
{
|
||||
driver = concurrentDriver,
|
||||
connectionList = connectionList,
|
||||
disconnectIndexList = disconnectIndexList.AsParallelWriter(),
|
||||
}.Schedule(connectionList, 16, networkJobHandle);
|
||||
|
||||
if (gameLogicJobHandle.IsCompleted)
|
||||
{
|
||||
gameLogicJobHandle.Complete();
|
||||
gameLogicJobHandle = new TestWorldJob()
|
||||
{
|
||||
world = world,
|
||||
|
||||
}.Schedule(networkJobHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,37 @@
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Networking.Transport;
|
||||
using UnityEngine;
|
||||
|
||||
using Unity.Burst;
|
||||
using Unity.Jobs;
|
||||
using Unity.Networking.Transport;
|
||||
|
||||
namespace ECSTest.Server
|
||||
{
|
||||
[BurstCompile]
|
||||
public struct ServerReceiveJob : IJobParallelForDefer
|
||||
{
|
||||
public NetworkDriver.Concurrent driver;
|
||||
|
||||
[ReadOnly]
|
||||
public NativeList<NetworkConnection> connectionList;
|
||||
public NativeList<int>.ParallelWriter disconnectIndexList;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
|
||||
var connection = connectionList[index];
|
||||
|
||||
NetworkEvent.Type cmd;
|
||||
while ((cmd = driver.PopEventForConnection(connection, out var stream)) !=
|
||||
NetworkEvent.Type.Empty)
|
||||
{
|
||||
if (cmd == NetworkEvent.Type.Data)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
else if (cmd == NetworkEvent.Type.Disconnect)
|
||||
{
|
||||
disconnectIndexList.AddNoResize(index);
|
||||
Debug.Log("[Server] Received a disconnection");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,13 @@
|
||||
using Unity.Burst;
|
||||
using Unity.Jobs;
|
||||
|
||||
using Unity.Burst;
|
||||
using Unity.Jobs;
|
||||
|
||||
namespace ECSTest.Server
|
||||
{
|
||||
[BurstCompile]
|
||||
public struct ServerSendJob : IJobParallelFor
|
||||
{
|
||||
public void Execute(int index)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using GameCore.TinyECS;
|
||||
|
||||
namespace ECSTest.Server
|
||||
{
|
||||
public struct World : IDisposable
|
||||
{
|
||||
public EntityDatabase<EntityType, EntityDataBlockChain> cannonDatabase;
|
||||
public EntityDatabase<EntityType, EntityDataBlockChain> bulletDatabase;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
cannonDatabase.Dispose();
|
||||
bulletDatabase.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34167e4ecf924d05b9abd31eb2b2e464
|
||||
timeCreated: 1765879427
|
||||
@@ -1,17 +1,18 @@
|
||||
using GameCore.TinyECS;
|
||||
using Unity.Collections;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameCore.Test
|
||||
namespace ECSTest
|
||||
{
|
||||
public static class TestEntityDataBlock
|
||||
{
|
||||
public static void Run()
|
||||
{
|
||||
var meta = EntityDataBlockMeta.Create<TransformData, StateData>();
|
||||
using var blockChain = new EntityDataBlockChain(meta, 1000);
|
||||
using var blockChain = new EntityDataBlockChain(meta, Allocator.Persistent, 1000);
|
||||
|
||||
blockChain.Add();
|
||||
ref var stateData = ref blockChain.GetData<StateData>(0);
|
||||
ref var stateData = ref blockChain.GetDataRef<StateData>(0);
|
||||
stateData.hp = 1000;
|
||||
|
||||
var view = blockChain.AsBlockView(0);
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using UnityEngine;
|
||||
|
||||
namespace ECSTest
|
||||
{
|
||||
public class TestIJobParallelForDefer
|
||||
{
|
||||
[BurstCompile]
|
||||
public struct PopulateJob : IJob
|
||||
{
|
||||
public NativeList<int> input;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Debug.Log($"000===== length: {input.Length}");
|
||||
for (int i = 0; i < 100; ++i)
|
||||
input.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
public struct StatJob : IJob
|
||||
{
|
||||
public NativeList<int> input;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
Debug.Log($"111===== length: {input.Length}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[BurstCompile]
|
||||
public struct ParallelJob : IJobParallelForDefer
|
||||
{
|
||||
[ReadOnly] public NativeList<int> input;
|
||||
|
||||
public void Execute(int index)
|
||||
{
|
||||
Debug.Log($"index: {index}, length: {input.Length}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void Test()
|
||||
{
|
||||
var list = new NativeList<int>(100, Allocator.TempJob);
|
||||
var handle = new PopulateJob() {input = list}.Schedule();
|
||||
handle = new ParallelJob() { input = list }.Schedule(list, 16, handle);
|
||||
handle = new PopulateJob() {input = list}.Schedule(handle);
|
||||
handle = new ParallelJob() { input = list }.Schedule(list, 16, handle);
|
||||
handle.Complete();
|
||||
list.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c02a6e16e5b349d3b07d50471da304c9
|
||||
timeCreated: 1766089200
|
||||
@@ -1,19 +0,0 @@
|
||||
using System;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameCore.Test
|
||||
{
|
||||
[BurstCompile]
|
||||
public struct TestJob : IJobParallelFor
|
||||
{
|
||||
public void Execute(int index)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace GameCore.LowLevel
|
||||
{
|
||||
public static class NativeArrayExtensions
|
||||
{
|
||||
public static ref T GetRef<T>(this NativeArray<T> array, int index)
|
||||
where T : struct
|
||||
{
|
||||
if (index < 0 || index >= array.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
unsafe
|
||||
{
|
||||
return ref UnsafeUtility.ArrayElementAsRef<T>(array.GetUnsafePtr(), index);
|
||||
}
|
||||
}
|
||||
|
||||
public static ref readonly T GetReadOnlyRef<T>(this NativeArray<T> array, int index)
|
||||
where T : struct
|
||||
{
|
||||
if (index < 0 || index >= array.Length)
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
unsafe
|
||||
{
|
||||
return ref UnsafeUtility.ArrayElementAsRef<T>(array.GetUnsafeReadOnlyPtr(), index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9b8d3e5900ff43ab8d285485371094ca
|
||||
timeCreated: 1767086551
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace GameCore.LowLevel
|
||||
{
|
||||
public unsafe struct NativeDataContainer<T> : IDisposable where T : unmanaged
|
||||
{
|
||||
[NativeDisableUnsafePtrRestriction]
|
||||
internal UnsafeDataContainer* m_UnsafeDataPtr;
|
||||
internal AllocatorManager.AllocatorHandle m_Allocator;
|
||||
|
||||
public int Length => m_UnsafeDataPtr->Length;
|
||||
|
||||
public bool IsCreated => m_UnsafeDataPtr != null;
|
||||
|
||||
public NativeDataContainer(AllocatorManager.AllocatorHandle allocator)
|
||||
{
|
||||
m_UnsafeDataPtr = AllocatorManager.Allocate<UnsafeDataContainer>(allocator);
|
||||
*m_UnsafeDataPtr = new UnsafeDataContainer(UnsafeUtility.SizeOf<T>(), allocator);
|
||||
|
||||
m_Allocator = allocator;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!IsCreated)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_UnsafeDataPtr->Dispose();
|
||||
AllocatorManager.Free(m_Allocator, m_UnsafeDataPtr);
|
||||
m_UnsafeDataPtr = null;
|
||||
}
|
||||
|
||||
public bool HasValue(int index)
|
||||
{
|
||||
return m_UnsafeDataPtr->HasValue(index);
|
||||
}
|
||||
|
||||
public bool Free(int index)
|
||||
{
|
||||
return m_UnsafeDataPtr->Free(index);
|
||||
}
|
||||
|
||||
public int Alloc(UnsafeDataContainer.AllocOptions options = UnsafeDataContainer.AllocOptions.None)
|
||||
{
|
||||
return m_UnsafeDataPtr->Alloc(options);
|
||||
}
|
||||
|
||||
public ref T ElementAt(int index)
|
||||
{
|
||||
return ref m_UnsafeDataPtr->ElementAt<T>(index);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
m_UnsafeDataPtr->Clear();
|
||||
}
|
||||
|
||||
public void CopyFrom(NativeDataContainer<T> other)
|
||||
{
|
||||
m_UnsafeDataPtr->CopyFrom(*other.m_UnsafeDataPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8c8c1ce9e9104a6ab8e96adc313588fe
|
||||
timeCreated: 1767171335
|
||||
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace GameCore.LowLevel
|
||||
{
|
||||
public ref struct TypedBuffer<T> where T : unmanaged
|
||||
{
|
||||
public NativeList<byte> buffer;
|
||||
|
||||
public int Length => buffer.Length / UnsafeUtility.SizeOf<T>();
|
||||
|
||||
public TypedBuffer(NativeList<byte> buffer)
|
||||
{
|
||||
this.buffer = buffer;
|
||||
}
|
||||
|
||||
public unsafe void Add(T data)
|
||||
{
|
||||
var oldLength = buffer.Length;
|
||||
buffer.Resize(oldLength + sizeof(T), NativeArrayOptions.UninitializedMemory);
|
||||
UnsafeUtility.CopyStructureToPtr(ref data, (byte*)buffer.GetUnsafePtr() + oldLength);
|
||||
}
|
||||
|
||||
public unsafe T this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index < 0 || index >= Length)
|
||||
throw new IndexOutOfRangeException(nameof(index));
|
||||
var p = (T*)buffer.GetUnsafeReadOnlyPtr();
|
||||
return p[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class TypedBufferExtensions
|
||||
{
|
||||
public static TypedBuffer<T> ToTypedBuffer<T>(this NativeList<byte> buffer)
|
||||
where T : unmanaged
|
||||
=> new(buffer);
|
||||
|
||||
public static unsafe void Sort<T>(this TypedBuffer<T> typedBuffer)
|
||||
where T : unmanaged, IComparable<T>
|
||||
{
|
||||
var p = (T*)typedBuffer.buffer.GetUnsafePtr();
|
||||
var l = typedBuffer.buffer.Length / sizeof(T);
|
||||
NativeSortExtension.Sort(p, l);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: edfdc737cb64451ebdd0dc178e8c07af
|
||||
timeCreated: 1767469202
|
||||
@@ -0,0 +1,124 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace GameCore.LowLevel
|
||||
{
|
||||
public unsafe struct UnsafeDataContainer : IDisposable
|
||||
{
|
||||
private struct FreeNode
|
||||
{
|
||||
public int next;
|
||||
public int _padding;
|
||||
}
|
||||
|
||||
public enum AllocOptions
|
||||
{
|
||||
None = 0,
|
||||
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);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
m_Buffer.Dispose();
|
||||
}
|
||||
|
||||
public bool HasValue(int index)
|
||||
{
|
||||
var node = m_Buffer[index * m_NodeNumPerElement];
|
||||
return node.next < 0;
|
||||
}
|
||||
|
||||
public bool Free(int index)
|
||||
{
|
||||
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;
|
||||
return true;
|
||||
}
|
||||
|
||||
public int Alloc(AllocOptions options = AllocOptions.None)
|
||||
{
|
||||
ref var head = ref m_Buffer.ElementAt(0);
|
||||
var index = head.next;
|
||||
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.ElementAt(index * m_NodeNumPerElement).next = -1;
|
||||
return index;
|
||||
}
|
||||
|
||||
ref var node = ref m_Buffer.ElementAt(index * m_NodeNumPerElement);
|
||||
if (options == AllocOptions.ClearAll)
|
||||
{
|
||||
var ptr = m_Buffer.Ptr + index * m_NodeNumPerElement;
|
||||
UnsafeUtility.MemClear(ptr, m_NodeNumPerElement * UnsafeUtility.SizeOf<FreeNode>());
|
||||
}
|
||||
|
||||
head.next = node.next;
|
||||
node.next = -1;
|
||||
return index;
|
||||
}
|
||||
|
||||
public ref T ElementAt<T>(int index) where T : unmanaged
|
||||
{
|
||||
ref var node = ref m_Buffer.ElementAt(index * m_NodeNumPerElement);
|
||||
if (node.next >= 0)
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
return ref UnsafeUtility.As<FreeNode, T>(ref m_Buffer.ElementAt(index * m_NodeNumPerElement + 1));
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
m_Buffer.Resize(m_NodeNumPerElement);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 345278cb8e5e4c4cbd58ead608d3d098
|
||||
timeCreated: 1766977488
|
||||
@@ -5,25 +5,9 @@
|
||||
"Unity.Collections",
|
||||
"Unity.Mathematics"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Android",
|
||||
"Editor",
|
||||
"iOS",
|
||||
"LinuxStandalone64",
|
||||
"Lumin",
|
||||
"macOSStandalone",
|
||||
"PS4",
|
||||
"Stadia",
|
||||
"Switch",
|
||||
"tvOS",
|
||||
"WSA",
|
||||
"WebGL",
|
||||
"WindowsStandalone32",
|
||||
"WindowsStandalone64",
|
||||
"XboxOne"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using GameCore.LowLevel;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace GameCore.Network
|
||||
{
|
||||
public struct ClientAgent : IDisposable
|
||||
{
|
||||
private struct Entry
|
||||
{
|
||||
public int srcIndex;
|
||||
public int generation;
|
||||
public int confirmedFrameId;
|
||||
public int deleteFrameId;
|
||||
public bool inView;
|
||||
}
|
||||
|
||||
private NativeList<Entry> entryList;
|
||||
private NativeList<int> freeEntryIndexStack;
|
||||
private NativeHashMap<int, int> entryIndexMap;
|
||||
private NativeList<int> dirtyList;
|
||||
private NativeList<byte> tempBuffer;
|
||||
|
||||
public ClientAgent(AllocatorManager.AllocatorHandle allocator)
|
||||
{
|
||||
entryList = new NativeList<Entry>(allocator) { default };
|
||||
freeEntryIndexStack = new NativeList<int>(allocator);
|
||||
entryIndexMap = new NativeHashMap<int, int>(16, allocator);
|
||||
|
||||
dirtyList = new NativeList<int>(allocator);
|
||||
tempBuffer = new NativeList<byte>(allocator);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
entryList.Dispose();
|
||||
freeEntryIndexStack.Dispose();
|
||||
entryIndexMap.Dispose();
|
||||
dirtyList.Dispose();
|
||||
tempBuffer.Dispose();
|
||||
}
|
||||
|
||||
private int AddEntry(int srcIndex)
|
||||
{
|
||||
var index = 0;
|
||||
if (freeEntryIndexStack.Length > 0)
|
||||
{
|
||||
index = freeEntryIndexStack[^1];
|
||||
freeEntryIndexStack.RemoveAt(freeEntryIndexStack.Length - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
index = entryList.Length;
|
||||
entryList.Add(default);
|
||||
}
|
||||
|
||||
entryIndexMap.Add(srcIndex, index);
|
||||
ref var entry = ref entryList.ElementAt(index);
|
||||
entry.srcIndex = srcIndex;
|
||||
entry.generation = 0;
|
||||
entry.inView = true;
|
||||
return index;
|
||||
}
|
||||
|
||||
private void ReleaseEntry(int index, int srcIndex)
|
||||
{
|
||||
freeEntryIndexStack.Add(index);
|
||||
entryIndexMap.Remove(srcIndex);
|
||||
}
|
||||
|
||||
public void UpdateDirtySet(NetDatabase.Snapshot netDatabase, int frameId)
|
||||
{
|
||||
// clear inView flag
|
||||
for (int i = 1, l = entryList.Length; i < l; ++i)
|
||||
{
|
||||
entryList.ElementAt(i).inView = false;
|
||||
}
|
||||
|
||||
var tempIntList = dirtyList;
|
||||
tempIntList.Clear();
|
||||
|
||||
// 收集旧视野中的东西,包括等待删除的
|
||||
for (int i = 1, l = entryList.Length; i < l; ++i)
|
||||
{
|
||||
ref readonly var entry = ref entryList.ElementAt(i);
|
||||
|
||||
if (entry.srcIndex == 0)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
else
|
||||
{
|
||||
tempIntList.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
var oldInViewCount = tempIntList.Length;
|
||||
|
||||
netDatabase.GatherNetDataIndex(tempIntList);
|
||||
|
||||
// 遍历 tempIntList 中新视野部分 (oldInViewCount 之后)
|
||||
{
|
||||
var j = oldInViewCount;
|
||||
for (int i = oldInViewCount, l = tempIntList.Length; i < l; ++i)
|
||||
{
|
||||
var srcIndex = tempIntList[i];
|
||||
if (entryIndexMap.TryGetValue(srcIndex, out var index))
|
||||
{
|
||||
entryList.ElementAt(index).inView = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
tempIntList[j++] = srcIndex; // 新添加的
|
||||
}
|
||||
}
|
||||
|
||||
tempIntList.Resize(j, NativeArrayOptions.UninitializedMemory);
|
||||
}
|
||||
|
||||
tempBuffer.Clear();
|
||||
var tempDirtyList = tempBuffer.ToTypedBuffer<(int, int)>();
|
||||
|
||||
// 新添加的加入dirty list
|
||||
for (int i = oldInViewCount, l = tempIntList.Length; i < l; ++i)
|
||||
{
|
||||
var srcIndex = tempIntList[i];
|
||||
var index = AddEntry(srcIndex);
|
||||
tempDirtyList.Add((int.MinValue, index));
|
||||
}
|
||||
|
||||
for (var i = 0; i < oldInViewCount; ++i)
|
||||
{
|
||||
var index = tempIntList[i];
|
||||
ref var entry = ref entryList.ElementAt(index);
|
||||
if (!entry.inView)
|
||||
{
|
||||
if (entry.srcIndex != 0)
|
||||
{
|
||||
ReleaseEntry(index, entry.srcIndex);
|
||||
var srcIndex = entry.srcIndex;
|
||||
entry.generation = 0;
|
||||
entry.srcIndex = 0;
|
||||
|
||||
//TODO parentIndex
|
||||
}
|
||||
|
||||
if (entry.confirmedFrameId < entry.deleteFrameId)
|
||||
{
|
||||
// 如果删除没有得到确认,那就标记 inView,保证发送删除操作
|
||||
entry.inView = true;
|
||||
tempDirtyList.Add((0, index));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
//TODO
|
||||
}
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e15dc0c921b45ec98b8428a748fee1e
|
||||
timeCreated: 1767301633
|
||||
@@ -0,0 +1,44 @@
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace GameCore.Network
|
||||
{
|
||||
public readonly struct FrameHistoryItem
|
||||
{
|
||||
public readonly ulong mask;
|
||||
public readonly int frameId;
|
||||
|
||||
public const int kMaxBitCount = 64;
|
||||
|
||||
public bool IsDirty => mask != 0ul;
|
||||
|
||||
private FrameHistoryItem(ulong mask, int frameId)
|
||||
{
|
||||
this.mask = mask;
|
||||
this.frameId = frameId;
|
||||
}
|
||||
|
||||
public static unsafe FrameHistoryItem Make<T>(T baseData, T newData, NativeArray<int> fieldSizeArray, int frameId) where T : unmanaged
|
||||
{
|
||||
var basePtr = (byte*) &baseData;
|
||||
var newPtr = (byte*) &newData;
|
||||
|
||||
ulong mask = 0ul;
|
||||
var offset = 0;
|
||||
for (int i = 0, n = math.min(64, fieldSizeArray.Length); i < n; ++i)
|
||||
{
|
||||
var nextOffset = fieldSizeArray[i];
|
||||
var fieldSize = nextOffset - offset;
|
||||
if (UnsafeUtility.MemCmp(basePtr + offset, newPtr + offset, fieldSize) != 0)
|
||||
{
|
||||
mask |= 1ul << i;
|
||||
}
|
||||
|
||||
offset = nextOffset;
|
||||
}
|
||||
|
||||
return new FrameHistoryItem(mask, frameId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89511e3f5bb34d8e8dd6d7cba42f415c
|
||||
timeCreated: 1767080177
|
||||
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using GameCore.LowLevel;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace GameCore.Network
|
||||
{
|
||||
public partial struct NetDatabase
|
||||
{
|
||||
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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 00a87772eaf0440eacc57a8efcad5707
|
||||
timeCreated: 1767177624
|
||||
@@ -0,0 +1,232 @@
|
||||
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 childrenListIndex;
|
||||
}
|
||||
|
||||
private NativeDataContainer<Entry> entries;
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
childrenList = new NativeList<UnsafeList<int>>(allocator) {default};
|
||||
freeChildrenListIndexStack = new NativeList<int>(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();
|
||||
|
||||
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,
|
||||
TypeMetaDatabase typeMetaDatabase) where T : unmanaged
|
||||
{
|
||||
var typeIndex = typeMetaDatabase.TypeIndexOf<T>();
|
||||
|
||||
generation = 0;
|
||||
|
||||
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;
|
||||
|
||||
entry.parentIndex = parentIndex;
|
||||
entry.childrenListIndex = 0;
|
||||
if (parentIndex > 0)
|
||||
{
|
||||
ref var parentEntry = ref entries.ElementAt(parentIndex);
|
||||
if (parentEntry.childrenListIndex == 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return RemoveInternal(index, true);
|
||||
}
|
||||
|
||||
private bool RemoveInternal(int index, bool removeFromParent)
|
||||
{
|
||||
if (!entries.HasValue(index))
|
||||
return false;
|
||||
|
||||
ref var entry = ref entries.ElementAt(index);
|
||||
ref var dataContainer = ref dataContainers.GetRef(entry.typeIndex);
|
||||
if (!dataContainer.Free(entry.dataIndex))
|
||||
throw new Exception("Data mismatch");
|
||||
|
||||
if (entry.parentIndex > 0)
|
||||
{
|
||||
if (removeFromParent)
|
||||
{
|
||||
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)
|
||||
{
|
||||
ref var list = ref childrenList.ElementAt(entry.childrenListIndex);
|
||||
for (int i = 0, len = list.Length; i < len; ++i)
|
||||
{
|
||||
RemoveInternal(list[i], false);
|
||||
}
|
||||
|
||||
list.Clear();
|
||||
freeChildrenListIndexStack.Add(entry.childrenListIndex);
|
||||
}
|
||||
|
||||
entries.Free(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
public int GetGeneration(int index)
|
||||
{
|
||||
ref var entry = ref entries.ElementAt(index);
|
||||
return entry.generation;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a240ee2c529a484b845eb5030590debf
|
||||
timeCreated: 1766976618
|
||||
@@ -18,12 +18,12 @@ namespace GameCore.Network
|
||||
public int packetJitterMs = 300;
|
||||
public int packetDropPercentage = 10;
|
||||
|
||||
private NetworkDriver CreateDriver()
|
||||
private NetworkDriver CreateDriver(out NetworkPipeline unreliablePipeline, out NetworkPipeline reliablePipeline)
|
||||
{
|
||||
var settings = new NetworkSettings(Allocator.Temp);
|
||||
settings.WithNetworkConfigParameters(disconnectTimeoutMS: 5000);
|
||||
settings.WithReliableStageParameters(32);
|
||||
settings.WithSimulatorStageParameters(32, NetworkParameterConstants.MaxConnectAttempts,
|
||||
settings.WithSimulatorStageParameters(32, mode: ApplyMode.SentPacketsOnly,
|
||||
packetDelayMs: packetDelayMs, packetJitterMs: packetJitterMs,
|
||||
packetDropPercentage: packetDropPercentage);
|
||||
|
||||
@@ -31,24 +31,25 @@ namespace GameCore.Network
|
||||
|
||||
if (useSimulator)
|
||||
{
|
||||
driver.CreatePipeline(typeof(SimulatorPipelineStageInSend));
|
||||
driver.CreatePipeline(typeof(ReliableSequencedPipelineStage), typeof(SimulatorPipelineStageInSend));
|
||||
unreliablePipeline = driver.CreatePipeline(typeof(SimulatorPipelineStage));
|
||||
reliablePipeline = driver.CreatePipeline(typeof(ReliableSequencedPipelineStage), typeof(SimulatorPipelineStage));
|
||||
}
|
||||
else
|
||||
{
|
||||
driver.CreatePipeline(typeof(ReliableSequencedPipelineStage));
|
||||
unreliablePipeline = NetworkPipeline.Null;
|
||||
reliablePipeline = driver.CreatePipeline(typeof(ReliableSequencedPipelineStage));
|
||||
}
|
||||
|
||||
return driver;
|
||||
}
|
||||
|
||||
public NetworkDriver CreateServerDriver(string address)
|
||||
public NetworkDriver CreateServerDriver(string address, out NetworkPipeline unreliablePipeline, out NetworkPipeline reliablePipeline)
|
||||
{
|
||||
var driver = CreateDriver();
|
||||
var driver = CreateDriver(out unreliablePipeline, out reliablePipeline);
|
||||
var ok = false;
|
||||
try
|
||||
{
|
||||
if (!NetworkEndPoint.TryParse(address, (ushort)port, out var endpoint))
|
||||
if (!NetworkEndpoint.TryParse(address, (ushort)port, out var endpoint))
|
||||
{
|
||||
return default;
|
||||
}
|
||||
@@ -70,10 +71,10 @@ namespace GameCore.Network
|
||||
}
|
||||
}
|
||||
|
||||
public NetworkDriver CreateClientDriver(string address, out NetworkConnection connection)
|
||||
public NetworkDriver CreateClientDriver(string address, out NetworkConnection connection, out NetworkPipeline unreliablePipeline, out NetworkPipeline reliablePipeline)
|
||||
{
|
||||
var driver = CreateDriver();
|
||||
if (!NetworkEndPoint.TryParse(address, (ushort)port, out var endpoint))
|
||||
var driver = CreateDriver(out unreliablePipeline, out reliablePipeline);
|
||||
if (!NetworkEndpoint.TryParse(address, (ushort)port, out var endpoint))
|
||||
{
|
||||
connection = default;
|
||||
driver.Dispose();
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60aaddd5a9e34cf68dd79f1a493e34b4
|
||||
timeCreated: 1767162757
|
||||
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Jobs;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GameCore.Network.Test
|
||||
{
|
||||
public class TestNetDatabase : MonoBehaviour
|
||||
{
|
||||
public struct Troop
|
||||
{
|
||||
public float2 position;
|
||||
}
|
||||
|
||||
public struct Soldier
|
||||
{
|
||||
public int id;
|
||||
public int2 coord;
|
||||
}
|
||||
|
||||
private TypeMetaDatabase typeMetaDatabase;
|
||||
private NetDatabase netDatabase;
|
||||
private NetDatabase.Snapshot snapshot;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
typeMetaDatabase = new TypeMetaDatabase(Allocator.Persistent);
|
||||
typeMetaDatabase.RegisterType<Troop>();
|
||||
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();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
typeMetaDatabase.Dispose();
|
||||
netDatabase.Dispose();
|
||||
snapshot.Dispose();
|
||||
}
|
||||
|
||||
[BurstCompile]
|
||||
private struct UpdateJob : IJob
|
||||
{
|
||||
public TypeMetaDatabase typeMetaDatabase;
|
||||
public NetDatabase netDatabase;
|
||||
public NetDatabase.Snapshot snapshot;
|
||||
public int frameId;
|
||||
|
||||
public void Execute()
|
||||
{
|
||||
var troop = new Troop() {position = new float2(1, 2)};
|
||||
var troopIndex = netDatabase.Add(troop, frameId, 0, out var gen0, typeMetaDatabase);
|
||||
Debug.Log($"Troop {troopIndex} added, generation {gen0}");
|
||||
|
||||
var soldier = new Soldier() {id = 1, coord = new int2(1, 1)};
|
||||
var soldierIndex = netDatabase.Add(soldier, frameId, troopIndex, out var gen1, typeMetaDatabase);
|
||||
Debug.Log($"Soldier {soldierIndex} added, generation {gen1}");
|
||||
|
||||
ref readonly var soldierData = ref netDatabase.Get<Soldier>(soldierIndex, typeMetaDatabase);
|
||||
Debug.Log($"Soldier id: {soldierData.id}, coord: {soldierData.coord}");
|
||||
soldier.coord = new int2(2, 2);
|
||||
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}");
|
||||
|
||||
snapshot.CopyFrom(netDatabase);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dae5c80c53134e4689ce1b03af81f96e
|
||||
timeCreated: 1767162806
|
||||
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Unity.Burst;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace GameCore.Network
|
||||
{
|
||||
public struct TypeMetaDatabase : IDisposable
|
||||
{
|
||||
private struct TypeInfo
|
||||
{
|
||||
public int offset;
|
||||
public int fieldCount;
|
||||
}
|
||||
|
||||
private static class TypeIndexHelper
|
||||
{
|
||||
public static int currentIndex;
|
||||
}
|
||||
|
||||
private struct TypeIndex<TT>
|
||||
{
|
||||
public int index;
|
||||
|
||||
public static readonly SharedStatic<TypeIndex<TT>> Instance =
|
||||
SharedStatic<TypeIndex<TT>>.GetOrCreate<TypeIndex<TT>>();
|
||||
|
||||
[BurstDiscard]
|
||||
static void EnsureInitialized()
|
||||
{
|
||||
if (Instance.Data.index == 0)
|
||||
{
|
||||
Instance.Data.index = ++TypeIndexHelper.currentIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Get()
|
||||
{
|
||||
EnsureInitialized();
|
||||
return Instance.Data.index;
|
||||
}
|
||||
}
|
||||
|
||||
private NativeList<TypeInfo> infoList;
|
||||
private NativeList<int> sizeList;
|
||||
|
||||
public TypeMetaDatabase(AllocatorManager.AllocatorHandle allocator)
|
||||
{
|
||||
infoList = new NativeList<TypeInfo>(allocator);
|
||||
sizeList = new NativeList<int>(allocator);
|
||||
sizeList.Add(0);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
infoList.Dispose();
|
||||
sizeList.Dispose();
|
||||
}
|
||||
|
||||
public int GetTotalTypeCount()
|
||||
{
|
||||
return infoList.Length;
|
||||
}
|
||||
|
||||
public int TypeIndexOf<T>() where T : unmanaged
|
||||
{
|
||||
var typeIndex = TypeIndex<T>.Get();
|
||||
CheckTypeIndex(typeIndex);
|
||||
return typeIndex;
|
||||
}
|
||||
|
||||
public void RegisterType<T>() where T : unmanaged
|
||||
{
|
||||
var typeIndex = TypeIndex<T>.Get();
|
||||
var sizeListStartIndex = sizeList.Length;
|
||||
|
||||
var type = typeof(T);
|
||||
var fields = type.GetFields();
|
||||
var fieldOffset = 0;
|
||||
foreach (var f in fields)
|
||||
{
|
||||
if (fieldOffset != UnsafeUtility.GetFieldOffset(f))
|
||||
throw new Exception("Field offset mismatch");
|
||||
var size = UnsafeUtility.SizeOf(f.FieldType);
|
||||
fieldOffset += size;
|
||||
sizeList.Add(fieldOffset);
|
||||
}
|
||||
|
||||
if (infoList.Length <= typeIndex)
|
||||
{
|
||||
infoList.Resize(typeIndex + 1, NativeArrayOptions.ClearMemory);
|
||||
}
|
||||
infoList.ElementAt(typeIndex) = new()
|
||||
{
|
||||
offset = sizeListStartIndex,
|
||||
fieldCount = sizeList.Length - sizeListStartIndex,
|
||||
};
|
||||
}
|
||||
|
||||
public int GetTypeSize(int typeIndex)
|
||||
{
|
||||
CheckTypeIndex(typeIndex);
|
||||
var info = infoList[typeIndex];
|
||||
return sizeList[info.offset + info.fieldCount - 1];
|
||||
}
|
||||
|
||||
public int GetTypeSize<T>() where T : unmanaged
|
||||
{
|
||||
return GetTypeSize(TypeIndex<T>.Get());
|
||||
}
|
||||
|
||||
public NativeArray<int> GetFieldSizeArray(int typeIndex)
|
||||
{
|
||||
CheckTypeIndex(typeIndex);
|
||||
var info = infoList[typeIndex];
|
||||
return sizeList.AsArray().GetSubArray(info.offset, info.fieldCount);
|
||||
}
|
||||
|
||||
public NativeArray<int> GetFieldSizeArray<T>() where T : unmanaged
|
||||
{
|
||||
return GetFieldSizeArray(TypeIndex<T>.Get());
|
||||
}
|
||||
|
||||
public bool IsValid(int typeIndex)
|
||||
{
|
||||
if (typeIndex < 0 || typeIndex >= infoList.Length || infoList[typeIndex].offset == 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsValid<T>()
|
||||
{
|
||||
return IsValid(TypeIndex<T>.Get());
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
void CheckTypeIndex(int typeIndex)
|
||||
{
|
||||
if (!IsValid(typeIndex))
|
||||
throw new Exception("Invalid type index");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5c20e85b6570434bbb3ca669abfbcf24
|
||||
timeCreated: 1766999459
|
||||
@@ -2,10 +2,15 @@
|
||||
"name": "nimin.network",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"Unity.Networking.Transport"
|
||||
"Unity.Networking.Transport",
|
||||
"Unity.Collections",
|
||||
"Unity.Burst",
|
||||
"nimin.lowlevel",
|
||||
"Unity.Mathematics"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
{
|
||||
"name": "com.nimin.network",
|
||||
"displayName": "GameCore Network",
|
||||
"version": "0.1.0",
|
||||
"unity": "2021.3",
|
||||
"description": "Network based on Unity Transport",
|
||||
"dependencies": {
|
||||
"com.unity.transport": "1.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
"Network",
|
||||
"JobSystem"
|
||||
]
|
||||
"name": "com.nimin.network",
|
||||
"displayName": "GameCore Network",
|
||||
"version": "0.1.0",
|
||||
"unity": "2021.3",
|
||||
"description": "Network based on Unity Transport",
|
||||
"dependencies": {
|
||||
"com.unity.transport": "2.6.0"
|
||||
},
|
||||
"keywords": [
|
||||
"Network",
|
||||
"JobSystem"
|
||||
]
|
||||
}
|
||||
@@ -1,25 +1,30 @@
|
||||
using System;
|
||||
using Unity.Burst;
|
||||
|
||||
namespace GameCore.TinyECS
|
||||
{
|
||||
public struct ComponentId
|
||||
internal static class ComponentIdHelper
|
||||
{
|
||||
struct Inner<T> where T : unmanaged
|
||||
public static int currentId;
|
||||
}
|
||||
|
||||
public struct ComponentId<T>
|
||||
{
|
||||
public int id;
|
||||
public static readonly SharedStatic<ComponentId<T>> Instance = SharedStatic<ComponentId<T>>.GetOrCreate<ComponentId<T>>();
|
||||
|
||||
[BurstDiscard]
|
||||
static void EnsureInitialized()
|
||||
{
|
||||
public int id;
|
||||
private Inner(int i) => id = i;
|
||||
public static Inner<T> Instance = default;
|
||||
if (Instance.Data.id == 0)
|
||||
{
|
||||
Instance.Data.id = ++ComponentIdHelper.currentId;
|
||||
}
|
||||
}
|
||||
|
||||
static int currentId;
|
||||
|
||||
public static int Get<T>() where T : unmanaged
|
||||
public static int Get()
|
||||
{
|
||||
if (Inner<T>.Instance.id == 0)
|
||||
{
|
||||
Inner<T>.Instance.id = ++currentId;
|
||||
}
|
||||
return Inner<T>.Instance.id;
|
||||
EnsureInitialized();
|
||||
return Instance.Data.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using GameCore.LowLevel;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace GameCore.TinyECS
|
||||
{
|
||||
public readonly struct Entity<TEnum> : IEquatable<Entity<TEnum>> where TEnum : unmanaged
|
||||
public readonly struct Entity<TEnum> : IEquatable<Entity<TEnum>> where TEnum : unmanaged, IConvertible
|
||||
{
|
||||
public readonly TEnum type;
|
||||
public readonly int index;
|
||||
@@ -19,7 +20,7 @@ namespace GameCore.TinyECS
|
||||
public override string ToString() => $"Entity<{type}>({index},{generation})";
|
||||
public bool Equals(Entity<TEnum> other) => type.Equals(other.type) && index == other.index && generation == other.generation;
|
||||
public override bool Equals(object obj) => obj is Entity<TEnum> other && Equals(other);
|
||||
public override int GetHashCode() => LowLevelUtility.HashCombine(type.GetHashCode(), index, generation);
|
||||
public override int GetHashCode() => LowLevelUtility.HashCombine(UnsafeUtility.EnumToInt(type), index, generation);
|
||||
public static bool operator ==(Entity<TEnum> lhs, Entity<TEnum> rhs) => lhs.Equals(rhs);
|
||||
public static bool operator !=(Entity<TEnum> lhs, Entity<TEnum> rhs) => !(lhs == rhs);
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using System.Diagnostics;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
|
||||
namespace GameCore.TinyECS
|
||||
{
|
||||
public struct EntityCollection<TEnum> : IDisposable where TEnum : unmanaged
|
||||
public struct EntityCollection<TEnum> : IDisposable
|
||||
where TEnum : unmanaged, IConvertible
|
||||
{
|
||||
private struct Buffer
|
||||
{
|
||||
@@ -12,11 +14,12 @@ namespace GameCore.TinyECS
|
||||
public int generation;
|
||||
}
|
||||
|
||||
public readonly TEnum entityType;
|
||||
|
||||
private NativeList<Buffer> entityBuffer;
|
||||
private NativeList<int> entityIndexToDataIndex;
|
||||
private TEnum entityType;
|
||||
|
||||
public EntityCollection(TEnum type, int capacity, Allocator allocator)
|
||||
public EntityCollection(TEnum type, int capacity, AllocatorManager.AllocatorHandle allocator)
|
||||
{
|
||||
entityType = type;
|
||||
entityBuffer = new (capacity, allocator);
|
||||
@@ -60,6 +63,25 @@ namespace GameCore.TinyECS
|
||||
return dataIndex;
|
||||
}
|
||||
|
||||
public int GetIndex(Entity<TEnum> entity)
|
||||
{
|
||||
CheckEntityType(entity);
|
||||
|
||||
if (entity.index >= entityIndexToDataIndex.Length)
|
||||
{
|
||||
throw new Exception($"Invalid entity: {entity}");
|
||||
}
|
||||
|
||||
var index = entityIndexToDataIndex[entity.index];
|
||||
var buf = entityBuffer[index];
|
||||
if (buf.index != entity.index || buf.generation != entity.generation)
|
||||
{
|
||||
throw new Exception($"Invalid entity: {entity}");
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public bool TryGetIndex(Entity<TEnum> entity, out int index)
|
||||
{
|
||||
CheckEntityType(entity);
|
||||
@@ -115,7 +137,7 @@ namespace GameCore.TinyECS
|
||||
[Conditional("DEBUG")]
|
||||
void CheckEntityType(Entity<TEnum> entity)
|
||||
{
|
||||
if (!entity.type.Equals(entityType))
|
||||
if (!UnsafeUtility.EnumEquals(entityType, entity.type))
|
||||
throw new Exception($"Wrong entity type: {entity.type}");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 24392c1216204b6ea64acd57bb43441b
|
||||
timeCreated: 1668251924
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9227b743e78463b8df770cefc98fb18
|
||||
timeCreated: 1668274486
|
||||
@@ -1,14 +0,0 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace GameCore.TinyECS
|
||||
{
|
||||
public struct EntityDataSet : IDisposable
|
||||
{
|
||||
public void Dispose()
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
-9
@@ -13,28 +13,31 @@ namespace GameCore.TinyECS
|
||||
public int elementAlign;
|
||||
}
|
||||
|
||||
public unsafe struct EntityDataBlockChain : IDisposable
|
||||
public unsafe struct EntityDataBlockChain : IEntityDataStruct
|
||||
{
|
||||
public readonly EntityDataBlockMeta blockMeta;
|
||||
private FixedList512Bytes<IntPtr> blockPtrList;
|
||||
private int maxElementCountPerBlock;
|
||||
private int elementCount;
|
||||
private AllocatorManager.AllocatorHandle allocator;
|
||||
|
||||
public int BlockCount => blockPtrList.Length;
|
||||
public int BlockCapacity => blockPtrList.Capacity;
|
||||
public int ElementCount => elementCount;
|
||||
public int MaxElementCount => MaxElementCountPerBlock * BlockCapacity;
|
||||
public int MaxElementCountPerBlock => maxElementCountPerBlock;
|
||||
public AllocatorManager.AllocatorHandle Allocator => allocator;
|
||||
|
||||
public bool IsFull => elementCount == MaxElementCount;
|
||||
public bool IsEmpty => elementCount == 0;
|
||||
|
||||
public EntityDataBlockChain(EntityDataBlockMeta blockMeta, int maxElementCountPerBlock)
|
||||
|
||||
public EntityDataBlockChain(EntityDataBlockMeta blockMeta, AllocatorManager.AllocatorHandle allocator, int maxElementCountPerBlock = 1024)
|
||||
{
|
||||
this.blockMeta = blockMeta;
|
||||
blockPtrList = default;
|
||||
this.maxElementCountPerBlock = maxElementCountPerBlock;
|
||||
elementCount = 0;
|
||||
this.allocator = allocator;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
@@ -48,7 +51,7 @@ namespace GameCore.TinyECS
|
||||
void AllocBlock()
|
||||
{
|
||||
var bufferSize = blockMeta.elementSize * maxElementCountPerBlock;
|
||||
var ptr = UnsafeUtility.Malloc(bufferSize, blockMeta.elementAlign, Allocator.Persistent);
|
||||
var ptr = AllocatorManager.Allocate(allocator, bufferSize, blockMeta.elementAlign);
|
||||
|
||||
blockPtrList.Add((IntPtr)ptr);
|
||||
}
|
||||
@@ -58,7 +61,7 @@ namespace GameCore.TinyECS
|
||||
var pBlock = (void*)blockPtrList[blockIndex];
|
||||
if (pBlock != null)
|
||||
{
|
||||
UnsafeUtility.Free(pBlock, Allocator.Persistent);
|
||||
AllocatorManager.Free(allocator, pBlock);
|
||||
blockPtrList.RemoveAt(blockIndex);
|
||||
}
|
||||
}
|
||||
@@ -72,7 +75,7 @@ namespace GameCore.TinyECS
|
||||
|
||||
void* ComponentPtrAt<T>(int elementIndex) where T : unmanaged
|
||||
{
|
||||
var componentId = ComponentId.Get<T>();
|
||||
var componentId = ComponentId<T>.Get();
|
||||
var componentIndex = blockMeta.componentIdToIndex[componentId];
|
||||
if (componentIndex > 0)
|
||||
{
|
||||
@@ -133,7 +136,16 @@ namespace GameCore.TinyECS
|
||||
elementCount--;
|
||||
}
|
||||
|
||||
public ref T GetData<T>(int index) where T : unmanaged
|
||||
public T GetData<T>(int index) where T : unmanaged
|
||||
{
|
||||
CheckElementIndex(index);
|
||||
var pComponent = ComponentPtrAt<T>(index);
|
||||
if (pComponent == null)
|
||||
throw new Exception($"Invalid component type: {typeof(T)}");
|
||||
return UnsafeUtility.AsRef<T>(pComponent);
|
||||
}
|
||||
|
||||
public ref T GetDataRef<T>(int index) where T : unmanaged
|
||||
{
|
||||
CheckElementIndex(index);
|
||||
var pComponent = ComponentPtrAt<T>(index);
|
||||
@@ -150,7 +162,7 @@ namespace GameCore.TinyECS
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe readonly struct EntityDataBlockView
|
||||
public readonly unsafe struct EntityDataBlockView
|
||||
{
|
||||
private readonly void* ptr;
|
||||
public readonly EntityDataBlockMeta meta;
|
||||
@@ -172,7 +184,7 @@ namespace GameCore.TinyECS
|
||||
|
||||
void* ComponentPtrAt<T>(int elementIndex) where T : unmanaged
|
||||
{
|
||||
var componentId = ComponentId.Get<T>();
|
||||
var componentId = ComponentId<T>.Get();
|
||||
var componentIndex = meta.componentIdToIndex[componentId];
|
||||
if (componentIndex > 0)
|
||||
{
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 694d8256118344eb2b130fceb1a11b7f
|
||||
guid: 7b0b5bb1c56f2114ba60d9154d447872
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
+3
-3
@@ -15,7 +15,7 @@ namespace GameCore.TinyECS
|
||||
meta.componentIdToIndex.Length = meta.componentIdToIndex.Capacity;
|
||||
meta.componentIdToOffset.Length = meta.componentIdToOffset.Capacity;
|
||||
|
||||
var id1 = ComponentId.Get<T1>();
|
||||
var id1 = ComponentId<T1>.Get();
|
||||
meta.componentIdToIndex[id1] = 1;
|
||||
meta.componentIdToOffset[id1] = 0;
|
||||
meta.elementSize = UnsafeUtility.SizeOf<T1>();
|
||||
@@ -31,8 +31,8 @@ namespace GameCore.TinyECS
|
||||
meta.componentIdToIndex.Length = meta.componentIdToIndex.Capacity;
|
||||
meta.componentIdToOffset.Length = meta.componentIdToOffset.Capacity;
|
||||
|
||||
var id1 = ComponentId.Get<T1>();
|
||||
var id2 = ComponentId.Get<T2>();
|
||||
var id1 = ComponentId<T1>.Get();
|
||||
var id2 = ComponentId<T2>.Get();
|
||||
meta.componentIdToIndex[id1] = 1;
|
||||
meta.componentIdToIndex[id2] = 2;
|
||||
meta.componentIdToOffset[id1] = (short)LowLevelUtility.OffsetOf<(T1, T2), T1>();
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68aafcef1265449e6b6b2dd81d7173a8
|
||||
guid: 747b2bec360ee8141b0b46886b09f92d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
|
||||
namespace GameCore.TinyECS
|
||||
{
|
||||
public interface IEntityDataStruct : IDisposable
|
||||
{
|
||||
AllocatorManager.AllocatorHandle Allocator { get; }
|
||||
|
||||
void Add();
|
||||
void Remove(int index);
|
||||
|
||||
T GetData<T>(int index) where T : unmanaged;
|
||||
ref T GetDataRef<T>(int index) where T : unmanaged;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 933c4528e6cf415dbfb79a148896839d
|
||||
timeCreated: 1765943532
|
||||
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace GameCore.TinyECS
|
||||
{
|
||||
public struct EntityDatabase<TEnum, TData> : IDisposable
|
||||
where TEnum : unmanaged, IConvertible
|
||||
where TData : unmanaged, IEntityDataStruct
|
||||
{
|
||||
public TData dataStruct;
|
||||
public EntityGenerator<TEnum> generator;
|
||||
public EntityCollection<TEnum> collection;
|
||||
|
||||
public int Count => collection.Count;
|
||||
|
||||
internal EntityDatabase(TEnum type, TData dataStruct, int initCapacity,
|
||||
AllocatorManager.AllocatorHandle allocator)
|
||||
{
|
||||
generator = new(type, initCapacity, allocator);
|
||||
collection = new(type, initCapacity, allocator);
|
||||
this.dataStruct = dataStruct;
|
||||
}
|
||||
|
||||
public Entity<TEnum> AddEntity()
|
||||
{
|
||||
var entity = generator.Create();
|
||||
collection.Add(entity);
|
||||
dataStruct.Add();
|
||||
return entity;
|
||||
}
|
||||
|
||||
public void RemoveEntity(Entity<TEnum> entity)
|
||||
{
|
||||
generator.Delete(entity);
|
||||
if (collection.Remove(entity, out var index, out var _))
|
||||
dataStruct.Remove(index);
|
||||
}
|
||||
|
||||
public T GetData<T>(Entity<TEnum> entity) where T : unmanaged
|
||||
{
|
||||
var index = collection.GetIndex(entity);
|
||||
return dataStruct.GetData<T>(index);
|
||||
}
|
||||
|
||||
public ref T GetDataRef<T>(Entity<TEnum> entity) where T : unmanaged
|
||||
{
|
||||
var index = collection.GetIndex(entity);
|
||||
return ref dataStruct.GetDataRef<T>(index);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
generator.Dispose();
|
||||
collection.Dispose();
|
||||
dataStruct.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public static class EntityDataBaseExtensions
|
||||
{
|
||||
public static EntityDatabase<TEnum, TData> CreateEntityDatabase<TEnum, TData>(this TData dataStruct, TEnum type, int initCapacity)
|
||||
where TEnum : unmanaged, IConvertible
|
||||
where TData : unmanaged, IEntityDataStruct
|
||||
{
|
||||
return new EntityDatabase<TEnum, TData>(type, dataStruct, initCapacity, dataStruct.Allocator);
|
||||
}
|
||||
}
|
||||
}
|
||||
File renamed without changes.
@@ -4,14 +4,15 @@ using Unity.Mathematics;
|
||||
|
||||
namespace GameCore.TinyECS
|
||||
{
|
||||
public struct EntityGenerator<TEnum> : IDisposable where TEnum : unmanaged
|
||||
public struct EntityGenerator<TEnum> : IDisposable
|
||||
where TEnum : unmanaged, IConvertible
|
||||
{
|
||||
public readonly TEnum entityType;
|
||||
private NativeList<int> indexToGeneration;
|
||||
private int beginSearchIndex;
|
||||
private int freeCount;
|
||||
private TEnum entityType;
|
||||
|
||||
public EntityGenerator(TEnum type, int capacity, Allocator allocator)
|
||||
public EntityGenerator(TEnum type, int capacity, AllocatorManager.AllocatorHandle allocator)
|
||||
{
|
||||
indexToGeneration = new(capacity, allocator) { 0 };
|
||||
beginSearchIndex = 1;
|
||||
|
||||
@@ -4,25 +4,10 @@
|
||||
"references": [
|
||||
"Unity.Collections",
|
||||
"Unity.Mathematics",
|
||||
"nimin.lowlevel"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Android",
|
||||
"Editor",
|
||||
"iOS",
|
||||
"LinuxStandalone64",
|
||||
"Lumin",
|
||||
"macOSStandalone",
|
||||
"PS4",
|
||||
"Stadia",
|
||||
"Switch",
|
||||
"tvOS",
|
||||
"WSA",
|
||||
"WebGL",
|
||||
"WindowsStandalone32",
|
||||
"WindowsStandalone64",
|
||||
"XboxOne"
|
||||
"nimin.lowlevel",
|
||||
"Unity.Burst"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
|
||||
+24
-13
@@ -14,7 +14,7 @@
|
||||
"depth": 0,
|
||||
"source": "local",
|
||||
"dependencies": {
|
||||
"com.unity.transport": "1.0.0"
|
||||
"com.unity.transport": "2.6.0"
|
||||
}
|
||||
},
|
||||
"com.nimin.tinyecs": {
|
||||
@@ -26,8 +26,8 @@
|
||||
}
|
||||
},
|
||||
"com.unity.burst": {
|
||||
"version": "1.8.21",
|
||||
"depth": 1,
|
||||
"version": "1.8.24",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.mathematics": "1.2.1",
|
||||
@@ -36,13 +36,14 @@
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.collections": {
|
||||
"version": "1.4.0",
|
||||
"depth": 1,
|
||||
"version": "2.2.1",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.burst": "1.6.6",
|
||||
"com.unity.test-framework": "1.1.31",
|
||||
"com.unity.nuget.mono-cecil": "1.11.4"
|
||||
"com.unity.burst": "1.8.8",
|
||||
"com.unity.nuget.mono-cecil": "1.11.4",
|
||||
"com.unity.modules.unityanalytics": "1.0.0",
|
||||
"com.unity.test-framework.performance": "3.0.2"
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
@@ -109,7 +110,7 @@
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.mathematics": {
|
||||
"version": "1.2.6",
|
||||
"version": "1.3.2",
|
||||
"depth": 2,
|
||||
"source": "registry",
|
||||
"dependencies": {},
|
||||
@@ -147,6 +148,16 @@
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.test-framework.performance": {
|
||||
"version": "3.0.2",
|
||||
"depth": 3,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.test-framework": "1.1.31",
|
||||
"com.unity.modules.jsonserialize": "1.0.0"
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.testtools.codecoverage": {
|
||||
"version": "1.2.6",
|
||||
"depth": 1,
|
||||
@@ -179,13 +190,13 @@
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
"com.unity.transport": {
|
||||
"version": "1.5.0",
|
||||
"version": "2.6.0",
|
||||
"depth": 1,
|
||||
"source": "registry",
|
||||
"dependencies": {
|
||||
"com.unity.burst": "1.6.6",
|
||||
"com.unity.collections": "1.2.4",
|
||||
"com.unity.mathematics": "1.2.6"
|
||||
"com.unity.burst": "1.8.24",
|
||||
"com.unity.collections": "2.2.1",
|
||||
"com.unity.mathematics": "1.3.2"
|
||||
},
|
||||
"url": "https://packages.unity.com"
|
||||
},
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASystem_002Ecs_002Fl_003AC_0021_003FUsers_003Fsunqinzhe_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F3ea01e77be99618395f448b16bd7cc2bd4248bd9e5d8474964b2d97f39c5d74_003FSystem_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AAllocator_002Ecs_002Fl_003AC_0021_003FUsers_003Fsunqinzhe_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F37cc348edc804f4cb176b63962c716e7177200_003Fa6_003F9ff064e4_003FAllocator_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABurstCompilerService_002Ecs_002Fl_003AC_0021_003FUsers_003Fsunqinzhe_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F37cc348edc804f4cb176b63962c716e7177200_003F87_003F6fa23538_003FBurstCompilerService_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AJobsUtility_002Ecs_002Fl_003AC_0021_003FUsers_003Fsunqinzhe_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F37cc348edc804f4cb176b63962c716e7177200_003F4c_003Fe16da97b_003FJobsUtility_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANativeArrayOptions_002Ecs_002Fl_003AC_0021_003FUsers_003Fsunqinzhe_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F37cc348edc804f4cb176b63962c716e7177200_003Fdb_003F0b3876fe_003FNativeArrayOptions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASystem_002Ecs_002Fl_003AC_0021_003FUsers_003Fsunqinzhe_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FSourcesCache_003F3ea01e77be99618395f448b16bd7cc2bd4248bd9e5d8474964b2d97f39c5d74_003FSystem_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AUnsafeUtility_002Ecs_002Fl_003AC_0021_003FUsers_003Fsunqinzhe_003FAppData_003FRoaming_003FJetBrains_003FRider2024_002E3_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F37cc348edc804f4cb176b63962c716e7177200_003F8b_003F35bd5f7e_003FUnsafeUtility_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
||||
Reference in new issue
Block a user