fix: 🐛 fix the bug about int overflows when the teacher uses pubnish
tags/v0.1.0
| @@ -240,8 +240,8 @@ namespace GameClass.GameObj | |||
| } | |||
| #endregion | |||
| #region 血量相关的基本属性及方法 | |||
| private int maxHp; | |||
| public int MaxHp | |||
| private long maxHp; | |||
| public long MaxHp | |||
| { | |||
| get | |||
| { | |||
| @@ -269,8 +269,8 @@ namespace GameClass.GameObj | |||
| } | |||
| } | |||
| } // 最大血量 | |||
| protected int hp; | |||
| public int HP | |||
| protected long hp; | |||
| public long HP | |||
| { | |||
| get | |||
| { | |||
| @@ -307,12 +307,12 @@ namespace GameClass.GameObj | |||
| /// 尝试减血 | |||
| /// </summary> | |||
| /// <param name="sub">减血量</param> | |||
| public int TrySubHp(int sub) | |||
| public long TrySubHp(long sub) | |||
| { | |||
| HPReadWriterLock.EnterWriteLock(); | |||
| try | |||
| { | |||
| int previousHp = hp; | |||
| long previousHp = hp; | |||
| if (hp <= sub) | |||
| { | |||
| hp = 0; | |||
| @@ -1,4 +1,5 @@ | |||
| using Preparation.Utility; | |||
| using System.Threading; | |||
| namespace GameClass.GameObj | |||
| { | |||
| @@ -17,20 +18,25 @@ namespace GameClass.GameObj | |||
| private int numOfFixing = 0; | |||
| public int NumOfFixing | |||
| { | |||
| get => numOfFixing; | |||
| set | |||
| { | |||
| lock (gameObjLock) | |||
| { | |||
| numOfFixing = value; | |||
| } | |||
| } | |||
| get => Interlocked.CompareExchange(ref numOfFixing, 0, 0); | |||
| } | |||
| public void AddNumOfFixing() | |||
| { | |||
| Interlocked.Increment(ref numOfFixing); | |||
| } | |||
| public void SubNumOfFixing() | |||
| { | |||
| Interlocked.Decrement(ref numOfFixing); | |||
| } | |||
| private int degreeOfRepair = 0; | |||
| public int DegreeOfRepair | |||
| { | |||
| get => degreeOfRepair; | |||
| get | |||
| { | |||
| lock (gameObjLock) | |||
| return degreeOfRepair; | |||
| } | |||
| private set | |||
| { | |||
| lock (gameObjLock) | |||
| @@ -76,35 +76,43 @@ namespace Gaming | |||
| public bool Fix(Student player)// 自动检查有无发电机可修 | |||
| { | |||
| if ((!player.Commandable()) || player.PlayerState == PlayerStateType.Fixing) | |||
| return false; | |||
| Generator? generatorForFix = (Generator?)gameMap.OneForInteract(player.Position, GameObjType.Generator); | |||
| if (generatorForFix == null) return false; | |||
| long stateNum = player.SetPlayerState(PlayerStateType.Fixing); | |||
| if (stateNum == -1) return false; | |||
| if (generatorForFix == null || generatorForFix.DegreeOfRepair == GameData.degreeOfFixedGenerator) | |||
| player.ThreadNum.WaitOne(); | |||
| if (generatorForFix.DegreeOfRepair == GameData.degreeOfFixedGenerator) | |||
| return false; | |||
| ++generatorForFix.NumOfFixing; | |||
| player.SetPlayerState(PlayerStateType.Fixing); | |||
| long threadNum = player.StateNum; | |||
| generatorForFix.AddNumOfFixing(); | |||
| new Thread | |||
| ( | |||
| () => | |||
| { | |||
| Thread.Sleep(GameData.frameDuration); | |||
| Thread.Sleep(GameData.checkInterval); | |||
| new FrameRateTaskExecutor<int>( | |||
| loopCondition: () => gameMap.Timer.IsGaming && threadNum == player.StateNum, | |||
| loopCondition: () => stateNum == player.StateNum && gameMap.Timer.IsGaming, | |||
| loopToDo: () => | |||
| { | |||
| if (generatorForFix.Repair(player.FixSpeed * GameData.frameDuration, player)) | |||
| if (generatorForFix.Repair(player.FixSpeed * GameData.checkInterval, player)) | |||
| gameMap.NumOfRepairedGenerators++; | |||
| if (generatorForFix.DegreeOfRepair == GameData.degreeOfFixedGenerator) | |||
| player.SetPlayerState();//Num == player.StateNum | |||
| { | |||
| lock (player.ActionLock) | |||
| { | |||
| if (stateNum == player.StateNum) | |||
| player.SetPlayerState(); | |||
| } | |||
| } | |||
| }, | |||
| timeInterval: GameData.frameDuration, | |||
| timeInterval: GameData.checkInterval, | |||
| finallyReturn: () => 0 | |||
| ) | |||
| .Start(); | |||
| --generatorForFix.NumOfFixing; | |||
| player.ThreadNum.Release(); | |||
| generatorForFix.SubNumOfFixing(); | |||
| } | |||
| ) | |||
| @@ -248,6 +248,7 @@ namespace Gaming | |||
| new Thread | |||
| (() => | |||
| { | |||
| Debugger.Output(player, " is stunned for " + time.ToString()); | |||
| Thread.Sleep(time); | |||
| if (threadNum == player.StateNum) | |||
| player.SetPlayerState(); | |||
| @@ -297,18 +298,18 @@ namespace Gaming | |||
| { | |||
| if (bullet.HasSpear) | |||
| { | |||
| int subHp = student.TrySubHp(bullet.AP); | |||
| long subHp = student.TrySubHp(bullet.AP); | |||
| #if DEBUG | |||
| Debugger.Output(this, "is being shot! Now his hp is" + student.HP.ToString()); | |||
| #endif | |||
| bullet.Parent.AddScore(GameData.TrickerScoreAttackStudent(subHp) + GameData.ScorePropUseSpear); | |||
| bullet.Parent.HP = (int)(bullet.Parent.HP + (bullet.Parent.Vampire * subHp)); | |||
| bullet.Parent.HP = (long)(bullet.Parent.HP + (bullet.Parent.Vampire * subHp)); | |||
| } | |||
| else return; | |||
| } | |||
| else | |||
| { | |||
| int subHp; | |||
| long subHp; | |||
| if (bullet.HasSpear) | |||
| { | |||
| subHp = student.TrySubHp(bullet.AP + GameData.ApSpearAdd); | |||
| @@ -354,8 +354,8 @@ namespace Gaming | |||
| || character.PlayerState == PlayerStateType.ClimbingThroughWindows) | |||
| && XY.DistanceFloor3(character.Position, player.Position) <= player.ViewRange / 3) | |||
| { | |||
| if (CharacterManager.BeStunned(character, GameData.timeOfGhostStunnedWhenPunish + GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP) / GameData.basicApOfGhost) > 0) | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.timeOfGhostStunnedWhenPunish + GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP) / GameData.basicApOfGhost)); | |||
| if (CharacterManager.BeStunned(character, GameData.timeOfGhostStunnedWhenPunish + (int)((GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP) / GameData.basicApOfGhost))) > 0) | |||
| player.AddScore(GameData.StudentScoreTrickerBeStunned(GameData.timeOfGhostStunnedWhenPunish + (int)(GameData.factorOfTimeStunnedWhenPunish * (player.MaxHp - player.HP) / GameData.basicApOfGhost))); | |||
| break; | |||
| } | |||
| } | |||
| @@ -6,7 +6,7 @@ namespace Preparation.Interface | |||
| public interface ICharacter : IMoveable | |||
| { | |||
| public long TeamID { get; } | |||
| public int HP { get; set; } | |||
| public long HP { get; set; } | |||
| public long Score { get; } | |||
| public void AddScore(long add); | |||
| public double Vampire { get; } | |||
| @@ -137,7 +137,7 @@ namespace Preparation.Utility | |||
| } | |||
| #endregion | |||
| #region 得分相关 | |||
| public static int TrickerScoreAttackStudent(int damage) | |||
| public static long TrickerScoreAttackStudent(long damage) | |||
| { | |||
| return damage * 100 / basicApOfGhost; | |||
| } | |||
| @@ -167,7 +167,7 @@ namespace Preparation.Utility | |||
| return time * 20 / 1000; | |||
| } | |||
| public const int StudentScoreRescue = 100; | |||
| public static int StudentScoreTreat(int degree) | |||
| public static long StudentScoreTreat(long degree) | |||
| { | |||
| return degree * 50 / basicTreatmentDegree; | |||
| } | |||
| @@ -58,8 +58,8 @@ namespace Server | |||
| { | |||
| X = player.Position.x, | |||
| Y = player.Position.y, | |||
| Speed = (int)player.MoveSpeed, | |||
| Determination = player.HP, | |||
| Speed = player.MoveSpeed, | |||
| Determination = (int)player.HP, | |||
| Addiction = player.GamingAddiction, | |||
| Guid = player.ID, | |||