| @@ -3,6 +3,7 @@ using System.Threading; | |||||
| using Preparation.Interface; | using Preparation.Interface; | ||||
| using Preparation.Utility; | using Preparation.Utility; | ||||
| using System; | using System; | ||||
| using System.Collections.Concurrent; | |||||
| namespace GameClass.GameObj | namespace GameClass.GameObj | ||||
| { | { | ||||
| @@ -21,32 +22,18 @@ namespace GameClass.GameObj | |||||
| uint value = Interlocked.Increment(ref numOfRepairedGenerators); | uint value = Interlocked.Increment(ref numOfRepairedGenerators); | ||||
| if (value == GameData.numOfGeneratorRequiredForEmergencyExit) | 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 | else | ||||
| if (value == GameData.numOfGeneratorRequiredForRepair) | 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 @@ namespace GameClass.GameObj | |||||
| private void OpenEmergencyExit() | 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() | private void AddScoreFromAddict() | ||||
| { | { | ||||
| @@ -134,10 +111,8 @@ namespace GameClass.GameObj | |||||
| } | } | ||||
| private Dictionary<GameObjType, IList<IGameObj>> gameObjDict; | |||||
| public Dictionary<GameObjType, IList<IGameObj>> GameObjDict => gameObjDict; | |||||
| private Dictionary<GameObjType, ReaderWriterLockSlim> gameObjLockDict; | |||||
| public Dictionary<GameObjType, ReaderWriterLockSlim> GameObjLockDict => gameObjLockDict; | |||||
| private Dictionary<GameObjType, LockedClassList<IGameObj>> gameObjDict; | |||||
| public Dictionary<GameObjType, LockedClassList<IGameObj>> GameObjDict => gameObjDict; | |||||
| public readonly uint[,] protoGameMap; | public readonly uint[,] protoGameMap; | ||||
| public uint[,] ProtoGameMap => protoGameMap; | public uint[,] ProtoGameMap => protoGameMap; | ||||
| @@ -175,182 +150,55 @@ namespace GameClass.GameObj | |||||
| public Character? FindPlayerInID(long playerID) | 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) | 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 Ghost? ghost = null; | ||||
| public Character? FindPlayerToAction(long playerID) | 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; | return player; | ||||
| } | } | ||||
| public GameObj? OneForInteract(XY Pos, GameObjType gameObjType) | 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) | 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) | 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) | 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) | 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) | public bool CanSee(Character player, GameObj gameObj) | ||||
| @@ -403,70 +251,35 @@ namespace GameClass.GameObj | |||||
| public bool Remove(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) | 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) | 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) | public Map(uint[,] mapResource) | ||||
| { | { | ||||
| gameObjDict = new Dictionary<GameObjType, IList<IGameObj>>(); | |||||
| gameObjLockDict = new Dictionary<GameObjType, ReaderWriterLockSlim>(); | |||||
| gameObjDict = new Dictionary<GameObjType, LockedClassList<IGameObj>>(); | |||||
| foreach (GameObjType idx in Enum.GetValues(typeof(GameObjType))) | foreach (GameObjType idx in Enum.GetValues(typeof(GameObjType))) | ||||
| { | { | ||||
| if (idx != GameObjType.Null) | if (idx != GameObjType.Null) | ||||
| { | { | ||||
| gameObjDict.Add(idx, new List<IGameObj>()); | |||||
| gameObjLockDict.Add(idx, new ReaderWriterLockSlim()); | |||||
| gameObjDict.TryAdd(idx, new LockedClassList<IGameObj>()); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,5 +1,6 @@ | |||||
| using System; | using System; | ||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Linq; | |||||
| using System.Threading; | using System.Threading; | ||||
| using Preparation.Interface; | using Preparation.Interface; | ||||
| using Preparation.Utility; | using Preparation.Utility; | ||||
| @@ -10,33 +11,25 @@ namespace GameEngine | |||||
| public IGameObj? CheckCollision(IMoveable obj, XY Pos) | public IGameObj? CheckCollision(IMoveable obj, XY Pos) | ||||
| { | { | ||||
| // 在列表中检查碰撞 | // 在列表中检查碰撞 | ||||
| Func<IEnumerable<IGameObj>, ReaderWriterLockSlim, IGameObj?> CheckCollisionInList = | |||||
| (IEnumerable<IGameObj> lst, ReaderWriterLockSlim listLock) => | |||||
| Func<LockedClassList<IGameObj>, IGameObj?> CheckCollisionInList = | |||||
| (LockedClassList<IGameObj> lst) => | |||||
| { | { | ||||
| IGameObj? collisionObj = null; | 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; | return collisionObj; | ||||
| }; | }; | ||||
| IGameObj? collisionObj; | IGameObj? collisionObj; | ||||
| foreach (var list in lists) | foreach (var list in lists) | ||||
| { | { | ||||
| if ((collisionObj = CheckCollisionInList(list.Item1, list.Item2)) != null) | |||||
| if ((collisionObj = CheckCollisionInList(list)) != null) | |||||
| { | { | ||||
| return collisionObj; | return collisionObj; | ||||
| } | } | ||||
| @@ -127,100 +120,86 @@ namespace GameEngine | |||||
| double maxDistance = uint.MaxValue; | double maxDistance = uint.MaxValue; | ||||
| foreach (var listWithLock in lists) | 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 | 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; | break; | ||||
| } | |||||
| if (tmpMax < maxDistance) | |||||
| maxDistance = tmpMax; | |||||
| } | |||||
| default: | |||||
| tmpMax = uint.MaxValue; | |||||
| break; | |||||
| } | } | ||||
| if (tmpMax < maxDistance) | |||||
| maxDistance = tmpMax; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| finally | |||||
| { | |||||
| listLock.ExitReadLock(); | |||||
| } | |||||
| } | } | ||||
| return maxDistance; | return maxDistance; | ||||
| } | } | ||||
| readonly IMap gameMap; | readonly IMap gameMap; | ||||
| private readonly Tuple<IEnumerable<IGameObj>, ReaderWriterLockSlim>[] lists; | |||||
| private readonly LockedClassList<IGameObj>[] lists; | |||||
| public CollisionChecker(IMap gameMap) | public CollisionChecker(IMap gameMap) | ||||
| { | { | ||||
| this.gameMap = gameMap; | this.gameMap = gameMap; | ||||
| lists = new Tuple<IEnumerable<IGameObj>, ReaderWriterLockSlim>[gameMap.GameObjDict.Count]; | |||||
| int i = 0; | |||||
| foreach (var keyValuePair in gameMap.GameObjDict) | |||||
| { | |||||
| lists[i++] = new Tuple<IEnumerable<IGameObj>, ReaderWriterLockSlim>(keyValuePair.Value as IList<IGameObj>, gameMap.GameObjLockDict[keyValuePair.Key]); | |||||
| } | |||||
| lists = gameMap.GameObjDict.Values.ToArray(); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -168,20 +168,11 @@ namespace Gaming | |||||
| { | { | ||||
| if (bullet.CanBeBombed(kvp.Key)) | 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); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -71,96 +71,72 @@ namespace Gaming | |||||
| bool noise = false; | bool noise = false; | ||||
| if (!newPlayer.IsGhost()) | 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<int>( | new FrameRateTaskExecutor<int>( | ||||
| loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsRemoved, | loopCondition: () => gameMap.Timer.IsGaming && !newPlayer.IsRemoved, | ||||
| loopToDo: () => | 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) | 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, | timeInterval: GameData.checkInterval, | ||||
| @@ -281,17 +281,9 @@ namespace Gaming | |||||
| { | { | ||||
| if (!gameMap.Timer.IsGaming) | if (!gameMap.Timer.IsGaming) | ||||
| return; | 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 @@ namespace Gaming | |||||
| { | { | ||||
| if (!GameData.NeedCopy(keyValuePair.Key)) | 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 @@ namespace Gaming | |||||
| { | { | ||||
| if (GameData.NeedCopy(keyValuePair.Key)) | 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; | return gameObjList; | ||||
| @@ -83,24 +83,16 @@ namespace Gaming | |||||
| } | } | ||||
| else | 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) | if (pickProp.GetPropType() != PropType.Null) | ||||
| @@ -142,47 +134,39 @@ namespace Gaming | |||||
| int len = availableCellForGenerateProp.Count; | int len = availableCellForGenerateProp.Count; | ||||
| Random r = new Random(Environment.TickCount); | 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 | new Thread | ||||
| ( | ( | ||||
| @@ -43,35 +43,27 @@ namespace Gaming | |||||
| loopCondition: () => player.Commandable() && gameMap.Timer.IsGaming, | loopCondition: () => player.Commandable() && gameMap.Timer.IsGaming, | ||||
| loopToDo: () => | 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, | timeInterval: GameData.checkIntervalWhenShowTime, | ||||
| maxTotalDuration: skill.DurationTime, | maxTotalDuration: skill.DurationTime, | ||||
| @@ -178,22 +170,15 @@ namespace Gaming | |||||
| loopToDo: () => | loopToDo: () => | ||||
| { | { | ||||
| dis = ((homingMissile == null || homingMissile.IsRemoved) ? double.MaxValue : XY.DistanceFloor3(homingMissile.Position, whoAttacked.Position)); | 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) | if (homingMissile != null) | ||||
| { | { | ||||
| homingMissile.CanMove.SetReturnOri(true); | homingMissile.CanMove.SetReturnOri(true); | ||||
| @@ -309,22 +294,14 @@ namespace Gaming | |||||
| if ((!player.Commandable())) return false; | if ((!player.Commandable())) return false; | ||||
| return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Howl), player, () => | 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); | characterManager.BackSwing(player, GameData.timeOfGhostSwingingAfterHowl); | ||||
| Debugger.Output(player, "howled!"); | Debugger.Output(player, "howled!"); | ||||
| }, | }, | ||||
| @@ -337,29 +314,21 @@ namespace Gaming | |||||
| if ((!player.Commandable())) return false; | if ((!player.Commandable())) return false; | ||||
| return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Punish), player, () => | 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!"); | Debugger.Output(player, "uses punishing!"); | ||||
| }, | }, | ||||
| () => | () => | ||||
| @@ -411,28 +380,20 @@ namespace Gaming | |||||
| if ((!player.Commandable())) return false; | if ((!player.Commandable())) return false; | ||||
| return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Rouse), player, () => | 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!"); | Debugger.Output(player, "rouse someone!"); | ||||
| }, | }, | ||||
| () => | () => | ||||
| @@ -444,24 +405,16 @@ namespace Gaming | |||||
| if ((!player.Commandable())) return false; | if ((!player.Commandable())) return false; | ||||
| return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Encourage), player, () => | 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!"); | Debugger.Output(player, "encourage someone!"); | ||||
| }, | }, | ||||
| () => | () => | ||||
| @@ -473,22 +426,14 @@ namespace Gaming | |||||
| if ((!player.Commandable())) return false; | if ((!player.Commandable())) return false; | ||||
| return ActiveSkillEffect(player.FindActiveSkill(ActiveSkillType.Inspire), player, () => | 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!"); | Debugger.Output(player, "inspires!"); | ||||
| }, | }, | ||||
| () => | () => | ||||
| @@ -1,4 +1,5 @@ | |||||
| using System.Collections.Generic; | |||||
| using System.Collections.Concurrent; | |||||
| using System.Collections.Generic; | |||||
| using System.Threading; | using System.Threading; | ||||
| using Preparation.Utility; | using Preparation.Utility; | ||||
| @@ -9,8 +10,7 @@ namespace Preparation.Interface | |||||
| ITimer Timer { get; } | ITimer Timer { get; } | ||||
| // the two dicts must have same keys | // the two dicts must have same keys | ||||
| Dictionary<GameObjType, IList<IGameObj>> GameObjDict { get; } | |||||
| Dictionary<GameObjType, ReaderWriterLockSlim> GameObjLockDict { get; } | |||||
| Dictionary<GameObjType, LockedClassList<IGameObj>> GameObjDict { get; } | |||||
| public uint[,] ProtoGameMap { get; } | public uint[,] ProtoGameMap { get; } | ||||
| public PlaceType GetPlaceType(IGameObj obj); | public PlaceType GetPlaceType(IGameObj obj); | ||||
| @@ -1,24 +1,26 @@ | |||||
| using System; | using System; | ||||
| using System.Collections; | |||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||
| using System.Threading; | using System.Threading; | ||||
| namespace Preparation.Utility | namespace Preparation.Utility | ||||
| { | { | ||||
| public class LockedClassList<T> where T : class | |||||
| public class LockedClassList<T> : IEnumerable | |||||
| where T : class | |||||
| { | { | ||||
| private readonly ReaderWriterLockSlim listLock = new(); | private readonly ReaderWriterLockSlim listLock = new(); | ||||
| private List<T> list; | private List<T> list; | ||||
| #region 构造 | #region 构造 | ||||
| public LockedList() | |||||
| public LockedClassList() | |||||
| { | { | ||||
| list = new List<T>(); | list = new List<T>(); | ||||
| } | } | ||||
| public LockedList(int capacity) | |||||
| public LockedClassList(int capacity) | |||||
| { | { | ||||
| list = new List<T>(capacity); | list = new List<T>(capacity); | ||||
| } | } | ||||
| public LockedList(IEnumerable<T> collection) | |||||
| public LockedClassList(IEnumerable<T> collection) | |||||
| { | { | ||||
| list = new List<T>(collection); | list = new List<T>(collection); | ||||
| } | } | ||||
| @@ -141,6 +143,17 @@ namespace Preparation.Utility | |||||
| return ReadLock(() => { return list.IndexOf(item); }); | return ReadLock(() => { return list.IndexOf(item); }); | ||||
| } | } | ||||
| public Array ToArray() | |||||
| { | |||||
| return ReadLock(() => { return list.ToArray(); }); | |||||
| } | |||||
| public List<T> ToNewList() | |||||
| { | |||||
| List<T> lt = new(); | |||||
| return ReadLock(() => { lt.AddRange(list); return lt; }); | |||||
| } | |||||
| public bool Contains(T item) | public bool Contains(T item) | ||||
| { | { | ||||
| return ReadLock(() => { return list.Contains(item); }); | return ReadLock(() => { return list.Contains(item); }); | ||||
| @@ -159,6 +172,11 @@ namespace Preparation.Utility | |||||
| public int FindIndex(Predicate<T> match) => ReadLock(() => { return list.FindIndex(match); }); | public int FindIndex(Predicate<T> match) => ReadLock(() => { return list.FindIndex(match); }); | ||||
| public void ForEach(Action<T> action) => ReadLock(() => { list.ForEach(action); }); | public void ForEach(Action<T> action) => ReadLock(() => { list.ForEach(action); }); | ||||
| public IEnumerator GetEnumerator() | |||||
| { | |||||
| return ReadLock(() => { return list.GetEnumerator(); }); | |||||
| } | |||||
| #endregion | #endregion | ||||
| } | } | ||||
| } | } | ||||
| @@ -173,17 +173,9 @@ namespace Server | |||||
| } | } | ||||
| private bool playerDeceased(int playerID) | 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; | return false; | ||||
| } | } | ||||
| @@ -191,19 +183,10 @@ namespace Server | |||||
| public override int[] GetScore() | public override int[] GetScore() | ||||
| { | { | ||||
| int[] score = new int[2]; // 0代表Student,1代表Tricker | 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; | return score; | ||||
| } | } | ||||