Browse Source

Merge pull request #432 from eesast/dev

fix!: 🐛 fix deadlock problem of spectator
tags/0.1.0
Changli Tang GitHub 2 years ago
parent
commit
2529754167
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 70 additions and 40 deletions
  1. +11
    -11
      CAPI/python/PyAPI/constants.py
  2. +5
    -0
      dependency/shell/run.sh
  3. +1
    -3
      docs/使用文档.md
  4. +2
    -2
      logic/Client/Properties/launchSettings.json
  5. +15
    -9
      logic/Server/GameServer.cs
  6. +2
    -2
      logic/Server/Properties/launchSettings.json
  7. +34
    -13
      logic/Server/RpcServices.cs

+ 11
- 11
CAPI/python/PyAPI/constants.py View File

@@ -51,22 +51,22 @@ class Constants(NoInstance):

# 攻击相关

Constants.basicApOfTricker = 1500000
Constants.basicCD = 3000 # 初始子弹冷却
Constants.basicCastTime = 500 # 基本前摇时间
Constants.basicBackswing = 800 # 基本后摇时间
Constants.basicRecoveryFromHit = 3700 # 基本命中攻击恢复时长
basicApOfTricker = 1500000
basicCD = 3000 # 初始子弹冷却
basicCastTime = 500 # 基本前摇时间
basicBackswing = 800 # 基本后摇时间
basicRecoveryFromHit = 3700 # 基本命中攻击恢复时长
basicStunnedTimeOfStudent = 4300

Constants.basicBulletMoveSpeed = 7400 # 基本子弹移动速度
Constants.basicRemoteAttackRange = 6000 # 基本远程攻击范围
Constants.basicAttackShortRange = 2200 # 基本近程攻击范围
Constants.basicBulletBombRange = 2000 # 基本子弹爆炸范围
basicBulletMoveSpeed = 7400 # 基本子弹移动速度
basicRemoteAttackRange = 6000 # 基本远程攻击范围
basicAttackShortRange = 2200 # 基本近程攻击范围
basicBulletBombRange = 2000 # 基本子弹爆炸范围

# 道具相关

apPropAdd = Constants.basicApOfTricker * 12 / 10
apSpearAdd = Constants.basicApOfTricker * 6 / 10
apPropAdd = basicApOfTricker * 12 / 10
apSpearAdd = basicApOfTricker * 6 / 10

# 技能相关
maxNumOfSkill = 3


+ 5
- 0
dependency/shell/run.sh View File

@@ -56,3 +56,8 @@ else
mv -f temp.lock $playback_dir/video.thuaipb
kill -9 $server_pid
fi

result=$(cat /usr/local/playback/result.json)
score0=$(parse_json $result "Student")
score1=$(parse_json $result "Tricker")
curl $URL -X PUT -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"result":[{"team_id":0, "score":'${score0}'}, {"team_id":1, "score":'${score1}'}], "mode":'${MODE}'}'

+ 1
- 3
docs/使用文档.md View File

@@ -7,9 +7,7 @@
- 不要使用conio.h,Windows.h

## 请注意下载器不更新AI.py,AI.cpp和脚本
- 最新版AI.cpp和AI.py
![AIcpp](https://raw.githubusercontent.com/shangfengh/THUAI6/new/resource/AIcpp.png)
![AIpy](https://raw.githubusercontent.com/shangfengh/THUAI6/new/resource/AIpy.png)
- [最新版AI.cpp云盘](https://cloud.tsinghua.edu.cn/lib/54b4eb7b-956e-474c-b932-7b1ac29a9267/file/AI.cpp) 和[AI.py云盘](https://cloud.tsinghua.edu.cn/lib/54b4eb7b-956e-474c-b932-7b1ac29a9267/file/AI.py)

## C++接口使用说明



+ 2
- 2
logic/Client/Properties/launchSettings.json View File

@@ -2,7 +2,7 @@
"profiles": {
"Client": {
"commandName": "Project",
"commandLineArgs": "--port 8888 --characterID 3 --type 1 --occupation 5"
"commandLineArgs": "--port 8892 --characterID 8880 --type 1 --occupation 1 --ip thuai6.eesast.com --cl"
}
}
}
}

+ 15
- 9
logic/Server/GameServer.cs View File

@@ -11,14 +11,15 @@ using Playback;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Preparation.Interface;
using System.Collections.Concurrent;


namespace Server
{
public partial class GameServer : AvailableService.AvailableServiceBase
{
private Dictionary<long, (SemaphoreSlim, SemaphoreSlim)> semaDict = new();
private object semaDictLock = new();
private ConcurrentDictionary<long, (SemaphoreSlim, SemaphoreSlim)> semaDict = new();
// private object semaDictLock = new();
protected readonly ArgumentOptions options;
private HttpSender? httpSender;
private object gameLock = new();
@@ -29,13 +30,13 @@ namespace Server
private SemaphoreSlim endGameSem = new(0);
protected readonly Game game;
private uint spectatorMinPlayerID = 2023;
private List<uint> spectatorList = new List<uint>();
public int playerNum;
public int TeamCount => options.TeamCount;
protected long[] communicationToGameID; // 通信用的ID映射到游戏内的ID,通信中0-3为Student,4为Tricker
private readonly object messageToAllClientsLock = new();
public static readonly long SendMessageToClientIntervalInMilliseconds = 50;
private MessageWriter? mwr = null;
private object spetatorJoinLock = new();

public void StartGame()
{
@@ -169,14 +170,19 @@ namespace Server
break;
}
}
foreach (var kvp in semaDict)
lock (spetatorJoinLock)
{
kvp.Value.Item1.Release();
}
foreach (var kvp in semaDict)
{
kvp.Value.Item1.Release();
}

foreach (var kvp in semaDict)
{
kvp.Value.Item2.Wait();
// 若此时观战者加入,则死锁,所以需要 spetatorJoinLock

foreach (var kvp in semaDict)
{
kvp.Value.Item2.Wait();
}
}
}
private bool playerDeceased(int playerID)


+ 2
- 2
logic/Server/Properties/launchSettings.json View File

@@ -2,7 +2,7 @@
"profiles": {
"Server": {
"commandName": "Project",
"commandLineArgs": "--ip 0.0.0.0 -p 8888 --characterID 2030"
"commandLineArgs": "--port 8888 --studentCount 4 --trickerCount 1 --gameTimeInSecond 600 --fileName video"
}
}
}
}

+ 34
- 13
logic/Server/RpcServices.cs View File

@@ -16,6 +16,7 @@ namespace Server
{
public partial class GameServer : AvailableService.AvailableServiceBase
{
private int playerCountNow = 0;
protected object spectatorLock = new object();
protected bool isSpectatorJoin = false;
protected bool IsSpectatorJoin
@@ -59,17 +60,18 @@ namespace Server
if (request.PlayerId >= spectatorMinPlayerID && options.NotAllowSpectator == false)
{
// 观战模式
uint tp = (uint)request.PlayerId;
if (!spectatorList.Contains(tp))
lock (spetatorJoinLock) // 具体原因见另一个上锁的地方
{
spectatorList.Add(tp);
Console.WriteLine("A new spectator comes to watch this game.");
var temp = (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1));
lock (semaDictLock)
if (semaDict.TryAdd(request.PlayerId, (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1))))
{
semaDict.Add(request.PlayerId, temp);
Console.WriteLine("A new spectator comes to watch this game.");
IsSpectatorJoin = true;
}
else
{
Console.WriteLine($"Duplicated Spectator ID {request.PlayerId}");
return;
}
IsSpectatorJoin = true;
}
do
{
@@ -82,13 +84,30 @@ namespace Server
//Console.WriteLine("Send!");
}
}
catch (InvalidOperationException)
{
if (semaDict.TryRemove(request.PlayerId, out var semas))
{
try
{
semas.Item1.Release();
semas.Item2.Release();
}
catch { }
Console.WriteLine($"The spectator {request.PlayerId} exited");
}
}
catch (Exception)
{
//Console.WriteLine(ex);
// Console.WriteLine(ex);
}
finally
{
semaDict[request.PlayerId].Item2.Release();
try
{
semaDict[request.PlayerId].Item2.Release();
}
catch { }
}
} while (game.GameMap.Timer.IsGaming);
return;
@@ -117,10 +136,12 @@ namespace Server
var temp = (new SemaphoreSlim(0, 1), new SemaphoreSlim(0, 1));
bool start = false;
Console.WriteLine($"Id: {request.PlayerId} joins.");
lock (semaDictLock)
// lock (semaDictLock)
{
semaDict.Add(request.PlayerId, temp);
start = (semaDict.Count - spectatorList.Count) == playerNum;
if (semaDict.TryAdd(request.PlayerId, temp))
{
start = Interlocked.Increment(ref playerCountNow) == playerNum;
}
}
if (start) StartGame();
}


Loading…
Cancel
Save