diff --git a/logic/GameClass/GameObj/Map/Map.cs b/logic/GameClass/GameObj/Map/Map.cs index dd7e6bbb..86ee053a 100644 --- a/logic/GameClass/GameObj/Map/Map.cs +++ b/logic/GameClass/GameObj/Map/Map.cs @@ -3,6 +3,7 @@ using Preparation.Interface; using Preparation.Utility; using System; +using System.Collections.Concurrent; namespace GameClass.GameObj { @@ -21,32 +22,18 @@ public void AddNumOfRepairedGenerators() uint value = Interlocked.Increment(ref numOfRepairedGenerators); if (value == GameData.numOfGeneratorRequiredForEmergencyExit) { - GameObjLockDict[GameObjType.EmergencyExit].EnterReadLock(); - try - { - Random r = new(Environment.TickCount); - EmergencyExit emergencyExit = (EmergencyExit)(GameObjDict[GameObjType.EmergencyExit][r.Next(0, GameObjDict[GameObjType.EmergencyExit].Count)]); - emergencyExit.CanOpen.SetReturnOri(true); - Preparation.Utility.Debugger.Output(emergencyExit, emergencyExit.Position.ToString()); - } - finally - { - GameObjLockDict[GameObjType.EmergencyExit].ExitReadLock(); - } + Random r = new(Environment.TickCount); + EmergencyExit emergencyExit = (EmergencyExit)(GameObjDict[GameObjType.EmergencyExit][r.Next(0, GameObjDict[GameObjType.EmergencyExit].Count)]); + emergencyExit.CanOpen.SetReturnOri(true); + Preparation.Utility.Debugger.Output(emergencyExit, emergencyExit.Position.ToString()); } else if (value == GameData.numOfGeneratorRequiredForRepair) { - GameObjLockDict[GameObjType.Doorway].EnterReadLock(); - try + GameObjDict[GameObjType.Doorway].ForEach(delegate (IGameObj doorway) { - foreach (Doorway doorway in GameObjDict[GameObjType.Doorway]) - doorway.PowerSupply.SetReturnOri(true); - } - finally - { - GameObjLockDict[GameObjType.Doorway].ExitReadLock(); - } + ((Doorway)doorway).PowerSupply.SetReturnOri(true); + }); } } @@ -113,20 +100,10 @@ public void MapRescueStudent() private void OpenEmergencyExit() { - GameObjLockDict[GameObjType.EmergencyExit].EnterReadLock(); - try - { - foreach (EmergencyExit emergencyExit in GameObjDict[GameObjType.EmergencyExit]) - if (emergencyExit.CanOpen) - { - emergencyExit.IsOpen = true; - break; - } - } - finally - { - GameObjLockDict[GameObjType.EmergencyExit].ExitReadLock(); - } + EmergencyExit? emergencyExit = + (EmergencyExit?)GameObjDict[GameObjType.EmergencyExit].Find(gameObj => ((EmergencyExit)gameObj).CanOpen); + if (emergencyExit != null) + emergencyExit.IsOpen = true; } private void AddScoreFromAddict() { @@ -134,10 +111,8 @@ private void AddScoreFromAddict() } - private Dictionary> gameObjDict; - public Dictionary> GameObjDict => gameObjDict; - private Dictionary gameObjLockDict; - public Dictionary GameObjLockDict => gameObjLockDict; + private Dictionary> gameObjDict; + public Dictionary> GameObjDict => gameObjDict; public readonly uint[,] protoGameMap; public uint[,] ProtoGameMap => protoGameMap; @@ -175,182 +150,55 @@ public IOutOfBound GetOutOfBound(XY pos) public Character? FindPlayerInID(long playerID) { - Character? player = null; - gameObjLockDict[GameObjType.Character].EnterReadLock(); - try - { - foreach (Character person in gameObjDict[GameObjType.Character]) - { - if (playerID == person.ID) - { - player = person; - break; - } - } - } - finally - { - gameObjLockDict[GameObjType.Character].ExitReadLock(); - } - return player; + return (Character?)GameObjDict[GameObjType.Character].Find(gameObj => (playerID == ((Character)gameObj).ID)); } public Character? FindPlayerInPlayerID(long playerID) { - Character? player = null; - gameObjLockDict[GameObjType.Character].EnterReadLock(); - try - { - foreach (Character person in gameObjDict[GameObjType.Character]) - { - if (playerID == person.PlayerID) - { - player = person; - break; - } - } - } - finally - { - gameObjLockDict[GameObjType.Character].ExitReadLock(); - } - return player; + return (Character?)GameObjDict[GameObjType.Character].Find(gameObj => (playerID == ((Character)gameObj).PlayerID)); } public Ghost? ghost = null; public Character? FindPlayerToAction(long playerID) { - Character? player = null; - gameObjLockDict[GameObjType.Character].EnterReadLock(); - try - { - foreach (Character person in gameObjDict[GameObjType.Character]) - { - if (playerID == person.ID) - { - if (person.CharacterType == CharacterType.TechOtaku) - { - foreach (Character character in gameObjDict[GameObjType.Character]) - { - if (((UseRobot)person.FindActiveSkill(ActiveSkillType.UseRobot)).NowPlayerID == character.PlayerID) - { - player = character; - break; - } - } - } - else player = person; - break; - } - } - } - finally - { - gameObjLockDict[GameObjType.Character].ExitReadLock(); - } + + Character? player = (Character?)GameObjDict[GameObjType.Character].Find(gameObj => (playerID == ((Character)gameObj).ID)); + if (player == null) return null; + if (player.CharacterType == CharacterType.TechOtaku) + player = (Character?)GameObjDict[GameObjType.Character].Find( + gameObj => ( + ((UseRobot)player.FindActiveSkill(ActiveSkillType.UseRobot)).NowPlayerID == ((Character)gameObj).PlayerID + ) + ); return player; } public GameObj? OneForInteract(XY Pos, GameObjType gameObjType) { - GameObj? GameObjForInteract = null; - GameObjLockDict[gameObjType].EnterReadLock(); - try - { - foreach (GameObj gameObj in GameObjDict[gameObjType]) - { - if (GameData.ApproachToInteract(gameObj.Position, Pos)) - { - GameObjForInteract = gameObj; - break; - } - } - } - finally - { - GameObjLockDict[gameObjType].ExitReadLock(); - } - return GameObjForInteract; + return (GameObj?)GameObjDict[gameObjType].Find(gameObj => GameData.ApproachToInteract(gameObj.Position, Pos)); } public Student? StudentForInteract(Student AStudent) { - GameObjLockDict[GameObjType.Character].EnterReadLock(); - try - { - foreach (Character character in GameObjDict[GameObjType.Character]) - { - if (!character.IsGhost() && character != AStudent && GameData.ApproachToInteract(character.Position, AStudent.Position)) - { - return (Student)character; - } - } - } - finally + return (Student?)GameObjDict[GameObjType.Character].Find(gameObj => { - GameObjLockDict[GameObjType.Character].ExitReadLock(); - } - return null; + Character character = (Character)gameObj; + return !character.IsGhost() && character != AStudent && GameData.ApproachToInteract(character.Position, AStudent.Position); + }); } public GameObj? OneInTheSameCell(XY Pos, GameObjType gameObjType) { - GameObj? GameObjForInteract = null; - GameObjLockDict[gameObjType].EnterReadLock(); - try - { - foreach (GameObj gameObj in GameObjDict[gameObjType]) - { - if (GameData.IsInTheSameCell(gameObj.Position, Pos)) - { - GameObjForInteract = gameObj; - break; - } - } - } - finally - { - GameObjLockDict[gameObjType].ExitReadLock(); - } - return GameObjForInteract; + return (GameObj?)GameObjDict[gameObjType].Find(gameObj => + GameData.IsInTheSameCell(gameObj.Position, Pos) + ); } public GameObj? PartInTheSameCell(XY Pos, GameObjType gameObjType) { - GameObj? GameObjForInteract = null; - GameObjLockDict[gameObjType].EnterReadLock(); - try - { - foreach (GameObj gameObj in GameObjDict[gameObjType]) - { - if (GameData.PartInTheSameCell(gameObj.Position, Pos)) - { - GameObjForInteract = gameObj; - break; - } - } - } - finally - { - GameObjLockDict[gameObjType].ExitReadLock(); - } - return GameObjForInteract; + return (GameObj?)GameObjDict[gameObjType].Find(gameObj => + GameData.PartInTheSameCell(gameObj.Position, Pos) +); } public GameObj? OneForInteractInACross(XY Pos, GameObjType gameObjType) { - GameObj? GameObjForInteract = null; - GameObjLockDict[gameObjType].EnterReadLock(); - try - { - foreach (GameObj gameObj in GameObjDict[gameObjType]) - { - if (GameData.ApproachToInteractInACross(gameObj.Position, Pos)) - { - GameObjForInteract = gameObj; - break; - } - } - } - finally - { - GameObjLockDict[gameObjType].ExitReadLock(); - } - return GameObjForInteract; + return (GameObj?)GameObjDict[gameObjType].Find(gameObj => + GameData.ApproachToInteractInACross(gameObj.Position, Pos)); } public bool CanSee(Character player, GameObj gameObj) @@ -403,70 +251,35 @@ public bool CanSee(Character player, GameObj gameObj) public bool Remove(GameObj gameObj) { - GameObj? ToDel = null; - GameObjLockDict[gameObj.Type].EnterWriteLock(); - try + if (GameObjDict[gameObj.Type].RemoveOne(obj => gameObj.ID == obj.ID)) { - foreach (GameObj obj in GameObjDict[gameObj.Type]) - { - if (gameObj.ID == obj.ID) - { - ToDel = obj; - break; - } - } - if (ToDel != null) - { - GameObjDict[gameObj.Type].Remove(ToDel); - ToDel.TryToRemove(); - } - } - finally - { - GameObjLockDict[gameObj.Type].ExitWriteLock(); + gameObj.TryToRemove(); + return true; } - return ToDel != null; + return false; } public bool RemoveJustFromMap(GameObj gameObj) { - GameObjLockDict[gameObj.Type].EnterWriteLock(); - try + if (GameObjDict[gameObj.Type].Remove(gameObj)) { - if (GameObjDict[gameObj.Type].Remove(gameObj)) - { - gameObj.TryToRemove(); - return true; - } - return false; - } - finally - { - GameObjLockDict[gameObj.Type].ExitWriteLock(); + gameObj.TryToRemove(); + return true; } + return false; } public void Add(GameObj gameObj) { - GameObjLockDict[gameObj.Type].EnterWriteLock(); - try - { - GameObjDict[gameObj.Type].Add(gameObj); - } - finally - { - GameObjLockDict[gameObj.Type].ExitWriteLock(); - } + GameObjDict[gameObj.Type].Add(gameObj); } public Map(uint[,] mapResource) { - gameObjDict = new Dictionary>(); - gameObjLockDict = new Dictionary(); + gameObjDict = new Dictionary>(); foreach (GameObjType idx in Enum.GetValues(typeof(GameObjType))) { if (idx != GameObjType.Null) { - gameObjDict.Add(idx, new List()); - gameObjLockDict.Add(idx, new ReaderWriterLockSlim()); + gameObjDict.TryAdd(idx, new LockedClassList()); } } diff --git a/logic/GameEngine/CollisionChecker.cs b/logic/GameEngine/CollisionChecker.cs index 1a7a2e31..b0f3e65f 100644 --- a/logic/GameEngine/CollisionChecker.cs +++ b/logic/GameEngine/CollisionChecker.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading; using Preparation.Interface; using Preparation.Utility; @@ -10,33 +11,25 @@ internal class CollisionChecker public IGameObj? CheckCollision(IMoveable obj, XY Pos) { // 在列表中检查碰撞 - Func, ReaderWriterLockSlim, IGameObj?> CheckCollisionInList = - (IEnumerable lst, ReaderWriterLockSlim listLock) => + Func, IGameObj?> CheckCollisionInList = + (LockedClassList lst) => { IGameObj? collisionObj = null; - listLock.EnterReadLock(); - try + foreach (IGameObj listObj in lst) { - foreach (var listObj in lst) + if (obj.WillCollideWith(listObj, Pos)) { - if (obj.WillCollideWith(listObj, Pos)) - { - collisionObj = listObj; - break; - } + collisionObj = listObj; + break; } } - finally - { - listLock.ExitReadLock(); - } return collisionObj; }; IGameObj? collisionObj; foreach (var list in lists) { - if ((collisionObj = CheckCollisionInList(list.Item1, list.Item2)) != null) + if ((collisionObj = CheckCollisionInList(list)) != null) { return collisionObj; } @@ -127,100 +120,86 @@ public double FindMax(IMoveable obj, XY nextPos, XY moveVec) double maxDistance = uint.MaxValue; foreach (var listWithLock in lists) { - var lst = listWithLock.Item1; - var listLock = listWithLock.Item2; - listLock.EnterReadLock(); - try + var lst = listWithLock; + foreach (IGameObj listObj in lst) { - foreach (IGameObj listObj in lst) + // 如果再走一步发生碰撞 + if (obj.WillCollideWith(listObj, nextPos)) { - // 如果再走一步发生碰撞 - if (obj.WillCollideWith(listObj, nextPos)) { + switch (listObj.Shape) // 默认obj为圆形 { - switch (listObj.Shape) // 默认obj为圆形 - { - case ShapeType.Circle: - { - // 计算两者之间的距离 - double mod = XY.DistanceFloor3(listObj.Position, obj.Position); - int orgDeltaX = listObj.Position.x - obj.Position.x; - int orgDeltaY = listObj.Position.y - obj.Position.y; + case ShapeType.Circle: + { + // 计算两者之间的距离 + double mod = XY.DistanceFloor3(listObj.Position, obj.Position); + int orgDeltaX = listObj.Position.x - obj.Position.x; + int orgDeltaY = listObj.Position.y - obj.Position.y; - if (mod < listObj.Radius + obj.Radius) // 如果两者已经重叠 + if (mod < listObj.Radius + obj.Radius) // 如果两者已经重叠 + { + tmpMax = 0; + } + else + { + double tmp = mod - obj.Radius - listObj.Radius; + // 计算能走的最长距离,好像这么算有一点误差? + tmp = ((int)(tmp * 1000 / Math.Cos(Math.Atan2(orgDeltaY, orgDeltaX) - moveVec.Angle()))); + if (tmp < 0 || tmp > uint.MaxValue || double.IsNaN(tmp)) { - tmpMax = 0; + tmpMax = uint.MaxValue; } else - { - double tmp = mod - obj.Radius - listObj.Radius; - // 计算能走的最长距离,好像这么算有一点误差? - tmp = ((int)(tmp * 1000 / Math.Cos(Math.Atan2(orgDeltaY, orgDeltaX) - moveVec.Angle()))); - if (tmp < 0 || tmp > uint.MaxValue || double.IsNaN(tmp)) - { - tmpMax = uint.MaxValue; - } - else - tmpMax = tmp / 1000.0; - } - break; + tmpMax = tmp / 1000.0; } - case ShapeType.Square: + break; + } + case ShapeType.Square: + { + // if (obj.WillCollideWith(listObj, obj.Position)) + // tmpMax = 0; + // else tmpMax = MaxMoveToSquare(obj, listObj); + // break; + if (obj.WillCollideWith(listObj, obj.Position)) + tmpMax = 0; + else { - // if (obj.WillCollideWith(listObj, obj.Position)) - // tmpMax = 0; - // else tmpMax = MaxMoveToSquare(obj, listObj); - // break; - if (obj.WillCollideWith(listObj, obj.Position)) - tmpMax = 0; - else + // 二分查找最大可能移动距离 + int left = 0, right = (int)moveVec.Length(); + while (left < right - 1) { - // 二分查找最大可能移动距离 - int left = 0, right = (int)moveVec.Length(); - while (left < right - 1) + int mid = (right - left) / 2 + left; + if (obj.WillCollideWith(listObj, obj.Position + new XY(moveVec, mid))) { - int mid = (right - left) / 2 + left; - if (obj.WillCollideWith(listObj, obj.Position + new XY(moveVec, mid))) - { - right = mid; - } - else - left = mid; + right = mid; } - tmpMax = (uint)left; + else + left = mid; } - break; + tmpMax = (uint)left; } - default: - tmpMax = uint.MaxValue; break; - } - if (tmpMax < maxDistance) - maxDistance = tmpMax; + } + default: + tmpMax = uint.MaxValue; + break; } + if (tmpMax < maxDistance) + maxDistance = tmpMax; } } } - finally - { - listLock.ExitReadLock(); - } } return maxDistance; } readonly IMap gameMap; - private readonly Tuple, ReaderWriterLockSlim>[] lists; + private readonly LockedClassList[] lists; public CollisionChecker(IMap gameMap) { this.gameMap = gameMap; - lists = new Tuple, ReaderWriterLockSlim>[gameMap.GameObjDict.Count]; - int i = 0; - foreach (var keyValuePair in gameMap.GameObjDict) - { - lists[i++] = new Tuple, ReaderWriterLockSlim>(keyValuePair.Value as IList, gameMap.GameObjLockDict[keyValuePair.Key]); - } + lists = gameMap.GameObjDict.Values.ToArray(); } } } diff --git a/logic/Gaming/AttackManager.cs b/logic/Gaming/AttackManager.cs index 70d61555..98e6bb9c 100644 --- a/logic/Gaming/AttackManager.cs +++ b/logic/Gaming/AttackManager.cs @@ -168,20 +168,11 @@ private void BulletBomb(Bullet bullet, GameObj? objBeingShot) { if (bullet.CanBeBombed(kvp.Key)) { - gameMap.GameObjLockDict[kvp.Key].EnterReadLock(); - try - { - foreach (var item in gameMap.GameObjDict[kvp.Key]) - if (bullet.CanAttack((GameObj)item)) - { - beAttackedList.Add(item); - } - - } - finally - { - gameMap.GameObjLockDict[kvp.Key].ExitReadLock(); - } + foreach (var item in gameMap.GameObjDict[kvp.Key]) + if (bullet.CanAttack((GameObj)item)) + { + beAttackedList.Add((IGameObj)item); + } } } diff --git a/logic/Gaming/CharacterManager.cs b/logic/Gaming/CharacterManager.cs index 9a51e869..157d4a38 100644 --- a/logic/Gaming/CharacterManager.cs +++ b/logic/Gaming/CharacterManager.cs @@ -71,96 +71,72 @@ public void DoubleFactorTeacher() bool noise = false; if (!newPlayer.IsGhost()) { - gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); - try + foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) { - foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) + if (person.IsGhost()) { - if (person.IsGhost()) + if (person.CharacterType == CharacterType.ANoisyPerson) { - if (person.CharacterType == CharacterType.ANoisyPerson) - { - noise = true; - newPlayer.AddBgm(BgmType.GhostIsComing, 1411180); - newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, 154991); - } + noise = true; + newPlayer.AddBgm(BgmType.GhostIsComing, 1411180); + newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, 154991); } } } - finally - { - gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); - } } new FrameRateTaskExecutor( loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsRemoved, loopToDo: () => { - gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); - try + if (newPlayer.IsGhost()) { - if (newPlayer.IsGhost()) + double bgmVolume = 0; + foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) { - double bgmVolume = 0; - foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) + if (!person.IsGhost() && XY.DistanceFloor3(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment)) { - if (!person.IsGhost() && XY.DistanceFloor3(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment)) - { - if ((double)newPlayer.AlertnessRadius / XY.DistanceFloor3(newPlayer.Position, person.Position) > bgmVolume) - bgmVolume = newPlayer.AlertnessRadius / XY.DistanceFloor3(newPlayer.Position, person.Position); - } + if ((double)newPlayer.AlertnessRadius / XY.DistanceFloor3(newPlayer.Position, person.Position) > bgmVolume) + bgmVolume = newPlayer.AlertnessRadius / XY.DistanceFloor3(newPlayer.Position, person.Position); } - newPlayer.AddBgm(BgmType.StudentIsApproaching, bgmVolume); } - else + newPlayer.AddBgm(BgmType.StudentIsApproaching, bgmVolume); + } + else + { + foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) { - foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) + if (person.IsGhost()) { - if (person.IsGhost()) + if (!noise) { - if (!noise) - { - if (XY.DistanceFloor3(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment)) - newPlayer.AddBgm(BgmType.GhostIsComing, (double)newPlayer.AlertnessRadius / XY.DistanceFloor3(newPlayer.Position, person.Position)); - else newPlayer.AddBgm(BgmType.GhostIsComing, 0); - } - if (newPlayer.CharacterType != CharacterType.Teacher && newPlayer.CharacterType != CharacterType.Robot && newPlayer.CanPinDown() && XY.DistanceFloor3(newPlayer.Position, person.Position) <= GameData.PinningDownRange) - { - TimePinningDown += GameData.checkInterval; - newPlayer.AddScore(GameData.StudentScorePinDown(TimePinningDown) - ScoreAdded); - ScoreAdded = GameData.StudentScorePinDown(TimePinningDown); - } - else TimePinningDown = ScoreAdded = 0; - break; + if (XY.DistanceFloor3(newPlayer.Position, person.Position) <= (newPlayer.AlertnessRadius / person.Concealment)) + newPlayer.AddBgm(BgmType.GhostIsComing, (double)newPlayer.AlertnessRadius / XY.DistanceFloor3(newPlayer.Position, person.Position)); + else newPlayer.AddBgm(BgmType.GhostIsComing, 0); } + if (newPlayer.CharacterType != CharacterType.Teacher && newPlayer.CharacterType != CharacterType.Robot && newPlayer.CanPinDown() && XY.DistanceFloor3(newPlayer.Position, person.Position) <= GameData.PinningDownRange) + { + TimePinningDown += GameData.checkInterval; + newPlayer.AddScore(GameData.StudentScorePinDown(TimePinningDown) - ScoreAdded); + ScoreAdded = GameData.StudentScorePinDown(TimePinningDown); + } + else TimePinningDown = ScoreAdded = 0; + break; } } } - finally - { - gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); - } if (!noise) { - gameMap.GameObjLockDict[GameObjType.Generator].EnterReadLock(); - try + double bgmVolume = 0; + foreach (Generator generator in gameMap.GameObjDict[GameObjType.Generator]) { - double bgmVolume = 0; - foreach (Generator generator in gameMap.GameObjDict[GameObjType.Generator]) + if (XY.DistanceFloor3(newPlayer.Position, generator.Position) <= newPlayer.AlertnessRadius) { - if (XY.DistanceFloor3(newPlayer.Position, generator.Position) <= newPlayer.AlertnessRadius) - { - if (generator.NumOfFixing > 0 && (double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.DistanceFloor3(newPlayer.Position, generator.Position) > bgmVolume) - bgmVolume = (double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.DistanceFloor3(newPlayer.Position, generator.Position); - } + if (generator.NumOfFixing > 0 && (double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.DistanceFloor3(newPlayer.Position, generator.Position) > bgmVolume) + bgmVolume = (double)newPlayer.AlertnessRadius * generator.DegreeOfRepair / GameData.degreeOfFixedGenerator / XY.DistanceFloor3(newPlayer.Position, generator.Position); } - newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, bgmVolume); - } - finally - { - gameMap.GameObjLockDict[GameObjType.Generator].ExitReadLock(); } + newPlayer.AddBgm(BgmType.GeneratorIsBeingFixed, bgmVolume); } }, timeInterval: GameData.checkInterval, diff --git a/logic/Gaming/Game.cs b/logic/Gaming/Game.cs index 02d783cb..2b47d90e 100644 --- a/logic/Gaming/Game.cs +++ b/logic/Gaming/Game.cs @@ -281,17 +281,9 @@ public void AllPlayerUsePassiveSkill() { if (!gameMap.Timer.IsGaming) return; - gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); - try + foreach (Character player in gameMap.GameObjDict[GameObjType.Character]) { - foreach (Character player in gameMap.GameObjDict[GameObjType.Character]) - { - skillManager.UseAllPassiveSkill(player); - } - } - finally - { - gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); + skillManager.UseAllPassiveSkill(player); } } @@ -319,22 +311,14 @@ public void ClearAllLists() { if (!GameData.NeedCopy(keyValuePair.Key)) { - gameMap.GameObjLockDict[keyValuePair.Key].EnterWriteLock(); - try + if (keyValuePair.Key == GameObjType.Character) { - if (keyValuePair.Key == GameObjType.Character) + foreach (Character player in gameMap.GameObjDict[GameObjType.Character]) { - foreach (Character player in gameMap.GameObjDict[GameObjType.Character]) - { - player.CanMove.SetReturnOri(false); - } + player.CanMove.SetReturnOri(false); } - gameMap.GameObjDict[keyValuePair.Key].Clear(); - } - finally - { - gameMap.GameObjLockDict[keyValuePair.Key].ExitWriteLock(); } + gameMap.GameObjDict[keyValuePair.Key].Clear(); } } } @@ -350,15 +334,7 @@ public List GetGameObj() { if (GameData.NeedCopy(keyValuePair.Key)) { - gameMap.GameObjLockDict[keyValuePair.Key].EnterReadLock(); - try - { - gameObjList.AddRange(gameMap.GameObjDict[keyValuePair.Key]); - } - finally - { - gameMap.GameObjLockDict[keyValuePair.Key].ExitReadLock(); - } + gameObjList.AddRange(gameMap.GameObjDict[keyValuePair.Key].ToNewList()); } } return gameObjList; diff --git a/logic/Gaming/PropManager.cs b/logic/Gaming/PropManager.cs index b370710b..4a1f18f4 100644 --- a/logic/Gaming/PropManager.cs +++ b/logic/Gaming/PropManager.cs @@ -83,24 +83,16 @@ public bool PickProp(Character player, PropType propType = PropType.Null) } else { - gameMap.GameObjLockDict[GameObjType.Gadget].EnterReadLock(); - try + foreach (Gadget prop in gameMap.GameObjDict[GameObjType.Gadget]) { - foreach (Gadget prop in gameMap.GameObjDict[GameObjType.Gadget]) + if (prop.GetPropType() == propType) { - if (prop.GetPropType() == propType) + if (GameData.IsInTheSameCell(prop.Position, player.Position) && prop.CanMove == false) { - if (GameData.IsInTheSameCell(prop.Position, player.Position) && prop.CanMove == false) - { - pickProp = player.PropInventory[indexing] = prop; - } + pickProp = player.PropInventory[indexing] = prop; } } } - finally - { - gameMap.GameObjLockDict[GameObjType.Gadget].ExitReadLock(); - } } if (pickProp.GetPropType() != PropType.Null) @@ -142,47 +134,39 @@ public void StartProducing() int len = availableCellForGenerateProp.Count; Random r = new Random(Environment.TickCount); - gameMap.GameObjLockDict[GameObjType.Chest].EnterReadLock(); - try + int cou = 0; + while (cou < GameData.numOfKeyEachArea) { - int cou = 0; - while (cou < GameData.numOfKeyEachArea) - { - ++cou; - Chest chest = GetChest(r); - chest.PropInChest[1] = new Key3(chest.Position); - chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); - } - cou = 0; - while (cou < GameData.numOfKeyEachArea) - { - ++cou; - Chest chest = GetChest(r); - chest.PropInChest[1] = new Key5(chest.Position); - chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); - } - cou = 0; - while (cou < GameData.numOfKeyEachArea) - { - ++cou; - Chest chest = GetChest(r); - chest.PropInChest[1] = new Key6(chest.Position); - chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); - } + ++cou; + Chest chest = GetChest(r); + chest.PropInChest[1] = new Key3(chest.Position); + chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); + } + cou = 0; + while (cou < GameData.numOfKeyEachArea) + { + ++cou; + Chest chest = GetChest(r); + chest.PropInChest[1] = new Key5(chest.Position); + chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); + } + cou = 0; + while (cou < GameData.numOfKeyEachArea) + { + ++cou; + Chest chest = GetChest(r); + chest.PropInChest[1] = new Key6(chest.Position); + chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); + } - foreach (Chest chest in gameMap.GameObjDict[GameObjType.Chest]) + foreach (Chest chest in gameMap.GameObjDict[GameObjType.Chest]) + { + if (chest.PropInChest[0].GetPropType() == PropType.Null) { - if (chest.PropInChest[0].GetPropType() == PropType.Null) - { - chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); - chest.PropInChest[1] = ProduceOnePropNotKey(r, chest.Position); - } + chest.PropInChest[0] = ProduceOnePropNotKey(r, chest.Position); + chest.PropInChest[1] = ProduceOnePropNotKey(r, chest.Position); } } - finally - { - gameMap.GameObjLockDict[GameObjType.Chest].ExitReadLock(); - } /* new Thread ( diff --git a/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs b/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs index c2326a83..e3a5eafe 100644 --- a/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs +++ b/logic/Gaming/SkillManager/SkillManager.ActiveSkill.cs @@ -43,35 +43,27 @@ public bool ShowTime(Character player) loopCondition: () => player.Commandable() && gameMap.Timer.IsGaming, loopToDo: () => { - gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); - try + foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) { - foreach (Character person in gameMap.GameObjDict[GameObjType.Character]) + if (!person.IsGhost() && person.CharacterType != CharacterType.Robot && !person.NoHp()) { - if (!person.IsGhost() && person.CharacterType != CharacterType.Robot && !person.NoHp()) + double dis = XY.DistanceFloor3(person.Position, player.Position); + if (dis >= player.AlertnessRadius) { - double dis = XY.DistanceFloor3(person.Position, player.Position); - if (dis >= player.AlertnessRadius) - { - person.AddMoveSpeed(GameData.checkIntervalWhenShowTime, dis / player.AlertnessRadius); - actionManager.MovePlayerWhenStunned(person, GameData.checkIntervalWhenShowTime, (player.Position - person.Position).Angle()); - } - else if (dis >= player.ViewRange) + person.AddMoveSpeed(GameData.checkIntervalWhenShowTime, dis / player.AlertnessRadius); + actionManager.MovePlayerWhenStunned(person, GameData.checkIntervalWhenShowTime, (player.Position - person.Position).Angle()); + } + else if (dis >= player.ViewRange) + { + Student student = (Student)person; + student.GamingAddiction.AddPositiveV(GameData.checkIntervalWhenShowTime); + if (student.GamingAddiction.IsMaxV()) { - Student student = (Student)person; - student.GamingAddiction.AddPositiveV(GameData.checkIntervalWhenShowTime); - if (student.GamingAddiction.IsMaxV()) - { - characterManager.Die(student); - } + characterManager.Die(student); } } } } - finally - { - gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); - } }, timeInterval: GameData.checkIntervalWhenShowTime, maxTotalDuration: skill.DurationTime, @@ -178,22 +170,15 @@ public bool SparksNSplash(Character player, int AttackID) loopToDo: () => { dis = ((homingMissile == null || homingMissile.IsRemoved) ? double.MaxValue : XY.DistanceFloor3(homingMissile.Position, whoAttacked.Position)); - gameMap.GameObjLockDict[GameObjType.Bullet].EnterReadLock(); - try + + foreach (Bullet bullet in gameMap.GameObjDict[GameObjType.Bullet]) { - foreach (Bullet bullet in gameMap.GameObjDict[GameObjType.Bullet]) + if (!bullet.CanMove && XY.DistanceFloor3(bullet.Position, whoAttacked.Position) < dis && bullet.TypeOfBullet == BulletType.JumpyDumpty) { - if (!bullet.CanMove && XY.DistanceFloor3(bullet.Position, whoAttacked.Position) < dis && bullet.TypeOfBullet == BulletType.JumpyDumpty) - { - homingMissile = bullet; - dis = XY.DistanceFloor3(bullet.Position, whoAttacked.Position); - } + homingMissile = bullet; + dis = XY.DistanceFloor3(bullet.Position, whoAttacked.Position); } } - finally - { - gameMap.GameObjLockDict[GameObjType.Bullet].ExitReadLock(); - } if (homingMissile != null) { homingMissile.CanMove.SetReturnOri(true); @@ -309,22 +294,14 @@ public bool Howl(Character player) if ((!player.Commandable())) return false; return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Howl), player, () => { - gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); - try + foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) { - foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) + if (!character.IsGhost() && !character.NoHp() && XY.DistanceFloor3(character.Position, player.Position) <= player.ViewRange) { - if (!character.IsGhost() && !character.NoHp() && XY.DistanceFloor3(character.Position, player.Position) <= player.ViewRange) - { - if (CharacterManager.BeStunned(character, GameData.timeOfStudentStunnedWhenHowl) > 0) - player.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.timeOfStudentStunnedWhenHowl)); - } + if (CharacterManager.BeStunned(character, GameData.timeOfStudentStunnedWhenHowl) > 0) + player.AddScore(GameData.TrickerScoreStudentBeStunned(GameData.timeOfStudentStunnedWhenHowl)); } } - finally - { - gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); - } characterManager.BackSwing(player, GameData.timeOfGhostSwingingAfterHowl); Debugger.Output(player, "howled!"); }, @@ -337,29 +314,21 @@ public bool Punish(Character player) if ((!player.Commandable())) return false; return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Punish), player, () => { - gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); - try + foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) { - foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) + if (character.IsGhost() && + (character.PlayerState == PlayerStateType.TryingToAttack || character.PlayerState == PlayerStateType.Swinging + || character.PlayerState == PlayerStateType.UsingSkill + || character.PlayerState == PlayerStateType.LockingTheDoor || character.PlayerState == PlayerStateType.OpeningTheDoor + || character.PlayerState == PlayerStateType.ClimbingThroughWindows) + && XY.DistanceFloor3(character.Position, player.Position) <= player.ViewRange / 3) { - if (character.IsGhost() && - (character.PlayerState == PlayerStateType.TryingToAttack || character.PlayerState == PlayerStateType.Swinging - || character.PlayerState == PlayerStateType.UsingSkill - || character.PlayerState == PlayerStateType.LockingTheDoor || character.PlayerState == PlayerStateType.OpeningTheDoor - || character.PlayerState == PlayerStateType.ClimbingThroughWindows) - && XY.DistanceFloor3(character.Position, player.Position) <= player.ViewRange / 3) - { - int stunTime = (GameData.timeOfGhostStunnedWhenPunish + (int)((GameData.factorOfTimeStunnedWhenPunish * (player.HP.GetMaxV() - player.HP) / GameData.basicApOfGhost))) / characterManager.FactorTeacher; - if (CharacterManager.BeStunned(character, stunTime) > 0) - player.AddScore(GameData.StudentScoreTrickerBeStunned(stunTime) / characterManager.FactorTeacher); - break; - } + int stunTime = (GameData.timeOfGhostStunnedWhenPunish + (int)((GameData.factorOfTimeStunnedWhenPunish * (player.HP.GetMaxV() - player.HP) / GameData.basicApOfGhost))) / characterManager.FactorTeacher; + if (CharacterManager.BeStunned(character, stunTime) > 0) + player.AddScore(GameData.StudentScoreTrickerBeStunned(stunTime) / characterManager.FactorTeacher); + break; } } - finally - { - gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); - } Debugger.Output(player, "uses punishing!"); }, () => @@ -411,28 +380,20 @@ public bool Rouse(Character player) if ((!player.Commandable())) return false; return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Rouse), player, () => { - gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); - try + foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) { - foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) + lock (character.ActionLock) { - lock (character.ActionLock) + if ((character.PlayerState == PlayerStateType.Addicted) && gameMap.CanSee(player, character)) { - if ((character.PlayerState == PlayerStateType.Addicted) && gameMap.CanSee(player, character)) - { - character.SetPlayerStateNaturally(); - character.HP.SetPositiveV(GameData.RemainHpWhenAddLife); - ((Student)character).TimeOfRescue.SetReturnOri(0); - player.AddScore(GameData.StudentScoreRescue); - break; - } + character.SetPlayerStateNaturally(); + character.HP.SetPositiveV(GameData.RemainHpWhenAddLife); + ((Student)character).TimeOfRescue.SetReturnOri(0); + player.AddScore(GameData.StudentScoreRescue); + break; } } } - finally - { - gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); - } Debugger.Output(player, "rouse someone!"); }, () => @@ -444,24 +405,16 @@ public bool Encourage(Character player) if ((!player.Commandable())) return false; return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Encourage), player, () => { - gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); - try + foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) { - foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) + if ((character.HP < character.HP.GetMaxV()) && gameMap.CanSee(player, character)) { - if ((character.HP < character.HP.GetMaxV()) && gameMap.CanSee(player, character)) - { - player.AddScore(GameData.StudentScoreTreat(GameData.addHpWhenEncourage)); - character.HP.AddPositiveV(GameData.addHpWhenEncourage); - ((Student)character).SetDegreeOfTreatment0(); - break; - } + player.AddScore(GameData.StudentScoreTreat(GameData.addHpWhenEncourage)); + character.HP.AddPositiveV(GameData.addHpWhenEncourage); + ((Student)character).SetDegreeOfTreatment0(); + break; } } - finally - { - gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); - } Debugger.Output(player, "encourage someone!"); }, () => @@ -473,22 +426,14 @@ public bool Inspire(Character player) if ((!player.Commandable())) return false; return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Inspire), player, () => { - gameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); - try + foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) { - foreach (Character character in gameMap.GameObjDict[GameObjType.Character]) + if (gameMap.CanSee(player, character) && !character.IsGhost()) { - if (gameMap.CanSee(player, character) && !character.IsGhost()) - { - player.AddScore(GameData.ScoreInspire); - character.AddMoveSpeed(GameData.timeOfAddingSpeedWhenInspire, GameData.addedTimeOfSpeedWhenInspire); - } + player.AddScore(GameData.ScoreInspire); + character.AddMoveSpeed(GameData.timeOfAddingSpeedWhenInspire, GameData.addedTimeOfSpeedWhenInspire); } } - finally - { - gameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); - } Debugger.Output(player, "inspires!"); }, () => diff --git a/logic/Preparation/Interface/IMap.cs b/logic/Preparation/Interface/IMap.cs index e504121d..11346539 100644 --- a/logic/Preparation/Interface/IMap.cs +++ b/logic/Preparation/Interface/IMap.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System.Collections.Concurrent; +using System.Collections.Generic; using System.Threading; using Preparation.Utility; @@ -9,8 +10,7 @@ public interface IMap ITimer Timer { get; } // the two dicts must have same keys - Dictionary> GameObjDict { get; } - Dictionary GameObjLockDict { get; } + Dictionary> GameObjDict { get; } public uint[,] ProtoGameMap { get; } public PlaceType GetPlaceType(IGameObj obj); diff --git a/logic/Preparation/Utility/SafeValue/Atomic.cs b/logic/Preparation/Utility/SafeValue/Atomic.cs index dc9c570e..5f9b31ec 100644 --- a/logic/Preparation/Utility/SafeValue/Atomic.cs +++ b/logic/Preparation/Utility/SafeValue/Atomic.cs @@ -1,5 +1,4 @@ -using Google.Protobuf.WellKnownTypes; -using System; +using System; using System.Threading; namespace Preparation.Utility diff --git a/logic/Preparation/Utility/SafeValue/ListLocked.cs b/logic/Preparation/Utility/SafeValue/ListLocked.cs new file mode 100644 index 00000000..fbee8556 --- /dev/null +++ b/logic/Preparation/Utility/SafeValue/ListLocked.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Threading; + +namespace Preparation.Utility +{ + public class LockedClassList : IEnumerable + where T : class + { + private readonly ReaderWriterLockSlim listLock = new(); + private List list; + + #region 构造 + public LockedClassList() + { + list = new List(); + } + public LockedClassList(int capacity) + { + list = new List(capacity); + } + public LockedClassList(IEnumerable collection) + { + list = new List(collection); + } + #endregion + + #region 修改 + public TResult WriteLock(Func func) + { + listLock.EnterWriteLock(); + try + { + return func(); + } + finally + { + listLock.ExitWriteLock(); + } + + } + public void WriteLock(Action func) + { + listLock.EnterWriteLock(); + try + { + func(); + } + finally + { + listLock.ExitWriteLock(); + } + + } + + public void Add(T item) + { + WriteLock(() => { list.Add(item); }); + } + + public void Insert(int index, T item) + { + WriteLock(() => { list.Insert(index, item); }); + } + + public void Clear() + { + WriteLock(() => { list.Clear(); }); + } + + public bool Remove(T item) + { + return WriteLock(() => { return list.Remove(item); }); + } + + public int RemoveAll(T item) => WriteLock(() => { return list.RemoveAll((t) => { return t == item; }); }); + + public bool RemoveOne(Predicate match) => + WriteLock(() => + { + int index = list.FindIndex(match); + if (index == -1) return false; + list.RemoveAt(index); + return true; + }); + + public int RemoveAll(Predicate match) => WriteLock(() => { return list.RemoveAll(match); }); + + public bool RemoveAt(int index) + { + return WriteLock(() => + { + if (index > list.Count) return false; + list.RemoveAt(index); + return true; + }); + } + #endregion + + #region 读取与对类操作 + public TResult ReadLock(Func func) + { + listLock.EnterReadLock(); + try + { + return func(); + } + finally + { + listLock.ExitReadLock(); + } + } + public void ReadLock(Action func) + { + listLock.EnterReadLock(); + try + { + func(); + } + finally + { + listLock.ExitReadLock(); + } + + } + + public T this[int index] + { + get + { + return ReadLock(() => { return list[index]; }); + } + set + { + ReadLock(() => { list[index] = value!; }); + } + } + public int Count => ReadLock(() => { return list.Count; }); + + public int IndexOf(T item) + { + return ReadLock(() => { return list.IndexOf(item); }); + } + + public Array ToArray() + { + return ReadLock(() => { return list.ToArray(); }); + } + + public List ToNewList() + { + List lt = new(); + return ReadLock(() => { lt.AddRange(list); return lt; }); + } + + public bool Contains(T item) + { + return ReadLock(() => { return list.Contains(item); }); + } + + public T? Find(Predicate match) + { + return ReadLock(() => { return list.Find(match); }); + } + + public List FindAll(Predicate match) + { + return ReadLock(() => { return list.FindAll(match); }); + } + + public int FindIndex(Predicate match) => ReadLock(() => { return list.FindIndex(match); }); + + public void ForEach(Action action) => ReadLock(() => { list.ForEach(action); }); + + public IEnumerator GetEnumerator() + { + return ReadLock(() => { return list.GetEnumerator(); }); + } + #endregion + } +} \ No newline at end of file diff --git a/logic/Server/GameServer.cs b/logic/Server/GameServer.cs index afebe2f7..35df1317 100644 --- a/logic/Server/GameServer.cs +++ b/logic/Server/GameServer.cs @@ -173,17 +173,9 @@ public void ReportGame(GameState gameState, bool requiredGaming = true) } private bool playerDeceased(int playerID) { - game.GameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); - try + foreach (Character character in game.GameMap.GameObjDict[GameObjType.Character]) { - foreach (Character character in game.GameMap.GameObjDict[GameObjType.Character]) - { - if (character.PlayerID == playerID && character.PlayerState == PlayerStateType.Deceased) return true; - } - } - finally - { - game.GameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); + if (character.PlayerID == playerID && character.PlayerState == PlayerStateType.Deceased) return true; } return false; } @@ -191,19 +183,10 @@ private bool playerDeceased(int playerID) public override int[] GetScore() { int[] score = new int[2]; // 0代表Student,1代表Tricker - game.GameMap.GameObjLockDict[GameObjType.Character].EnterReadLock(); - try - { - foreach (Character character in game.GameMap.GameObjDict[GameObjType.Character]) - { - if (!character.IsGhost()) score[0] += (int)character.Score; - else score[1] += (int)character.Score; - } - - } - finally + foreach (Character character in game.GameMap.GameObjDict[GameObjType.Character]) { - game.GameMap.GameObjLockDict[GameObjType.Character].ExitReadLock(); + if (!character.IsGhost()) score[0] += (int)character.Score; + else score[1] += (int)character.Score; } return score; }