iFactory.Cutting.Unity/Assets/BITKit/Unity/Scripts/Entity/Net/EntitiesNetService.cs

173 lines
5.0 KiB
C#
Raw Normal View History

2024-01-23 02:56:26 +08:00
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Timers;
using BITKit.Entities.Player;
using UnityEngine;
namespace BITKit.Entities
{
[Serializable]
public struct EntitiesNetSyncCommand
{
public byte[] Data;
}
[Serializable]
public struct EntitiesNetSyncBatchCommand
{
public int Length;
2024-04-22 03:48:37 +08:00
public int[] Ids;
2024-01-23 02:56:26 +08:00
public ulong[] AddressablePaths;
public EntitiesNetSyncCommand[] Commands;
}
public class EntitiesNetService : MonoBehaviour
{
[Header(Constant.Header.Services)]
[SerializeReference, SubclassSelector] private ITicker ticker;
[SerializeReference, SubclassSelector] private IEntitiesService entitiesService;
[SerializeReference, SubclassSelector] private IPlayerService playerService;
[SerializeReference, SubclassSelector]private INetClient client;
[SerializeReference, SubclassSelector]private INetServer server;
private INetProvider clientNetProvider => client.Source as INetProvider;
private INetProvider serverNetProvider => server.Source as INetProvider;
[Inject]
private IEntityBinaryHeader _playerHeader;
[Inject] private IAddressable _playerAddressable;
[Inject]
private IEntity _playerEntity;
private readonly ConcurrentQueue<EntitiesNetSyncBatchCommand> _batchCommands = new();
private readonly ConcurrentQueue<EntitiesNetSyncCommand> _syncCommands = new();
private void Start()
{
ticker.Add(Tick);
clientNetProvider.AddCommandListener<EntitiesNetSyncBatchCommand>(_batchCommands.Enqueue);
serverNetProvider.AddCommandListener<EntitiesNetSyncCommand>(_syncCommands.Enqueue);
playerService.OnPlayerInitialized+=OnPlayerInitialized;
playerService.OnPlayerDisposed += OnPlayerDisposed;
destroyCancellationToken.Register(() =>
{
ticker.Remove(Tick);
playerService.OnPlayerInitialized-=OnPlayerInitialized;
});
}
private void OnPlayerDisposed(Entity obj)
{
_playerHeader = null;
_playerAddressable = null;
_playerEntity = null;
}
private void OnPlayerInitialized(Entity obj)
{
obj.Inject(this);
}
private void OnSyncCommand(EntitiesNetSyncCommand obj)
{
using var ms = new MemoryStream(obj.Data);
using var reader = new BinaryReader(ms);
2024-04-22 03:48:37 +08:00
var id = reader.ReadInt32();
2024-01-23 02:56:26 +08:00
var path = reader.ReadUInt64();
entitiesService.GetOrAdd(id, x => AddEntity(id, path)).TryGetComponent<IEntityBinaryHeader>(out var header);
header.Deserialize(reader);
}
private void OnBatchCommand(EntitiesNetSyncBatchCommand obj)
{
for (var i = 0; i < obj.Length; i++)
{
var id = obj.Ids[i];
var path = obj.AddressablePaths[i];
var command = obj.Commands[i];
var entity = entitiesService.GetOrAdd(id,x=>AddEntity(id,path));
entity.TryGetComponent<IEntityBinaryHeader>(out var header);
using var ms = new MemoryStream(command.Data);
using var reader = new BinaryReader(ms);
header.Deserialize(reader);
}
}
2024-04-22 03:48:37 +08:00
private static IEntity AddEntity(int id,ulong addressableId)
2024-01-23 02:56:26 +08:00
{
var entity = AddressableHelper.Get<GameObject>(addressableId);
var instance = Instantiate(entity).GetComponent<Entity>();
instance.Id = id;
instance.WaitForInitializationComplete();
return instance;
}
private void Tick(float deltaTime)
{
while (_batchCommands.TryDequeue(out var command))
{
OnBatchCommand(command);
}
while (_syncCommands.TryDequeue(out var command))
{
OnSyncCommand(command);
}
if (client.IsConnected is false && server.IsRunningServer is false) return;
using var memoryStream = new MemoryStream();
if (client.IsConnected && _playerEntity as Entity && _playerHeader != null)
{
using var writer = new BinaryWriter(memoryStream);
writer.Write(_playerEntity.Id);
writer.Write(_playerAddressable.AddressableId);
_playerHeader.Serialize(writer);
var command = new EntitiesNetSyncCommand
{
Data = memoryStream.ToArray()
};
clientNetProvider.ServerCommand(command);
}
else if (server.IsRunningServer)
{
using var writer = new BinaryWriter(memoryStream);
var headers = entitiesService.QueryComponents<IEntity, IEntityBinaryHeader, IAddressable>();
var batchCommand = new EntitiesNetSyncBatchCommand()
{
Length = headers.Length,
2024-04-22 03:48:37 +08:00
Ids = new int[headers.Length],
2024-01-23 02:56:26 +08:00
AddressablePaths = new ulong[headers.Length],
Commands = new EntitiesNetSyncCommand[headers.Length]
};
var count = -1;
foreach (var (entity, header, addressable) in headers)
{
count++;
using var ms = new MemoryStream();
using var entityWriter = new BinaryWriter(ms);
header.Serialize(entityWriter);
entityWriter.Flush();
batchCommand.Ids[count] = entity.Id;
batchCommand.AddressablePaths[count] = addressable.AddressableId;
batchCommand.Commands[count] = new EntitiesNetSyncCommand { Data = ms.ToArray() };
}
serverNetProvider.AllClientCommand(batchCommand);
}
}
}
}