-
Notifications
You must be signed in to change notification settings - Fork 17
Expand file tree
/
Copy pathLocalSceneDevelopmentController.cs
More file actions
121 lines (103 loc) · 4.95 KB
/
Copy pathLocalSceneDevelopmentController.cs
File metadata and controls
121 lines (103 loc) · 4.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
using Arch.Core;
using Cysharp.Threading.Tasks;
using DCL.Character.CharacterMotion.Components;
using DCL.Diagnostics;
using DCL.SkyBox;
using DCL.SkyBox.Components;
using Decentraland.Sdk.Development;
using Google.Protobuf;
using System;
using System.Threading;
using Utility.Multithreading;
using Utility.Networking;
namespace ECS.SceneLifeCycle.LocalSceneDevelopment
{
public class LocalSceneDevelopmentController
{
private const double RELOAD_SCENE_TIMEOUT_SECS = 5;
private readonly ECSReloadScene reloadScene;
private readonly Entity playerEntity;
private readonly Entity skyboxEntity;
private readonly World globalWorld;
private DCLWebSocket? webSocket;
public LocalSceneDevelopmentController(ECSReloadScene reloadScene,
Entity playerEntity,
Entity skyboxEntity,
World globalWorld)
{
this.reloadScene = reloadScene;
this.playerEntity = playerEntity;
this.skyboxEntity = skyboxEntity;
this.globalWorld = globalWorld;
}
public void Dispose()
{
try
{
webSocket?.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
webSocket?.Dispose();
}
catch (ObjectDisposedException) { }
}
public async UniTask ConnectToServerAsync(string url, CancellationToken ct)
{
await ConnectToServerAsync(url, new WsSceneMessage(), new byte[1024], ct);
}
private async UniTask ConnectToServerAsync(string localSceneWebsocketServer,
WsSceneMessage wsSceneMessage, byte[] receiveBuffer, CancellationToken ct)
{
await DCLTask.SwitchToThreadPool();
ReportHub.Log(ReportCategory.SDK_LOCAL_SCENE_DEVELOPMENT, $"Trying to connect to: {localSceneWebsocketServer}");
webSocket = new DCLWebSocket();
await webSocket.ConnectAsync(new Uri(localSceneWebsocketServer), ct);
ReportHub.Log(ReportCategory.SDK_LOCAL_SCENE_DEVELOPMENT, $"Websocket connection state: {webSocket.State}");
while (webSocket.State == WebSocketState.Open)
{
// every iteration starts on the thread pool
await DCLTask.SwitchToThreadPool();
WebSocketReceiveResult? receiveResult = await webSocket.ReceiveAsync(receiveBuffer, ct);
if (receiveResult.MessageType == WebSocketMessageType.Binary)
{
wsSceneMessage.MergeFrom(receiveBuffer.AsSpan(0, receiveResult.Count));
ReportHub.Log(ReportCategory.SDK_LOCAL_SCENE_DEVELOPMENT, $"Websocket scene message received: {wsSceneMessage.MessageCase}");
// An UpdateModel message names the single GLTF that changed; carry it through so the
// reload can evict just that asset instead of draining every cache.
string sceneId;
ChangedGltfModel? changedModel;
if (wsSceneMessage.MessageCase == WsSceneMessage.MessageOneofCase.UpdateModel)
{
sceneId = wsSceneMessage.UpdateModel.SceneId;
changedModel = new ChangedGltfModel(wsSceneMessage.UpdateModel.Src, wsSceneMessage.UpdateModel.Hash);
}
else
{
sceneId = wsSceneMessage.UpdateScene.SceneId;
changedModel = null;
}
// Switch to the main thread because `TryReloadSceneAsync` requires that
await UniTask.SwitchToMainThread(cancellationToken: ct);
try
{
// We need to freeze the character movement until the scene is reloaded
globalWorld.AddOrGet(playerEntity, new StopCharacterMotion());
// And pause the skybox update while loading to avoid transitions
globalWorld.AddOrGet(skyboxEntity, new PauseSkyboxTimeUpdate());
await reloadScene.TryReloadSceneAsync(ct, sceneId, changedModel)
.Timeout(TimeSpan.FromSeconds(RELOAD_SCENE_TIMEOUT_SECS));
}
catch (TimeoutException) { }
finally
{
globalWorld.Remove<StopCharacterMotion>(playerEntity);
globalWorld.Remove<PauseSkyboxTimeUpdate>(skyboxEntity);
}
}
else if (receiveResult.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, null, ct);
ReportHub.Log(ReportCategory.SDK_LOCAL_SCENE_DEVELOPMENT, $"Websocket connection closed.");
}
}
}
}
}