Skip to content

Commit c146bb4

Browse files
authored
Merge pull request #165 from eesast/dev
robuster
2 parents 1980a4f + 3c4a42f commit c146bb4

11 files changed

Lines changed: 177 additions & 52 deletions

File tree

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using System;
2+
using System.Globalization;
3+
using THUAI9.Unity.Playback;
4+
using UnityEngine;
5+
6+
namespace THUAI9.Unity.WebGL
7+
{
8+
public sealed class LegacyPlaybackInputManager : MonoBehaviour
9+
{
10+
public const string LegacyObjectName = "InputManager";
11+
private const string EmptyPlaybackUrlStatus = "\u72b6\u6001\uff1a\u5728\u7ebf\u56de\u653e\u5730\u5740\u4e3a\u7a7a";
12+
private static LegacyPlaybackInputManager instance;
13+
private PlaybackController playbackController;
14+
15+
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
16+
private static void Bootstrap() => GetOrCreate();
17+
18+
public static LegacyPlaybackInputManager GetOrCreate()
19+
{
20+
if (instance != null) return instance;
21+
instance = FindObjectOfType<LegacyPlaybackInputManager>();
22+
if (instance != null)
23+
{
24+
instance.gameObject.name = LegacyObjectName;
25+
return instance;
26+
}
27+
28+
GameObject go = GameObject.Find(LegacyObjectName) ?? new GameObject(LegacyObjectName);
29+
instance = go.GetComponent<LegacyPlaybackInputManager>() ?? go.AddComponent<LegacyPlaybackInputManager>();
30+
return instance;
31+
}
32+
33+
private void Awake()
34+
{
35+
if (instance != null && instance != this)
36+
{
37+
Destroy(this);
38+
return;
39+
}
40+
41+
instance = this;
42+
gameObject.name = LegacyObjectName;
43+
DontDestroyOnLoad(gameObject);
44+
RefreshReferences();
45+
}
46+
47+
public void AfterInputPlaySpeed(string speed)
48+
{
49+
if (!float.TryParse(speed, NumberStyles.Float, CultureInfo.InvariantCulture, out float value))
50+
{
51+
Debug.LogWarning($"Ignoring invalid legacy playback speed: {speed}");
52+
return;
53+
}
54+
55+
WithPlaybackController(controller => controller.SetSpeed(value));
56+
}
57+
58+
public void AfterInputFilename(string filenameOrUrl)
59+
{
60+
if (string.IsNullOrWhiteSpace(filenameOrUrl))
61+
{
62+
WithPlaybackController(controller => controller.SetStatusMessage(EmptyPlaybackUrlStatus));
63+
return;
64+
}
65+
66+
string trimmed = filenameOrUrl.Trim().Trim('"');
67+
WithPlaybackController(controller => controller.LoadPlaybackFile(trimmed));
68+
}
69+
70+
private void WithPlaybackController(Action<PlaybackController> action)
71+
{
72+
RefreshReferences();
73+
if (playbackController == null)
74+
{
75+
Debug.LogWarning("Legacy playback InputManager could not find PlaybackController.");
76+
return;
77+
}
78+
79+
action(playbackController);
80+
}
81+
82+
private void RefreshReferences()
83+
{
84+
playbackController ??= FindObjectOfType<PlaybackController>();
85+
}
86+
}
87+
}

interface/Unity/Unity-Playback/Assets/Scripts/WebGL/LegacyPlaybackInputManager.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
-19.1 KB
Binary file not shown.
1.91 KB
Binary file not shown.

interface/Unity/Unity-WebGL/playback/Build/playback.framework.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
2.16 KB
Binary file not shown.

interface/Unity/Unity-WebGL/playback/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
}
5858

5959
var thuai9Mode = 'playback';
60-
var thuai9BuildStamp = '639152674144621830';
60+
var thuai9BuildStamp = '639154060282295972';
6161
var thuai9Query = new URLSearchParams(window.location.search);
6262
function thuai9CacheBust(url) {
6363
return url + (url.indexOf('?') >= 0 ? '&' : '?') + 'v=' + encodeURIComponent(thuai9BuildStamp);

logic/Gaming/Game.cs

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -105,46 +105,53 @@ public bool StartGame(int milliSeconds)
105105
(
106106
() =>
107107
{
108-
Thread.Sleep(GameData.CheckInterval);
109-
new Timothy.FrameRateTask.FrameRateTaskExecutor<int>
110-
(
111-
loopCondition: () => gameMap.Timer.IsGaming,
112-
loopToDo: () =>
113-
{
114-
int nowTimeMs = NowTime();
115-
TryTriggerPeriodicEvent(nowTimeMs);
116-
117-
// Count occupied compute centers per team
118-
int[] occupiedCounts = new int[teams.Count + 1];
119-
if (gameMap.GameObjDict.TryGetValue(GameObjType.COMPUTE_CENTER, out var centerList))
108+
try
109+
{
110+
Thread.Sleep(GameData.CheckInterval);
111+
new Timothy.FrameRateTask.FrameRateTaskExecutor<int>
112+
(
113+
loopCondition: () => gameMap.Timer.IsGaming,
114+
loopToDo: () =>
120115
{
121-
var centers = centerList.Cast<ComputeCenter>()?.ToNewList();
122-
if (centers != null)
116+
int nowTimeMs = NowTime();
117+
TryTriggerPeriodicEvent(nowTimeMs);
118+
119+
// Count occupied compute centers per team
120+
int[] occupiedCounts = new int[teams.Count + 1];
121+
if (gameMap.GameObjDict.TryGetValue(GameObjType.COMPUTE_CENTER, out var centerList))
123122
{
124-
foreach (var cc in centers)
123+
var centers = centerList.Cast<ComputeCenter>()?.ToNewList();
124+
if (centers != null)
125125
{
126-
if (cc.IsOccupied)
126+
foreach (var cc in centers)
127127
{
128-
long ownerId = cc.OccupiedByTeamId;
129-
if (ownerId > 0 && ownerId < occupiedCounts.Length)
130-
occupiedCounts[ownerId]++;
128+
if (cc.IsOccupied)
129+
{
130+
long ownerId = cc.OccupiedByTeamId;
131+
if (ownerId > 0 && ownerId < occupiedCounts.Length)
132+
occupiedCounts[ownerId]++;
133+
}
131134
}
132135
}
133136
}
134-
}
135-
foreach (var team in teams)
136-
{
137-
var fac = team.Value.Factory;
138-
if (fac == null) continue;
139-
fac.SetOccupiedComputeCenters(occupiedCounts[team.Key]);
140-
fac.TickComputingPower(GameData.CheckInterval);
141-
}
137+
foreach (var team in teams)
138+
{
139+
var fac = team.Value.Factory;
140+
if (fac == null) continue;
141+
fac.SetOccupiedComputeCenters(occupiedCounts[team.Key]);
142+
fac.TickComputingPower(GameData.CheckInterval);
143+
}
142144

143-
return !CheckAndHandleGameEnd();
144-
},
145-
timeInterval: GameData.CheckInterval,
146-
finallyReturn: () => 0
147-
).Start();
145+
return !CheckAndHandleGameEnd();
146+
},
147+
timeInterval: GameData.CheckInterval,
148+
finallyReturn: () => 0
149+
).Start();
150+
}
151+
catch (Exception ex)
152+
{
153+
LogicLogging.logger.LogError($"Game tick thread crashed: {ex}");
154+
}
148155
}
149156
).Start();
150157
return true;

logic/PlayBack/MessageWriter.cs

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,46 +6,61 @@ namespace Playback
66
{
77
public class MessageWriter : IDisposable
88
{
9-
/// <summary>
10-
/// 回放文件绝对路径
11-
/// </summary>
129
public string FileName { get; }
1310

1411
/// <summary>
15-
/// 写入消息数量
12+
/// 总写入消息数
1613
/// </summary>
1714
public uint WrittenNum { get; private set; } = 0;
18-
private readonly uint FlushNum; // 刷新间隔
1915

20-
private readonly CodedOutputStream cos; // Protobuf类型二进制输出流
16+
private uint sinceLastFlush = 0;
17+
private readonly uint FlushNum;
18+
19+
private readonly FileStream fs;
20+
private readonly GZipStream gzs;
21+
private readonly CodedOutputStream cos;
2122
public bool Disposed { get; private set; } = false;
2223

23-
public MessageWriter(string fileName, uint teamCount, uint playerCount, uint flushNum = 500)
24+
public MessageWriter(string fileName, uint teamCount, uint playerCount, uint flushNum = 50)
2425
{
2526
Utils.FileNameRegular(ref fileName);
26-
FileStream fs = File.Create(fileName);
27+
fs = File.Create(fileName);
2728
FileName = fs.Name;
2829
fs.WriteHeader(teamCount, playerCount);
29-
GZipStream gzs = new(fs, CompressionMode.Compress);
30+
gzs = new(fs, CompressionMode.Compress);
3031
cos = new(gzs);
3132
FlushNum = flushNum;
3233
}
3334

3435
public void WriteOne(MessageToClient msg)
3536
{
3637
if (Disposed) return;
37-
cos.WriteMessage(msg);
38-
WrittenNum++;
39-
if (WrittenNum % FlushNum == 0)
38+
try
39+
{
40+
cos.WriteMessage(msg);
41+
WrittenNum++;
42+
sinceLastFlush++;
43+
44+
if (sinceLastFlush >= FlushNum)
45+
{
46+
cos.Flush();
47+
sinceLastFlush = 0;
48+
}
49+
}
50+
catch (Exception)
4051
{
41-
Flush();
42-
WrittenNum = 0;
52+
// 写回放文件失败不应影响游戏主循环
4353
}
4454
}
4555

4656
public void Flush()
4757
{
48-
cos.Flush();
58+
try
59+
{
60+
cos.Flush();
61+
sinceLastFlush = 0;
62+
}
63+
catch { }
4964
}
5065

5166
public void Dispose()
@@ -59,7 +74,10 @@ protected virtual void Dispose(bool disposing)
5974
if (Disposed) return;
6075
if (disposing)
6176
{
62-
cos.Dispose();
77+
try { cos.Flush(); } catch { }
78+
try { cos.Dispose(); } catch { }
79+
try { gzs.Dispose(); } catch { }
80+
try { fs.Dispose(); } catch { }
6381
}
6482
Disposed = true;
6583
}

logic/Server/GameServer.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,8 @@ public void ReportGame(GameState gameState, bool requiredGaming = true)
463463
{
464464
foreach (var kvp in dict)
465465
{
466-
kvp.Value.Item1.Release();
466+
try { kvp.Value.Item1.Release(); }
467+
catch (SemaphoreFullException) { /* 客户端还没消费上一帧 */ }
467468
}
468469
}
469470

0 commit comments

Comments
 (0)