mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-14 16:51:28 +00:00
[+] 接入ET8服务端
[+] 接入ET8服务端
This commit is contained in:
8
Assets/GameScripts/DotNet/Hotfix/Client/Demo.meta
Normal file
8
Assets/GameScripts/DotNet/Hotfix/Client/Demo.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4cb05eea2613caf458483a4ce7afbf94
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/GameScripts/DotNet/Hotfix/Client/Demo/AI.meta
Normal file
8
Assets/GameScripts/DotNet/Hotfix/Client/Demo/AI.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d2c1d7db177785844a4b941708d953b9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
43
Assets/GameScripts/DotNet/Hotfix/Client/Demo/AI/AI_Attack.cs
Normal file
43
Assets/GameScripts/DotNet/Hotfix/Client/Demo/AI/AI_Attack.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
public class AI_Attack: AAIHandler
|
||||
{
|
||||
public override int Check(AIComponent aiComponent, AIConfig aiConfig)
|
||||
{
|
||||
long sec = aiComponent.Fiber().TimeInfo.ClientNow() / 1000 % 15;
|
||||
if (sec >= 10)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public override async ETTask Execute(AIComponent aiComponent, AIConfig aiConfig, ETCancellationToken cancellationToken)
|
||||
{
|
||||
Fiber fiber = aiComponent.Fiber();
|
||||
|
||||
Unit myUnit = UnitHelper.GetMyUnitFromClientScene(fiber.Root);
|
||||
if (myUnit == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 停在当前位置
|
||||
fiber.Root.GetComponent<ClientSenderCompnent>().Send(new C2M_Stop());
|
||||
|
||||
Log.Debug("开始攻击");
|
||||
|
||||
for (int i = 0; i < 100000; ++i)
|
||||
{
|
||||
Log.Debug($"攻击: {i}次");
|
||||
|
||||
// 因为协程可能被中断,任何协程都要传入cancellationToken,判断如果是中断则要返回
|
||||
await fiber.TimerComponent.WaitAsync(1000, cancellationToken);
|
||||
if (cancellationToken.IsCancel())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de532cb8e5e687a4bb61aa666459d086
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
42
Assets/GameScripts/DotNet/Hotfix/Client/Demo/AI/AI_XunLuo.cs
Normal file
42
Assets/GameScripts/DotNet/Hotfix/Client/Demo/AI/AI_XunLuo.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
public class AI_XunLuo: AAIHandler
|
||||
{
|
||||
public override int Check(AIComponent aiComponent, AIConfig aiConfig)
|
||||
{
|
||||
long sec = aiComponent.Fiber().TimeInfo.ClientNow() / 1000 % 15;
|
||||
if (sec < 10)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public override async ETTask Execute(AIComponent aiComponent, AIConfig aiConfig, ETCancellationToken cancellationToken)
|
||||
{
|
||||
Scene root = aiComponent.Root();
|
||||
|
||||
Unit myUnit = UnitHelper.GetMyUnitFromClientScene(root);
|
||||
if (myUnit == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Log.Debug("开始巡逻");
|
||||
|
||||
while (true)
|
||||
{
|
||||
XunLuoPathComponent xunLuoPathComponent = myUnit.GetComponent<XunLuoPathComponent>();
|
||||
float3 nextTarget = xunLuoPathComponent.GetCurrent();
|
||||
await myUnit.MoveToAsync(nextTarget, cancellationToken);
|
||||
if (cancellationToken.IsCancel())
|
||||
{
|
||||
return;
|
||||
}
|
||||
xunLuoPathComponent.MoveNext();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d77ea7dfe040894aa330386e3b7bb8f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,18 @@
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
[FriendOf(typeof(XunLuoPathComponent))]
|
||||
public static partial class XunLuoPathComponentSystem
|
||||
{
|
||||
public static float3 GetCurrent(this XunLuoPathComponent self)
|
||||
{
|
||||
return self.path[self.Index];
|
||||
}
|
||||
|
||||
public static void MoveNext(this XunLuoPathComponent self)
|
||||
{
|
||||
self.Index = ++self.Index % self.path.Length;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4293e004a928ffb43bf52f374808d139
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
3
Assets/GameScripts/DotNet/Hotfix/Client/Demo/Main.meta
Normal file
3
Assets/GameScripts/DotNet/Hotfix/Client/Demo/Main.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2e5141370ec84e1282c5d0a38f2ef25b
|
||||
timeCreated: 1688537612
|
@@ -0,0 +1,47 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[EntitySystemOf(typeof(ClientSenderCompnent))]
|
||||
[FriendOf(typeof(ClientSenderCompnent))]
|
||||
public static partial class ClientSenderCompnentSystem
|
||||
{
|
||||
[EntitySystem]
|
||||
private static void Awake(this ClientSenderCompnent self)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[EntitySystem]
|
||||
private static void Destroy(this ClientSenderCompnent self)
|
||||
{
|
||||
if (self.fiberId != 0)
|
||||
{
|
||||
FiberManager.Instance.Remove(self.fiberId);
|
||||
}
|
||||
}
|
||||
|
||||
public static async ETTask<long> LoginAsync(this ClientSenderCompnent self, string account, string password)
|
||||
{
|
||||
self.fiberId = await FiberManager.Instance.Create(SchedulerType.ThreadPool, 0, SceneType.NetClient, "");
|
||||
self.netClientActorId = new ActorId(self.Fiber().Process, self.fiberId);
|
||||
|
||||
NetClient2Main_Login response = await self.Fiber().ActorInnerComponent.Call(self.netClientActorId, new Main2NetClient_Login() { Account = account, Password = password }) as NetClient2Main_Login;
|
||||
return response.PlayerId;
|
||||
}
|
||||
|
||||
public static void Send(this ClientSenderCompnent self, IMessage message)
|
||||
{
|
||||
A2NetClient_Message a2NetClientMessage = A2NetClient_Message.Create();
|
||||
a2NetClientMessage.MessageObject = message;
|
||||
self.Fiber().ActorInnerComponent.Send(self.netClientActorId, a2NetClientMessage);
|
||||
}
|
||||
|
||||
public static async ETTask<IResponse> Call(this ClientSenderCompnent self, IRequest request, bool needException = true)
|
||||
{
|
||||
A2NetClient_Request a2NetClientRequest = A2NetClient_Request.Create();
|
||||
a2NetClientRequest.MessageObject = request;
|
||||
A2NetClient_Response response = await self.Fiber().ActorInnerComponent.Call(self.netClientActorId, a2NetClientRequest, needException: needException) as A2NetClient_Response;
|
||||
return response.MessageObject;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a11bff036359a2143aca1de23150ce40
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c38213e2fca6b8b489ffb3fee170c51f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
public static partial class EnterMapHelper
|
||||
{
|
||||
public static async ETTask EnterMapAsync(Scene root)
|
||||
{
|
||||
try
|
||||
{
|
||||
G2C_EnterMap g2CEnterMap = await root.GetComponent<ClientSenderCompnent>().Call(new C2G_EnterMap()) as G2C_EnterMap;
|
||||
|
||||
// 等待场景切换完成
|
||||
await root.GetComponent<ObjectWait>().Wait<Wait_SceneChangeFinish>();
|
||||
|
||||
EventSystem.Instance.Publish(root, new EventType.EnterMapFinish());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static async ETTask Match(Fiber fiber)
|
||||
{
|
||||
try
|
||||
{
|
||||
G2C_Match g2CEnterMap = await fiber.Root.GetComponent<ClientSenderCompnent>().Call(new C2G_Match()) as G2C_Match;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25a13c7e1f3127848a33352576e747c9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0e5f376ea66398e4f8d5fc5d700b4373
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,15 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[ActorMessageHandler(SceneType.Demo)]
|
||||
public class M2C_PathfindingResultHandler : ActorMessageHandler<Scene, M2C_PathfindingResult>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, M2C_PathfindingResult message)
|
||||
{
|
||||
Unit unit = root.CurrentScene().GetComponent<UnitComponent>().Get(message.Id);
|
||||
|
||||
float speed = unit.GetComponent<NumericComponent>().GetAsFloat(NumericType.Speed);
|
||||
|
||||
await unit.GetComponent<MoveComponent>().MoveToAsync(message.Points, speed);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46ac4bf2b7bf6ea468ccbfbf09367733
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,24 @@
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
[ActorMessageHandler(SceneType.Demo)]
|
||||
public class M2C_StopHandler : ActorMessageHandler<Scene, M2C_Stop>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, M2C_Stop message)
|
||||
{
|
||||
Unit unit = root.CurrentScene().GetComponent<UnitComponent>().Get(message.Id);
|
||||
if (unit == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
MoveComponent moveComponent = unit.GetComponent<MoveComponent>();
|
||||
moveComponent.Stop(message.Error == 0);
|
||||
unit.Position = message.Position;
|
||||
unit.Rotation = message.Rotation;
|
||||
unit.GetComponent<ObjectWait>()?.Notify(new Wait_UnitStop() {Error = message.Error});
|
||||
await ETTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb3ae6bd37192c648b88723824beaaa7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,36 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
public static partial class MoveHelper
|
||||
{
|
||||
// 可以多次调用,多次调用的话会取消上一次的协程
|
||||
public static async ETTask<int> MoveToAsync(this Unit unit, float3 targetPos, ETCancellationToken cancellationToken = null)
|
||||
{
|
||||
C2M_PathfindingResult msg = new C2M_PathfindingResult() { Position = targetPos };
|
||||
unit.Root().GetComponent<ClientSenderCompnent>().Send(msg);
|
||||
|
||||
ObjectWait objectWait = unit.GetComponent<ObjectWait>();
|
||||
|
||||
// 要取消上一次的移动协程
|
||||
objectWait.Notify(new Wait_UnitStop() { Error = WaitTypeError.Cancel });
|
||||
|
||||
// 一直等到unit发送stop
|
||||
Wait_UnitStop waitUnitStop = await objectWait.Wait<Wait_UnitStop>(cancellationToken);
|
||||
if (cancellationToken.IsCancel())
|
||||
{
|
||||
return WaitTypeError.Cancel;
|
||||
}
|
||||
return waitUnitStop.Error;
|
||||
}
|
||||
|
||||
public static async ETTask MoveToAsync(this Unit unit, List<float3> path)
|
||||
{
|
||||
float speed = unit.GetComponent<NumericComponent>().GetAsFloat(NumericType.Speed);
|
||||
MoveComponent moveComponent = unit.GetComponent<MoveComponent>();
|
||||
await moveComponent.MoveToAsync(path, speed);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9517a733443387b49a227cfb10aa82d6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,12 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[ActorMessageHandler(SceneType.All)]
|
||||
public class NetClient2Main_SessionDisposeHandler: ActorMessageHandler<Scene, NetClient2Main_SessionDispose>
|
||||
{
|
||||
protected override async ETTask Run(Scene entity, NetClient2Main_SessionDispose message)
|
||||
{
|
||||
Log.Error($"session dispose, error: {message.Error}");
|
||||
await ETTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9fbd99f39ddd82042af56cdbf9ce8dc3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0d507c6bfa0e3424380311d17689451c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,14 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
public static class CurrentSceneFactory
|
||||
{
|
||||
public static Scene Create(long id, string name, CurrentScenesComponent currentScenesComponent)
|
||||
{
|
||||
Scene currentScene = EntitySceneFactory.CreateScene(currentScenesComponent, id, currentScenesComponent.Fiber().IdGenerater.GenerateInstanceId(), SceneType.Current, name);
|
||||
currentScenesComponent.Scene = currentScene;
|
||||
|
||||
EventSystem.Instance.Publish(currentScene, new EventType.AfterCreateCurrentScene());
|
||||
return currentScene;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7e7628945100a44193d11f6c86856fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,11 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[ActorMessageHandler(SceneType.Demo)]
|
||||
public class M2C_StartSceneChangeHandler : ActorMessageHandler<Scene, M2C_StartSceneChange>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, M2C_StartSceneChange message)
|
||||
{
|
||||
await SceneChangeHelper.SceneChangeTo(root, message.SceneName, message.SceneInstanceId);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ba66d6939e13bc47b59fe326cac0526
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,29 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
public static partial class SceneChangeHelper
|
||||
{
|
||||
// 场景切换协程
|
||||
public static async ETTask SceneChangeTo(Scene root, string sceneName, long sceneInstanceId)
|
||||
{
|
||||
root.RemoveComponent<AIComponent>();
|
||||
|
||||
CurrentScenesComponent currentScenesComponent = root.GetComponent<CurrentScenesComponent>();
|
||||
currentScenesComponent.Scene?.Dispose(); // 删除之前的CurrentScene,创建新的
|
||||
Scene currentScene = CurrentSceneFactory.Create(sceneInstanceId, sceneName, currentScenesComponent);
|
||||
UnitComponent unitComponent = currentScene.AddComponent<UnitComponent>();
|
||||
|
||||
// 可以订阅这个事件中创建Loading界面
|
||||
EventSystem.Instance.Publish(root, new EventType.SceneChangeStart());
|
||||
// 等待CreateMyUnit的消息
|
||||
Wait_CreateMyUnit waitCreateMyUnit = await root.GetComponent<ObjectWait>().Wait<Wait_CreateMyUnit>();
|
||||
M2C_CreateMyUnit m2CCreateMyUnit = waitCreateMyUnit.Message;
|
||||
Unit unit = UnitFactory.Create(currentScene, m2CCreateMyUnit.Unit);
|
||||
unitComponent.Add(unit);
|
||||
root.RemoveComponent<AIComponent>();
|
||||
|
||||
EventSystem.Instance.Publish(currentScene, new EventType.SceneChangeFinish());
|
||||
// 通知等待场景切换的协程
|
||||
root.GetComponent<ObjectWait>().Notify(new Wait_SceneChangeFinish());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eff9697e3de79f54dbfd7996f55c6f47
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b99fb42c78388f147beaf9a963a80458
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,13 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[ActorMessageHandler(SceneType.Demo)]
|
||||
public class M2C_CreateMyUnitHandler: ActorMessageHandler<Scene, M2C_CreateMyUnit>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, M2C_CreateMyUnit message)
|
||||
{
|
||||
// 通知场景切换协程继续往下走
|
||||
root.GetComponent<ObjectWait>().Notify(new Wait_CreateMyUnit() {Message = message});
|
||||
await ETTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 69fc464a314f79d46922ca7c44dad617
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,22 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[ActorMessageHandler(SceneType.Demo)]
|
||||
public class M2C_CreateUnitsHandler: ActorMessageHandler<Scene, M2C_CreateUnits>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, M2C_CreateUnits message)
|
||||
{
|
||||
Scene currentScene = root.CurrentScene();
|
||||
UnitComponent unitComponent = currentScene.GetComponent<UnitComponent>();
|
||||
|
||||
foreach (UnitInfo unitInfo in message.Units)
|
||||
{
|
||||
if (unitComponent.Get(unitInfo.UnitId) != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Unit unit = UnitFactory.Create(currentScene, unitInfo);
|
||||
}
|
||||
await ETTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0b8fc07def7b312469c243c3ccad1b39
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,21 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[ActorMessageHandler(SceneType.Demo)]
|
||||
public class M2C_RemoveUnitsHandler: ActorMessageHandler<Scene, M2C_RemoveUnits>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, M2C_RemoveUnits message)
|
||||
{
|
||||
UnitComponent unitComponent = root.CurrentScene()?.GetComponent<UnitComponent>();
|
||||
if (unitComponent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (long unitId in message.Units)
|
||||
{
|
||||
unitComponent.Remove(unitId);
|
||||
}
|
||||
|
||||
await ETTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6c4d413c1206d8844b7f6ccc95dd2ce6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,41 @@
|
||||
using Unity.Mathematics;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
public static partial class UnitFactory
|
||||
{
|
||||
public static Unit Create(Scene currentScene, UnitInfo unitInfo)
|
||||
{
|
||||
UnitComponent unitComponent = currentScene.GetComponent<UnitComponent>();
|
||||
Unit unit = unitComponent.AddChildWithId<Unit, int>(unitInfo.UnitId, unitInfo.ConfigId);
|
||||
unitComponent.Add(unit);
|
||||
|
||||
unit.Position = unitInfo.Position;
|
||||
unit.Forward = unitInfo.Forward;
|
||||
|
||||
NumericComponent numericComponent = unit.AddComponent<NumericComponent>();
|
||||
|
||||
foreach (var kv in unitInfo.KV)
|
||||
{
|
||||
numericComponent.Set(kv.Key, kv.Value);
|
||||
}
|
||||
|
||||
unit.AddComponent<MoveComponent>();
|
||||
if (unitInfo.MoveInfo != null)
|
||||
{
|
||||
if (unitInfo.MoveInfo.Points.Count > 0)
|
||||
{
|
||||
unitInfo.MoveInfo.Points[0] = unit.Position;
|
||||
unit.MoveToAsync(unitInfo.MoveInfo.Points).Coroutine();
|
||||
}
|
||||
}
|
||||
|
||||
unit.AddComponent<ObjectWait>();
|
||||
|
||||
unit.AddComponent<XunLuoPathComponent>();
|
||||
|
||||
EventSystem.Instance.Publish(unit.Scene(), new EventType.AfterUnitCreate() {Unit = unit});
|
||||
return unit;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f76a73cf5e806e9499c3eb92aeeb46d2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,18 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
public static partial class UnitHelper
|
||||
{
|
||||
public static Unit GetMyUnitFromClientScene(Scene root)
|
||||
{
|
||||
PlayerComponent playerComponent = root.GetComponent<PlayerComponent>();
|
||||
Scene currentScene = root.GetComponent<CurrentScenesComponent>().Scene;
|
||||
return currentScene.GetComponent<UnitComponent>().Get(playerComponent.MyId);
|
||||
}
|
||||
|
||||
public static Unit GetMyUnitFromCurrentScene(Scene currentScene)
|
||||
{
|
||||
PlayerComponent playerComponent = currentScene.Root().GetComponent<PlayerComponent>();
|
||||
return currentScene.GetComponent<UnitComponent>().Get(playerComponent.MyId);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90e53c0be7b8aab4c827ed76d193ca42
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9016545e3eb60946afce20928d2d34b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,12 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[ActorMessageHandler(SceneType.NetClient)]
|
||||
public class A2NetClient_MessageHandler: ActorMessageHandler<Scene, A2NetClient_Message>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, A2NetClient_Message message)
|
||||
{
|
||||
root.GetComponent<SessionComponent>().Session.Send(message.MessageObject);
|
||||
await ETTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0f70391ff9eb499db68bae992a9c85b6
|
||||
timeCreated: 1688540041
|
@@ -0,0 +1,11 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[ActorMessageHandler(SceneType.NetClient)]
|
||||
public class A2NetClient_RequestHandler: ActorMessageHandler<Scene, A2NetClient_Request, A2NetClient_Response>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, A2NetClient_Request request, A2NetClient_Response response)
|
||||
{
|
||||
response.MessageObject = await root.GetComponent<SessionComponent>().Session.Call(request.MessageObject);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f3ac2d21dada4f2b8b51b26e0efe891e
|
||||
timeCreated: 1688540239
|
@@ -0,0 +1,16 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[Invoke((long)SceneType.NetClient)]
|
||||
public class FiberInit_NetClient: AInvokeHandler<FiberInit, ETTask>
|
||||
{
|
||||
public override async ETTask Handle(FiberInit fiberInit)
|
||||
{
|
||||
Scene root = fiberInit.Fiber.Root;
|
||||
root.AddComponent<MailBoxComponent, MailBoxType>(MailBoxType.UnOrderedMessage);
|
||||
root.AddComponent<TimerComponent>();
|
||||
root.AddComponent<CoroutineLockComponent>();
|
||||
root.AddComponent<ActorInnerComponent>();
|
||||
await ETTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dee733932d1381941bc0496fc337341a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,17 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
public static class LoginHelper
|
||||
{
|
||||
public static async ETTask Login(Scene root, string account, string password)
|
||||
{
|
||||
root.RemoveComponent<ClientSenderCompnent>();
|
||||
ClientSenderCompnent clientSenderCompnent = root.AddComponent<ClientSenderCompnent>();
|
||||
|
||||
long playerId = await clientSenderCompnent.LoginAsync(account, password);
|
||||
|
||||
root.GetComponent<PlayerComponent>().MyId = playerId;
|
||||
|
||||
await EventSystem.Instance.PublishAsync(root, new EventType.LoginFinish());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d8c6e9a02dc4ab41ad32d56d9594354
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,43 @@
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
[ActorMessageHandler(SceneType.NetClient)]
|
||||
public class Main2NetClient_LoginHandler: ActorMessageHandler<Scene, Main2NetClient_Login, NetClient2Main_Login>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, Main2NetClient_Login request, NetClient2Main_Login response)
|
||||
{
|
||||
string account = request.Account;
|
||||
string password = request.Password;
|
||||
// 创建一个ETModel层的Session
|
||||
root.RemoveComponent<RouterAddressComponent>();
|
||||
// 获取路由跟realmDispatcher地址
|
||||
RouterAddressComponent routerAddressComponent = root.GetComponent<RouterAddressComponent>();
|
||||
if (routerAddressComponent == null)
|
||||
{
|
||||
routerAddressComponent =
|
||||
root.AddComponent<RouterAddressComponent, string, int>(ConstValue.RouterHttpHost, ConstValue.RouterHttpPort);
|
||||
await routerAddressComponent.Init();
|
||||
root.AddComponent<NetClientComponent, AddressFamily>(routerAddressComponent.RouterManagerIPAddress.AddressFamily);
|
||||
}
|
||||
IPEndPoint realmAddress = routerAddressComponent.GetRealmAddress(account);
|
||||
|
||||
R2C_Login r2CLogin;
|
||||
using (Session session = await RouterHelper.CreateRouterSession(root, realmAddress))
|
||||
{
|
||||
r2CLogin = (R2C_Login)await session.Call(new C2R_Login() { Account = account, Password = password });
|
||||
}
|
||||
|
||||
// 创建一个gate Session,并且保存到SessionComponent中
|
||||
Session gateSession = await RouterHelper.CreateRouterSession(root, NetworkHelper.ToIPEndPoint(r2CLogin.Address));
|
||||
gateSession.AddComponent<ClientSessionErrorComponent>();
|
||||
root.AddComponent<SessionComponent>().Session = gateSession;
|
||||
G2C_LoginGate g2CLoginGate = (G2C_LoginGate)await gateSession.Call(new C2G_LoginGate() { Key = r2CLogin.Key, GateId = r2CLogin.GateId });
|
||||
|
||||
Log.Debug("登陆gate成功!");
|
||||
|
||||
response.PlayerId = g2CLoginGate.PlayerId;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02d16f101211408496a7e86b273ed882
|
||||
timeCreated: 1688536630
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 657f5f7736369e24786203c1c377ec14
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
[EntitySystemOf(typeof(PingComponent))]
|
||||
public static partial class PingComponentSystem
|
||||
{
|
||||
[EntitySystem]
|
||||
private static void Awake(this PingComponent self)
|
||||
{
|
||||
self.PingAsync().Coroutine();
|
||||
}
|
||||
|
||||
[EntitySystem]
|
||||
private static void Destroy(this PingComponent self)
|
||||
{
|
||||
self.Ping = default;
|
||||
}
|
||||
|
||||
private static async ETTask PingAsync(this PingComponent self)
|
||||
{
|
||||
Session session = self.GetParent<Session>();
|
||||
long instanceId = self.InstanceId;
|
||||
Fiber fiber = self.Fiber();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (self.InstanceId != instanceId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long time1 = self.Fiber().TimeInfo.ClientNow();
|
||||
try
|
||||
{
|
||||
C2G_Ping c2GPing = C2G_Ping.Create(true);
|
||||
using G2C_Ping response = await session.Call(c2GPing) as G2C_Ping;
|
||||
|
||||
if (self.InstanceId != instanceId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long time2 = self.Fiber().TimeInfo.ClientNow();
|
||||
self.Ping = time2 - time1;
|
||||
|
||||
fiber.TimeInfo.ServerMinusClientTime = response.Time + (time2 - time1) / 2 - time2;
|
||||
|
||||
await fiber.TimerComponent.WaitAsync(2000);
|
||||
}
|
||||
catch (RpcException e)
|
||||
{
|
||||
// session断开导致ping rpc报错,记录一下即可,不需要打成error
|
||||
Log.Info($"ping error: {self.Id} {e.Error}");
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error($"ping error: \n{e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df3747692b8ee23439aa241d5dcfabdc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0dd08876e79fc2e4e92db27f7a59b403
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
public static partial class HttpClientHelper
|
||||
{
|
||||
public static async ETTask<string> Get(string link)
|
||||
{
|
||||
try
|
||||
{
|
||||
using HttpClient httpClient = new();
|
||||
HttpResponseMessage response = await httpClient.GetAsync(link);
|
||||
string result = await response.Content.ReadAsStringAsync();
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new Exception($"http request fail: {link.Substring(0,link.IndexOf('?'))}\n{e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c6ca4a5394922f488127ebb53362456
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
[EntitySystemOf(typeof(RouterAddressComponent))]
|
||||
[FriendOf(typeof(RouterAddressComponent))]
|
||||
public static partial class RouterAddressComponentSystem
|
||||
{
|
||||
[EntitySystem]
|
||||
private static void Awake(this RouterAddressComponent self, string address, int port)
|
||||
{
|
||||
self.RouterManagerHost = address;
|
||||
self.RouterManagerPort = port;
|
||||
}
|
||||
|
||||
public static async ETTask Init(this RouterAddressComponent self)
|
||||
{
|
||||
self.RouterManagerIPAddress = NetworkHelper.GetHostAddress(self.RouterManagerHost);
|
||||
await self.GetAllRouter();
|
||||
}
|
||||
|
||||
private static async ETTask GetAllRouter(this RouterAddressComponent self)
|
||||
{
|
||||
string url = $"http://{self.RouterManagerHost}:{self.RouterManagerPort}/get_router?v={RandomGenerator.RandUInt32()}";
|
||||
Log.Debug($"start get router info: {url}");
|
||||
string routerInfo = await HttpClientHelper.Get(url);
|
||||
Log.Debug($"recv router info: {routerInfo}");
|
||||
HttpGetRouterResponse httpGetRouterResponse = MongoHelper.FromJson<HttpGetRouterResponse>(routerInfo);
|
||||
self.Info = httpGetRouterResponse;
|
||||
Log.Debug($"start get router info finish: {MongoHelper.ToJson(httpGetRouterResponse)}");
|
||||
|
||||
// 打乱顺序
|
||||
RandomGenerator.BreakRank(self.Info.Routers);
|
||||
|
||||
self.WaitTenMinGetAllRouter().Coroutine();
|
||||
}
|
||||
|
||||
// 等10分钟再获取一次
|
||||
public static async ETTask WaitTenMinGetAllRouter(this RouterAddressComponent self)
|
||||
{
|
||||
await self.Fiber().TimerComponent.WaitAsync(5 * 60 * 1000);
|
||||
if (self.IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
await self.GetAllRouter();
|
||||
}
|
||||
|
||||
public static IPEndPoint GetAddress(this RouterAddressComponent self)
|
||||
{
|
||||
if (self.Info.Routers.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string address = self.Info.Routers[self.RouterIndex++ % self.Info.Routers.Count];
|
||||
string[] ss = address.Split(':');
|
||||
IPAddress ipAddress = IPAddress.Parse(ss[0]);
|
||||
if (self.RouterManagerIPAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
{
|
||||
ipAddress = ipAddress.MapToIPv6();
|
||||
}
|
||||
return new IPEndPoint(ipAddress, int.Parse(ss[1]));
|
||||
}
|
||||
|
||||
public static IPEndPoint GetRealmAddress(this RouterAddressComponent self, string account)
|
||||
{
|
||||
int v = account.Mode(self.Info.Realms.Count);
|
||||
string address = self.Info.Realms[v];
|
||||
string[] ss = address.Split(':');
|
||||
IPAddress ipAddress = IPAddress.Parse(ss[0]);
|
||||
//if (self.IPAddress.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
//{
|
||||
// ipAddress = ipAddress.MapToIPv6();
|
||||
//}
|
||||
return new IPEndPoint(ipAddress, int.Parse(ss[1]));
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 567a551c7abf2fd4c9b592af991b609e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
[EntitySystemOf(typeof(RouterCheckComponent))]
|
||||
public static partial class RouterCheckComponentSystem
|
||||
{
|
||||
[EntitySystem]
|
||||
private static void Awake(this RouterCheckComponent self)
|
||||
{
|
||||
self.CheckAsync().Coroutine();
|
||||
}
|
||||
|
||||
private static async ETTask CheckAsync(this RouterCheckComponent self)
|
||||
{
|
||||
Session session = self.GetParent<Session>();
|
||||
long instanceId = self.InstanceId;
|
||||
Fiber fiber = self.Fiber();
|
||||
Scene root = fiber.Root;
|
||||
while (true)
|
||||
{
|
||||
if (self.InstanceId != instanceId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await fiber.TimerComponent.WaitAsync(1000);
|
||||
|
||||
if (self.InstanceId != instanceId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
long time = self.Fiber().TimeInfo.ClientFrameTime();
|
||||
|
||||
if (time - session.LastRecvTime < 7 * 1000)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
long sessionId = session.Id;
|
||||
|
||||
(uint localConn, uint remoteConn) = session.AService.GetChannelConn(sessionId);
|
||||
|
||||
IPEndPoint realAddress = self.GetParent<Session>().RemoteAddress;
|
||||
Log.Info($"get recvLocalConn start: {root.Id} {realAddress} {localConn} {remoteConn}");
|
||||
|
||||
(uint recvLocalConn, IPEndPoint routerAddress) = await RouterHelper.GetRouterAddress(root, realAddress, localConn, remoteConn);
|
||||
if (recvLocalConn == 0)
|
||||
{
|
||||
Log.Error($"get recvLocalConn fail: {root.Id} {routerAddress} {realAddress} {localConn} {remoteConn}");
|
||||
continue;
|
||||
}
|
||||
|
||||
Log.Info($"get recvLocalConn ok: {root.Id} {routerAddress} {realAddress} {recvLocalConn} {localConn} {remoteConn}");
|
||||
|
||||
session.LastRecvTime = self.Fiber().TimeInfo.ClientNow();
|
||||
|
||||
session.AService.ChangeAddress(sessionId, routerAddress);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55f4125eddb1aa543bfdce8f42b4d5f9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,109 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
public static partial class RouterHelper
|
||||
{
|
||||
// 注册router
|
||||
public static async ETTask<Session> CreateRouterSession(Scene root, IPEndPoint address)
|
||||
{
|
||||
(uint recvLocalConn, IPEndPoint routerAddress) = await GetRouterAddress(root, address, 0, 0);
|
||||
|
||||
if (recvLocalConn == 0)
|
||||
{
|
||||
throw new Exception($"get router fail: {root.Id} {address}");
|
||||
}
|
||||
|
||||
Log.Info($"get router: {recvLocalConn} {routerAddress}");
|
||||
|
||||
Session routerSession = root.GetComponent<NetClientComponent>().Create(routerAddress, address, recvLocalConn);
|
||||
routerSession.AddComponent<PingComponent>();
|
||||
routerSession.AddComponent<RouterCheckComponent>();
|
||||
|
||||
return routerSession;
|
||||
}
|
||||
|
||||
public static async ETTask<(uint, IPEndPoint)> GetRouterAddress(Scene root, IPEndPoint address, uint localConn, uint remoteConn)
|
||||
{
|
||||
Log.Info($"start get router address: {root.Id} {address} {localConn} {remoteConn}");
|
||||
//return (RandomHelper.RandUInt32(), address);
|
||||
RouterAddressComponent routerAddressComponent = root.GetComponent<RouterAddressComponent>();
|
||||
IPEndPoint routerInfo = routerAddressComponent.GetAddress();
|
||||
|
||||
uint recvLocalConn = await Connect(root, routerInfo, address, localConn, remoteConn);
|
||||
|
||||
Log.Info($"finish get router address: {root.Id} {address} {localConn} {remoteConn} {recvLocalConn} {routerInfo}");
|
||||
return (recvLocalConn, routerInfo);
|
||||
}
|
||||
|
||||
// 向router申请
|
||||
private static async ETTask<uint> Connect(Scene root, IPEndPoint routerAddress, IPEndPoint realAddress, uint localConn, uint remoteConn)
|
||||
{
|
||||
uint connectId = RandomGenerator.RandUInt32();
|
||||
|
||||
using Socket socket = new Socket(routerAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
|
||||
|
||||
int count = 20;
|
||||
byte[] sendCache = new byte[512];
|
||||
byte[] recvCache = new byte[512];
|
||||
|
||||
uint synFlag = localConn == 0? KcpProtocalType.RouterSYN : KcpProtocalType.RouterReconnectSYN;
|
||||
sendCache.WriteTo(0, synFlag);
|
||||
sendCache.WriteTo(1, localConn);
|
||||
sendCache.WriteTo(5, remoteConn);
|
||||
sendCache.WriteTo(9, connectId);
|
||||
byte[] addressBytes = realAddress.ToString().ToByteArray();
|
||||
Array.Copy(addressBytes, 0, sendCache, 13, addressBytes.Length);
|
||||
|
||||
Log.Info($"router connect: {connectId} {localConn} {remoteConn} {routerAddress} {realAddress}");
|
||||
|
||||
EndPoint recvIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
|
||||
|
||||
long lastSendTimer = 0;
|
||||
|
||||
Fiber fiber = root.Fiber;
|
||||
while (true)
|
||||
{
|
||||
long timeNow = fiber.TimeInfo.ClientFrameTime();
|
||||
if (timeNow - lastSendTimer > 300)
|
||||
{
|
||||
if (--count < 0)
|
||||
{
|
||||
Log.Error($"router connect timeout fail! {localConn} {remoteConn} {routerAddress} {realAddress}");
|
||||
return 0;
|
||||
}
|
||||
lastSendTimer = timeNow;
|
||||
// 发送
|
||||
socket.SendTo(sendCache, 0, addressBytes.Length + 13, SocketFlags.None, routerAddress);
|
||||
}
|
||||
|
||||
await fiber.TimerComponent.WaitFrameAsync();
|
||||
|
||||
// 接收
|
||||
if (socket.Available > 0)
|
||||
{
|
||||
int messageLength = socket.ReceiveFrom(recvCache, ref recvIPEndPoint);
|
||||
if (messageLength != 9)
|
||||
{
|
||||
Log.Error($"router connect error1: {connectId} {messageLength} {localConn} {remoteConn} {routerAddress} {realAddress}");
|
||||
continue;
|
||||
}
|
||||
|
||||
byte flag = recvCache[0];
|
||||
if (flag != KcpProtocalType.RouterReconnectACK && flag != KcpProtocalType.RouterACK)
|
||||
{
|
||||
Log.Error($"router connect error2: {connectId} {synFlag} {flag} {localConn} {remoteConn} {routerAddress} {realAddress}");
|
||||
continue;
|
||||
}
|
||||
|
||||
uint recvRemoteConn = BitConverter.ToUInt32(recvCache, 1);
|
||||
uint recvLocalConn = BitConverter.ToUInt32(recvCache, 5);
|
||||
Log.Info($"router connect finish: {connectId} {recvRemoteConn} {recvLocalConn} {localConn} {remoteConn} {routerAddress} {realAddress}");
|
||||
return recvLocalConn;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c76c4f4f2b0cbc5458c3a39c18717d31
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/GameScripts/DotNet/Hotfix/Client/LockStep.meta
Normal file
8
Assets/GameScripts/DotNet/Hotfix/Client/LockStep.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c99aac44889414b359c3c2427356076f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,11 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[MessageHandler(SceneType.LockStep)]
|
||||
public class Match2G_NotifyMatchSuccessHandler: MessageHandler<Match2G_NotifyMatchSuccess>
|
||||
{
|
||||
protected override async ETTask Run(Session session, Match2G_NotifyMatchSuccess message)
|
||||
{
|
||||
await LSSceneChangeHelper.SceneChangeTo(session.Root(), "Map1", message.ActorId.InstanceId);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbf8b88a563eb46bfbaf987167d6a451
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,12 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[MessageHandler(SceneType.LockStep)]
|
||||
public class G2C_ReconnectHandler: MessageHandler<G2C_Reconnect>
|
||||
{
|
||||
protected override async ETTask Run(Session session, G2C_Reconnect message)
|
||||
{
|
||||
await LSSceneChangeHelper.SceneChangeToReconnect(session.Root(), message);
|
||||
await ETTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 41d6bacdbd4ca1843a732fc0144dc8fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,126 @@
|
||||
using System.IO;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
public static partial class LSClientHelper
|
||||
{
|
||||
public static void RunLSRollbackSystem(Entity entity)
|
||||
{
|
||||
if (entity is LSEntity)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LSEntitySystemSingleton.Instance.LSRollback(entity);
|
||||
|
||||
if (entity.ComponentsCount() > 0)
|
||||
{
|
||||
foreach (var kv in entity.Components)
|
||||
{
|
||||
RunLSRollbackSystem(kv.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if (entity.ChildrenCount() > 0)
|
||||
{
|
||||
foreach (var kv in entity.Children)
|
||||
{
|
||||
RunLSRollbackSystem(kv.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 回滚
|
||||
public static void Rollback(Room room, int frame)
|
||||
{
|
||||
room.LSWorld.Dispose();
|
||||
FrameBuffer frameBuffer = room.FrameBuffer;
|
||||
|
||||
// 回滚
|
||||
room.LSWorld = room.GetLSWorld(SceneType.LockStepClient, frame);
|
||||
OneFrameInputs authorityFrameInput = frameBuffer.FrameInputs(frame);
|
||||
// 执行AuthorityFrame
|
||||
room.Update(authorityFrameInput);
|
||||
room.SendHash(frame);
|
||||
|
||||
|
||||
// 重新执行预测的帧
|
||||
for (int i = room.AuthorityFrame + 1; i <= room.PredictionFrame; ++i)
|
||||
{
|
||||
OneFrameInputs oneFrameInputs = frameBuffer.FrameInputs(i);
|
||||
LSClientHelper.CopyOtherInputsTo(room, authorityFrameInput, oneFrameInputs); // 重新预测消息
|
||||
room.Update(oneFrameInputs);
|
||||
}
|
||||
|
||||
RunLSRollbackSystem(room);
|
||||
}
|
||||
|
||||
public static void SendHash(this Room self, int frame)
|
||||
{
|
||||
if (frame > self.AuthorityFrame)
|
||||
{
|
||||
return;
|
||||
}
|
||||
long hash = self.FrameBuffer.GetHash(frame);
|
||||
C2Room_CheckHash c2RoomCheckHash = C2Room_CheckHash.Create();
|
||||
c2RoomCheckHash.Frame = frame;
|
||||
c2RoomCheckHash.Hash = hash;
|
||||
self.Root().GetComponent<ClientSenderCompnent>().Send(c2RoomCheckHash);
|
||||
}
|
||||
|
||||
// 重新调整预测消息,只需要调整其他玩家的输入
|
||||
public static void CopyOtherInputsTo(Room room, OneFrameInputs from, OneFrameInputs to)
|
||||
{
|
||||
long myId = room.GetComponent<LSClientUpdater>().MyId;
|
||||
foreach (var kv in from.Inputs)
|
||||
{
|
||||
if (kv.Key == myId)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
to.Inputs[kv.Key] = kv.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SaveReplay(Room room, string path)
|
||||
{
|
||||
if (room.IsReplay)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Log.Debug($"save replay: {path} frame: {room.Replay.FrameInputs.Count}");
|
||||
byte[] bytes = MemoryPackHelper.Serialize(room.Replay);
|
||||
File.WriteAllBytes(path, bytes);
|
||||
}
|
||||
|
||||
public static void JumpReplay(Room room, int frame)
|
||||
{
|
||||
if (!room.IsReplay)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (frame >= room.Replay.FrameInputs.Count)
|
||||
{
|
||||
frame = room.Replay.FrameInputs.Count - 1;
|
||||
}
|
||||
|
||||
int snapshotIndex = frame / LSConstValue.SaveLSWorldFrameCount;
|
||||
Log.Debug($"jump replay start {room.AuthorityFrame} {frame} {snapshotIndex}");
|
||||
if (snapshotIndex != room.AuthorityFrame / LSConstValue.SaveLSWorldFrameCount || frame < room.AuthorityFrame)
|
||||
{
|
||||
room.LSWorld.Dispose();
|
||||
// 回滚
|
||||
byte[] memoryBuffer = room.Replay.Snapshots[snapshotIndex];
|
||||
LSWorld lsWorld = MongoHelper.Deserialize(typeof (LSWorld), memoryBuffer, 0, memoryBuffer.Length) as LSWorld;
|
||||
room.LSWorld = lsWorld;
|
||||
room.AuthorityFrame = snapshotIndex * LSConstValue.SaveLSWorldFrameCount;
|
||||
RunLSRollbackSystem(room);
|
||||
}
|
||||
|
||||
room.FixedTimeCounter.Reset(room.Fiber.TimeInfo.ServerFrameTime() - frame * LSConstValue.UpdateInterval, 0);
|
||||
|
||||
Log.Debug($"jump replay finish {frame}");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 915aaa51beb994638bd10e0d2ed9d8a7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
[EntitySystemOf(typeof(LSClientUpdater))]
|
||||
[FriendOf(typeof (LSClientUpdater))]
|
||||
public static partial class LSClientUpdaterSystem
|
||||
{
|
||||
[EntitySystem]
|
||||
private static void Awake(this LSClientUpdater self)
|
||||
{
|
||||
Room room = self.GetParent<Room>();
|
||||
self.MyId = room.Root().GetComponent<PlayerComponent>().MyId;
|
||||
}
|
||||
|
||||
[EntitySystem]
|
||||
private static void Update(this LSClientUpdater self)
|
||||
{
|
||||
Room room = self.GetParent<Room>();
|
||||
long timeNow = self.Fiber().TimeInfo.ServerNow();
|
||||
Scene root = room.Root();
|
||||
|
||||
int i = 0;
|
||||
while (true)
|
||||
{
|
||||
if (timeNow < room.FixedTimeCounter.FrameTime(room.PredictionFrame + 1))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 最多只预测5帧
|
||||
if (room.PredictionFrame - room.AuthorityFrame > 5)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
++room.PredictionFrame;
|
||||
OneFrameInputs oneFrameInputs = self.GetOneFrameMessages(room.PredictionFrame);
|
||||
|
||||
room.Update(oneFrameInputs);
|
||||
room.SendHash(room.PredictionFrame);
|
||||
|
||||
room.SpeedMultiply = ++i;
|
||||
|
||||
FrameMessage frameMessage = FrameMessage.Create();
|
||||
frameMessage.Frame = room.PredictionFrame;
|
||||
frameMessage.Input = self.Input;
|
||||
root.GetComponent<ClientSenderCompnent>().Send(frameMessage);
|
||||
|
||||
long timeNow2 = self.Fiber().TimeInfo.ServerNow();
|
||||
if (timeNow2 - timeNow > 5)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static OneFrameInputs GetOneFrameMessages(this LSClientUpdater self, int frame)
|
||||
{
|
||||
Room room = self.GetParent<Room>();
|
||||
FrameBuffer frameBuffer = room.FrameBuffer;
|
||||
|
||||
if (frame <= room.AuthorityFrame)
|
||||
{
|
||||
return frameBuffer.FrameInputs(frame);
|
||||
}
|
||||
|
||||
// predict
|
||||
OneFrameInputs predictionFrame = frameBuffer.FrameInputs(frame);
|
||||
|
||||
frameBuffer.MoveForward(frame);
|
||||
if (frameBuffer.CheckFrame(room.AuthorityFrame))
|
||||
{
|
||||
OneFrameInputs authorityFrame = frameBuffer.FrameInputs(room.AuthorityFrame);
|
||||
authorityFrame.CopyTo(predictionFrame);
|
||||
}
|
||||
predictionFrame.Inputs[self.MyId] = self.Input;
|
||||
|
||||
return predictionFrame;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46f47e16ad6bc417391e3cdee1b5a851
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
[EntitySystemOf(typeof(LSReplayUpdater))]
|
||||
[FriendOf(typeof(LSReplayUpdater))]
|
||||
public static partial class LSReplayUpdaterSystem
|
||||
{
|
||||
[EntitySystem]
|
||||
private static void Awake(this LSReplayUpdater self)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[EntitySystem]
|
||||
private static void Update(this LSReplayUpdater self)
|
||||
{
|
||||
Room room = self.GetParent<Room>();
|
||||
Fiber fiber = self.Fiber();
|
||||
long timeNow = fiber.TimeInfo.ServerNow();
|
||||
|
||||
int i = 0;
|
||||
while (true)
|
||||
{
|
||||
if (room.AuthorityFrame + 1 >= room.Replay.FrameInputs.Count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (timeNow < room.FixedTimeCounter.FrameTime(room.AuthorityFrame + 1))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
++room.AuthorityFrame;
|
||||
|
||||
OneFrameInputs oneFrameInputs = room.Replay.FrameInputs[room.AuthorityFrame];
|
||||
|
||||
room.Update(oneFrameInputs);
|
||||
room.SpeedMultiply = ++i;
|
||||
|
||||
long timeNow2 = fiber.TimeInfo.ServerNow();
|
||||
if (timeNow2 - timeNow > 5)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void ChangeReplaySpeed(this LSReplayUpdater self)
|
||||
{
|
||||
Room room = self.Room();
|
||||
LSReplayUpdater lsReplayUpdater = room.GetComponent<LSReplayUpdater>();
|
||||
if (lsReplayUpdater.ReplaySpeed == 8)
|
||||
{
|
||||
lsReplayUpdater.ReplaySpeed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
lsReplayUpdater.ReplaySpeed *= 2;
|
||||
}
|
||||
|
||||
int updateInterval = LSConstValue.UpdateInterval / lsReplayUpdater.ReplaySpeed;
|
||||
room.FixedTimeCounter.ChangeInterval(updateInterval, room.AuthorityFrame);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f2dc3825dd2f4641bce36a7b8b7708e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,72 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
|
||||
public static partial class LSSceneChangeHelper
|
||||
{
|
||||
// 场景切换协程
|
||||
public static async ETTask SceneChangeTo(Scene root, string sceneName, long sceneInstanceId)
|
||||
{
|
||||
root.RemoveComponent<Room>();
|
||||
|
||||
Room room = root.AddComponentWithId<Room>(sceneInstanceId);
|
||||
room.Name = sceneName;
|
||||
|
||||
// 等待表现层订阅的事件完成
|
||||
await EventSystem.Instance.PublishAsync(root, new EventType.LSSceneChangeStart() {Room = room});
|
||||
|
||||
root.GetComponent<ClientSenderCompnent>().Send(new C2Room_ChangeSceneFinish());
|
||||
|
||||
// 等待Room2C_EnterMap消息
|
||||
WaitType.Wait_Room2C_Start waitRoom2CStart = await root.GetComponent<ObjectWait>().Wait<WaitType.Wait_Room2C_Start>();
|
||||
|
||||
room.LSWorld = new LSWorld(SceneType.LockStepClient);
|
||||
room.Init(waitRoom2CStart.Message.UnitInfo, waitRoom2CStart.Message.StartTime);
|
||||
|
||||
room.AddComponent<LSClientUpdater>();
|
||||
|
||||
// 这个事件中可以订阅取消loading
|
||||
EventSystem.Instance.Publish(root, new EventType.LSSceneInitFinish());
|
||||
}
|
||||
|
||||
// 场景切换协程
|
||||
public static async ETTask SceneChangeToReplay(Scene root, Replay replay)
|
||||
{
|
||||
root.RemoveComponent<Room>();
|
||||
|
||||
Room room = root.AddComponent<Room>();
|
||||
room.Name = "Map1";
|
||||
room.IsReplay = true;
|
||||
room.Replay = replay;
|
||||
room.LSWorld = new LSWorld(SceneType.LockStepClient);
|
||||
room.Init(replay.UnitInfos, root.Fiber().TimeInfo.ServerFrameTime());
|
||||
|
||||
// 等待表现层订阅的事件完成
|
||||
await EventSystem.Instance.PublishAsync(root, new EventType.LSSceneChangeStart() {Room = room});
|
||||
|
||||
|
||||
room.AddComponent<LSReplayUpdater>();
|
||||
// 这个事件中可以订阅取消loading
|
||||
EventSystem.Instance.Publish(root, new EventType.LSSceneInitFinish());
|
||||
}
|
||||
|
||||
// 场景切换协程
|
||||
public static async ETTask SceneChangeToReconnect(Scene root, G2C_Reconnect message)
|
||||
{
|
||||
root.RemoveComponent<Room>();
|
||||
|
||||
Room room = root.AddComponent<Room>();
|
||||
room.Name = "Map1";
|
||||
|
||||
room.LSWorld = new LSWorld(SceneType.LockStepClient);
|
||||
room.Init(message.UnitInfos, message.StartTime, message.Frame);
|
||||
|
||||
// 等待表现层订阅的事件完成
|
||||
await EventSystem.Instance.PublishAsync(root, new EventType.LSSceneChangeStart() {Room = room});
|
||||
|
||||
|
||||
room.AddComponent<LSClientUpdater>();
|
||||
// 这个事件中可以订阅取消loading
|
||||
EventSystem.Instance.Publish(root, new EventType.LSSceneInitFinish());
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b38bd6590f604a9e9bc0360a81fe2b3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,51 @@
|
||||
using System;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
[MessageHandler(SceneType.LockStep)]
|
||||
public class OneFrameInputsHandler: MessageHandler<OneFrameInputs>
|
||||
{
|
||||
protected override async ETTask Run(Session session, OneFrameInputs input)
|
||||
{
|
||||
using var _ = input ; // 方法结束时回收消息
|
||||
|
||||
Room room = session.Scene().GetComponent<Room>();
|
||||
|
||||
Log.Debug($"OneFrameInputs: {room.AuthorityFrame + 1} {input.ToJson()}");
|
||||
|
||||
FrameBuffer frameBuffer = room.FrameBuffer;
|
||||
|
||||
++room.AuthorityFrame;
|
||||
// 服务端返回的消息比预测的还早
|
||||
if (room.AuthorityFrame > room.PredictionFrame)
|
||||
{
|
||||
OneFrameInputs authorityFrame = frameBuffer.FrameInputs(room.AuthorityFrame);
|
||||
input.CopyTo(authorityFrame);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 服务端返回来的消息,跟预测消息对比
|
||||
OneFrameInputs predictionInput = frameBuffer.FrameInputs(room.AuthorityFrame);
|
||||
// 对比失败有两种可能,
|
||||
// 1是别人的输入预测失败,这种很正常,
|
||||
// 2 自己的输入对比失败,这种情况是自己发送的消息比服务器晚到了,服务器使用了你的上一次输入
|
||||
// 回滚重新预测的时候,自己的输入不用变化
|
||||
if (input != predictionInput)
|
||||
{
|
||||
Log.Debug($"frame diff: {predictionInput} {input}");
|
||||
input.CopyTo(predictionInput);
|
||||
// 回滚到frameBuffer.AuthorityFrame
|
||||
Log.Debug($"roll back start {room.AuthorityFrame}");
|
||||
LSClientHelper.Rollback(room, room.AuthorityFrame);
|
||||
Log.Debug($"roll back finish {room.AuthorityFrame}");
|
||||
}
|
||||
else // 对比成功
|
||||
{
|
||||
room.Record(room.AuthorityFrame);
|
||||
room.SendHash(room.AuthorityFrame);
|
||||
}
|
||||
}
|
||||
await ETTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce16289caea864b01988193d7ea2e08a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,25 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[ActorMessageHandler(SceneType.LockStep)]
|
||||
public class Room2C_AdjustUpdateTimeHandler: ActorMessageHandler<Scene, Room2C_AdjustUpdateTime>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, Room2C_AdjustUpdateTime message)
|
||||
{
|
||||
Room room = root.GetComponent<Room>();
|
||||
int newInterval = (1000 + (message.DiffTime - LSConstValue.UpdateInterval)) * LSConstValue.UpdateInterval / 1000;
|
||||
|
||||
if (newInterval < 40)
|
||||
{
|
||||
newInterval = 40;
|
||||
}
|
||||
|
||||
if (newInterval > 66)
|
||||
{
|
||||
newInterval = 66;
|
||||
}
|
||||
|
||||
room.FixedTimeCounter.ChangeInterval(newInterval, room.PredictionFrame);
|
||||
await ETTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4df743a2d294ae59bf4844174591716
|
||||
timeCreated: 1682414000
|
@@ -0,0 +1,25 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[ActorMessageHandler(SceneType.LockStep)]
|
||||
public class Room2C_CheckHashFailHandler: ActorMessageHandler<Scene, Room2C_CheckHashFail>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, Room2C_CheckHashFail message)
|
||||
{
|
||||
LSWorld serverWorld = MongoHelper.Deserialize(typeof(LSWorld), message.LSWorldBytes, 0, message.LSWorldBytes.Length) as LSWorld;
|
||||
using (root.AddChild(serverWorld))
|
||||
{
|
||||
Log.Debug($"check hash fail, server: {message.Frame} {serverWorld.ToJson()}");
|
||||
}
|
||||
|
||||
Room room = root.GetComponent<Room>();
|
||||
LSWorld clientWorld = room.GetLSWorld(SceneType.LockStepClient, message.Frame);
|
||||
using (root.AddChild(clientWorld))
|
||||
{
|
||||
Log.Debug($"check hash fail, client: {message.Frame} {clientWorld.ToJson()}");
|
||||
}
|
||||
|
||||
message.Dispose();
|
||||
await ETTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd750474e6e5d437e8f1ac8279a7489d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,12 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[ActorMessageHandler(SceneType.LockStep)]
|
||||
public class Room2C_EnterMapHandler: ActorMessageHandler<Scene, Room2C_Start>
|
||||
{
|
||||
protected override async ETTask Run(Scene root, Room2C_Start message)
|
||||
{
|
||||
root.GetComponent<ObjectWait>().Notify(new WaitType.Wait_Room2C_Start() {Message = message});
|
||||
await ETTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c61c8470e59f14b9eb2ace115446c1c5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/GameScripts/DotNet/Hotfix/Client/Module.meta
Normal file
8
Assets/GameScripts/DotNet/Hotfix/Client/Module.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 83e42b45e303e71468c08f3d8f2d271a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6378fb95ea17e6d46b536062736457a5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,25 @@
|
||||
namespace ET.Client
|
||||
{
|
||||
[EntitySystemOf(typeof(ClientSessionErrorComponent))]
|
||||
public static partial class ClientSessionErrorComponentSystem
|
||||
{
|
||||
[EntitySystem]
|
||||
private static void Awake(this ClientSessionErrorComponent self)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[EntitySystem]
|
||||
private static void Destroy(this ClientSessionErrorComponent self)
|
||||
{
|
||||
Fiber fiber = self.Fiber();
|
||||
if (fiber.IsDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
NetClient2Main_SessionDispose message = NetClient2Main_SessionDispose.Create();
|
||||
message.Error = self.GetParent<Session>().Error;
|
||||
fiber.ActorInnerComponent.Send(new ActorId(fiber.Process, ConstFiberId.Main), message);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b9b509edbaf46e64f97bb6c4b55ccc7c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,102 @@
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using MongoDB.Bson;
|
||||
|
||||
namespace ET.Client
|
||||
{
|
||||
[EntitySystemOf(typeof(NetClientComponent))]
|
||||
[FriendOf(typeof(NetClientComponent))]
|
||||
public static partial class NetClientComponentSystem
|
||||
{
|
||||
[EntitySystem]
|
||||
private static void Awake(this NetClientComponent self, AddressFamily addressFamily)
|
||||
{
|
||||
self.AService = new KService(addressFamily, ServiceType.Outer);
|
||||
self.AService.ReadCallback = self.OnRead;
|
||||
self.AService.ErrorCallback = self.OnError;
|
||||
}
|
||||
|
||||
[EntitySystem]
|
||||
private static void Destroy(this NetClientComponent self)
|
||||
{
|
||||
self.AService.Dispose();
|
||||
}
|
||||
|
||||
[EntitySystem]
|
||||
private static void Update(this NetClientComponent self)
|
||||
{
|
||||
self.AService.Update();
|
||||
}
|
||||
|
||||
private static void OnRead(this NetClientComponent self, long channelId, ActorId actorId, object message)
|
||||
{
|
||||
Session session = self.GetChild<Session>(channelId);
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
session.LastRecvTime = self.Fiber().TimeInfo.ClientNow();
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case IResponse response:
|
||||
{
|
||||
session.OnResponse(response);
|
||||
break;
|
||||
}
|
||||
case IActorMessage:
|
||||
{
|
||||
// 扔到Main纤程队列中
|
||||
ActorMessageQueue.Instance.Send(new ActorId(self.Fiber().Process, ConstFiberId.Main), message as MessageObject);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// 普通消息或者是Rpc请求消息
|
||||
MessageDispatcherComponent.Instance.Handle(session, message);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnError(this NetClientComponent self, long channelId, int error)
|
||||
{
|
||||
Session session = self.GetChild<Session>(channelId);
|
||||
if (session == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
session.Error = error;
|
||||
session.Dispose();
|
||||
}
|
||||
|
||||
public static Session Create(this NetClientComponent self, IPEndPoint realIPEndPoint)
|
||||
{
|
||||
long channelId = NetServices.Instance.CreateConnectChannelId();
|
||||
Session session = self.AddChildWithId<Session, AService>(channelId, self.AService);
|
||||
session.RemoteAddress = realIPEndPoint;
|
||||
if (self.IScene.SceneType != SceneType.Benchmark)
|
||||
{
|
||||
session.AddComponent<SessionIdleCheckerComponent>();
|
||||
}
|
||||
self.AService.Create(session.Id, realIPEndPoint);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
public static Session Create(this NetClientComponent self, IPEndPoint routerIPEndPoint, IPEndPoint realIPEndPoint, uint localConn)
|
||||
{
|
||||
long channelId = localConn;
|
||||
Session session = self.AddChildWithId<Session, AService>(channelId, self.AService);
|
||||
session.RemoteAddress = realIPEndPoint;
|
||||
if (self.IScene.SceneType != SceneType.Benchmark)
|
||||
{
|
||||
session.AddComponent<SessionIdleCheckerComponent>();
|
||||
}
|
||||
self.AService.Create(session.Id, routerIPEndPoint);
|
||||
return session;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7fb1278bab55fff4789e94463d9cbdab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Assets/GameScripts/DotNet/Hotfix/Client/Plugins.meta
Normal file
8
Assets/GameScripts/DotNet/Hotfix/Client/Plugins.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9fd48acf90b9dd34a9f4d6c3a7ca409b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a574066b9ea021c4b9d593dad32e2f97
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@@ -0,0 +1 @@
|
||||
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9e0137fab5357074e8b6dfe36113542e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user