diff --git a/dependency/Dockerfile/Dockerfile_run b/dependency/Dockerfile/Dockerfile_run index 2bb0dd25..383b34a6 100755 --- a/dependency/Dockerfile/Dockerfile_run +++ b/dependency/Dockerfile/Dockerfile_run @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:8.0.201-jammy-amd64 AS build +FROM mcr.microsoft.com/dotnet/sdk:8.0.203-jammy-amd64 AS build MAINTAINER eesast WORKDIR /usr/local COPY . . diff --git a/installer/installer.csproj b/installer/installer.csproj index f5c2bd3e..e310be12 100755 --- a/installer/installer.csproj +++ b/installer/installer.csproj @@ -86,8 +86,8 @@ - - + + diff --git a/logic/Client/Client.csproj b/logic/Client/Client.csproj index 9f9b29b0..c96d6491 100755 --- a/logic/Client/Client.csproj +++ b/logic/Client/Client.csproj @@ -63,7 +63,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/logic/GameClass/GameObj/Areas/Asteroid.cs b/logic/GameClass/GameObj/Areas/Asteroid.cs index 4f0b12b6..8d9776f2 100755 --- a/logic/GameClass/GameObj/Areas/Asteroid.cs +++ b/logic/GameClass/GameObj/Areas/Asteroid.cs @@ -3,12 +3,9 @@ namespace GameClass.GameObj.Areas; -public class Asteroid : Immovable +public class Asteroid(XY initPos) + : Immovable(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Asteroid) { public override bool IsRigid => true; public override ShapeType Shape => ShapeType.Square; - public Asteroid(XY initPos) - : base(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Asteroid) - { - } } diff --git a/logic/GameClass/GameObj/Areas/Construction.cs b/logic/GameClass/GameObj/Areas/Construction.cs index 8454c655..1da5e81b 100755 --- a/logic/GameClass/GameObj/Areas/Construction.cs +++ b/logic/GameClass/GameObj/Areas/Construction.cs @@ -3,10 +3,11 @@ namespace GameClass.GameObj.Areas; -public class Construction : Immovable +public class Construction(XY initPos) + : Immovable(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Construction) { public AtomicLong TeamID { get; } = new(long.MaxValue); - public LongInTheVariableRange HP { get; } = new LongInTheVariableRange(0, GameData.CommunityHP); + public LongInTheVariableRange HP { get; } = new(0, GameData.CommunityHP); public override bool IsRigid => constructionType == ConstructionType.Community; public override ShapeType Shape => ShapeType.Square; private ConstructionType constructionType = ConstructionType.Null; @@ -18,13 +19,13 @@ public bool Construct(int constructSpeed, ConstructionType constructionType, Shi { return false; } - if (this.constructionType != ConstructionType.Null && this.constructionType != constructionType && this.HP > 0) + if (this.constructionType != ConstructionType.Null && this.constructionType != constructionType && HP > 0) { return false; } - if (this.constructionType == ConstructionType.Null || this.HP == 0) + if (this.constructionType == ConstructionType.Null || HP == 0) { - this.TeamID.SetReturnOri(ship.TeamID); + TeamID.SetReturnOri(ship.TeamID); this.constructionType = constructionType; switch (constructionType) { @@ -45,12 +46,11 @@ public bool Construct(int constructSpeed, ConstructionType constructionType, Shi } public void BeAttacked(Bullet bullet) { - if (bullet!.Parent!.TeamID == this.TeamID) + if (bullet!.Parent!.TeamID != TeamID) { - return; + long subHP = bullet.AP; + HP.SubPositiveV(subHP); } - long subHP = bullet.AP; - this.HP.SubPositiveV(subHP); } public void AddConstructNum(int add = 1) { @@ -60,8 +60,4 @@ public void SubConstructNum(int sub = 1) { ConstructNum.Sub(sub); } - public Construction(XY initPos) - : base(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Construction) - { - } } diff --git a/logic/GameClass/GameObj/Areas/Home.cs b/logic/GameClass/GameObj/Areas/Home.cs index b05f31dc..9dfb4093 100755 --- a/logic/GameClass/GameObj/Areas/Home.cs +++ b/logic/GameClass/GameObj/Areas/Home.cs @@ -14,10 +14,7 @@ public class Home(XY initPos, long id) public void BeAttacked(Bullet bullet) { - if (bullet!.Parent!.TeamID == this.TeamID) - { - return; - } - this.HP.SubPositiveV(bullet.AP); + if (bullet!.Parent!.TeamID != TeamID) + HP.SubPositiveV(bullet.AP); } } diff --git a/logic/GameClass/GameObj/Areas/NullArea.cs b/logic/GameClass/GameObj/Areas/NullArea.cs index 342e6056..674b9f3f 100755 --- a/logic/GameClass/GameObj/Areas/NullArea.cs +++ b/logic/GameClass/GameObj/Areas/NullArea.cs @@ -2,12 +2,9 @@ namespace GameClass.GameObj.Areas; -public class NullArea : Immovable +public class NullArea(XY initPos) + : Immovable(initPos, int.MaxValue, GameObjType.Null) { public override bool IsRigid => false; public override ShapeType Shape => ShapeType.Null; - public NullArea(XY initPos) - : base(initPos, int.MaxValue, GameObjType.Null) - { - } } diff --git a/logic/GameClass/GameObj/Areas/OutOfBoundBlock.cs b/logic/GameClass/GameObj/Areas/OutOfBoundBlock.cs index 6d6d13a4..dfbcf758 100755 --- a/logic/GameClass/GameObj/Areas/OutOfBoundBlock.cs +++ b/logic/GameClass/GameObj/Areas/OutOfBoundBlock.cs @@ -6,12 +6,9 @@ namespace GameClass.GameObj.Areas; /// /// 逻辑墙 /// -public class OutOfBoundBlock : Immovable, IOutOfBound +public class OutOfBoundBlock(XY initPos) + : Immovable(initPos, int.MaxValue, GameObjType.OutOfBoundBlock), IOutOfBound { public override bool IsRigid => true; public override ShapeType Shape => ShapeType.Square; - public OutOfBoundBlock(XY initPos) - : base(initPos, int.MaxValue, GameObjType.OutOfBoundBlock) - { - } } diff --git a/logic/GameClass/GameObj/Areas/Resource.cs b/logic/GameClass/GameObj/Areas/Resource.cs index 76c657ed..4b0ad354 100755 --- a/logic/GameClass/GameObj/Areas/Resource.cs +++ b/logic/GameClass/GameObj/Areas/Resource.cs @@ -4,7 +4,8 @@ namespace GameClass.GameObj.Areas; -public class Resource : Immovable +public class Resource(XY initPos) + : Immovable(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Resource) { public LongInTheVariableRange HP { get; } = new LongInTheVariableRange(GameData.ResourceHP); public override bool IsRigid => true; @@ -22,8 +23,4 @@ public void SubProduceNum(int sub = 1) { ProduceNum.Sub(sub); } - public Resource(XY initPos) - : base(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Resource) - { - } } diff --git a/logic/GameClass/GameObj/Areas/Ruin.cs b/logic/GameClass/GameObj/Areas/Ruin.cs index b3da5f49..fcb32017 100755 --- a/logic/GameClass/GameObj/Areas/Ruin.cs +++ b/logic/GameClass/GameObj/Areas/Ruin.cs @@ -1,14 +1,10 @@ using Preparation.Utility; -using System; namespace GameClass.GameObj.Areas; -public class Ruin : Immovable +public class Ruin(XY initPos) + : Immovable(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Ruin) { public override bool IsRigid => true; public override ShapeType Shape => ShapeType.Square; - public Ruin(XY initPos) - : base(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Ruin) - { - } } diff --git a/logic/GameClass/GameObj/Areas/Shadow.cs b/logic/GameClass/GameObj/Areas/Shadow.cs index 3705a760..921d82db 100755 --- a/logic/GameClass/GameObj/Areas/Shadow.cs +++ b/logic/GameClass/GameObj/Areas/Shadow.cs @@ -3,12 +3,9 @@ namespace GameClass.GameObj.Areas; -public class Shadow : Immovable +public class Shadow(XY initPos) + : Immovable(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Shadow) { public override bool IsRigid => false; public override ShapeType Shape => ShapeType.Square; - public Shadow(XY initPos) - : base(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Shadow) - { - } } \ No newline at end of file diff --git a/logic/GameClass/GameObj/Areas/Wormhole.cs b/logic/GameClass/GameObj/Areas/Wormhole.cs index fdb68635..47153773 100755 --- a/logic/GameClass/GameObj/Areas/Wormhole.cs +++ b/logic/GameClass/GameObj/Areas/Wormhole.cs @@ -5,10 +5,11 @@ namespace GameClass.GameObj.Areas; -public class Wormhole : Immovable, IWormhole +public class Wormhole(XY initPos, List grids) + : Immovable(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Wormhole), IWormhole { - public LongInTheVariableRange HP = new LongInTheVariableRange(GameData.WormholeHP); - private readonly List grids = new(); + public LongInTheVariableRange HP = new(GameData.WormholeHP); + private readonly List grids = grids; public List Grids => grids; public override bool IsRigid => HP > GameData.WormholeHP / 2; public override ShapeType Shape => ShapeType.Square; @@ -20,7 +21,7 @@ public bool Repair(int constructSpeed, Ship ship) public void BeAttacked(Bullet bullet) { long subHP = bullet.AP; - this.HP.SubPositiveV(subHP); + HP.SubPositiveV(subHP); } public void AddRepairNum(int add = 1) { @@ -30,9 +31,4 @@ public void SubRepairNum(int sub = 1) { RepairNum.Sub(sub); } - public Wormhole(XY initPos, List grids) - : base(initPos, GameData.NumOfPosGridPerCell / 2, GameObjType.Wormhole) - { - this.grids = grids; - } } \ No newline at end of file diff --git a/logic/GameClass/GameObj/BombedBullet.cs b/logic/GameClass/GameObj/BombedBullet.cs index 8f3f3270..6e628038 100755 --- a/logic/GameClass/GameObj/BombedBullet.cs +++ b/logic/GameClass/GameObj/BombedBullet.cs @@ -3,20 +3,13 @@ namespace GameClass.GameObj { // 为方便界面组做子弹爆炸特效,现引入“爆炸中的子弹”,在每帧发送给界面组 - public sealed class BombedBullet : Immovable + public sealed class BombedBullet(Bullet bullet) + : Immovable(bullet.Position, bullet.Radius, GameObjType.BombedBullet) { public override ShapeType Shape => ShapeType.Circle; public override bool IsRigid => false; - public long MappingID { get; } - public readonly Bullet bulletHasBombed; - public readonly XY facingDirection; - - public BombedBullet(Bullet bullet) : - base(bullet.Position, bullet.Radius, GameObjType.BombedBullet) - { - this.bulletHasBombed = bullet; - this.MappingID = bullet.ID; - this.facingDirection = bullet.FacingDirection; - } + public long MappingID { get; } = bullet.ID; + public readonly Bullet bulletHasBombed = bullet; + public readonly XY facingDirection = bullet.FacingDirection; } } diff --git a/logic/GameClass/GameObj/Bullet.cs b/logic/GameClass/GameObj/Bullet.cs index b73c9815..05298313 100755 --- a/logic/GameClass/GameObj/Bullet.cs +++ b/logic/GameClass/GameObj/Bullet.cs @@ -35,8 +35,8 @@ public override bool IgnoreCollideExecutor(IGameObj targetObj) public Bullet(Ship ship, int radius, XY Position) : base(Position, radius, GameObjType.Bullet) { - this.CanMove.SetReturnOri(true); - this.MoveSpeed.SetReturnOri(this.Speed); - this.Parent = ship; + CanMove.SetReturnOri(true); + MoveSpeed.SetReturnOri(Speed); + Parent = ship; } } diff --git a/logic/GameClass/GameObj/Bullets/Arc.cs b/logic/GameClass/GameObj/Bullets/Arc.cs index 039e86be..96de7bf4 100755 --- a/logic/GameClass/GameObj/Bullets/Arc.cs +++ b/logic/GameClass/GameObj/Bullets/Arc.cs @@ -9,7 +9,7 @@ public Arc(Ship ship, XY pos, int radius = GameData.BulletRadius) : base(ship, radius, pos) { Random random = new(); - this.AP.SetReturnOri(random.Next(GameData.ArcDamageMin, GameData.ArcDamageMax)); + AP.SetReturnOri(random.Next(GameData.ArcDamageMin, GameData.ArcDamageMax)); } public override double BulletBombRange => 0; public override double AttackDistance => GameData.ArcRange; diff --git a/logic/GameClass/GameObj/Bullets/Laser.cs b/logic/GameClass/GameObj/Bullets/Laser.cs index 9df9a78c..e4551276 100755 --- a/logic/GameClass/GameObj/Bullets/Laser.cs +++ b/logic/GameClass/GameObj/Bullets/Laser.cs @@ -10,7 +10,7 @@ internal sealed class Laser : Bullet public Laser(Ship ship, XY pos, int radius = GameData.BulletRadius) : base(ship, radius, pos) { - this.AP.SetReturnOri(GameData.LaserDamage); + AP.SetReturnOri(GameData.LaserDamage); } public override double BulletBombRange => 0; public override double AttackDistance => GameData.LaserRange; diff --git a/logic/GameClass/GameObj/Bullets/Missile.cs b/logic/GameClass/GameObj/Bullets/Missile.cs index 7302f893..2e4e0b84 100755 --- a/logic/GameClass/GameObj/Bullets/Missile.cs +++ b/logic/GameClass/GameObj/Bullets/Missile.cs @@ -8,7 +8,7 @@ internal sealed class Missile : Bullet public Missile(Ship ship, XY pos, int radius = GameData.BulletRadius) : base(ship, radius, pos) { - this.AP.SetReturnOri(GameData.MissileDamage); + AP.SetReturnOri(GameData.MissileDamage); } public override double BulletBombRange => GameData.MissileBombRange; public override double AttackDistance => GameData.MissileRange; diff --git a/logic/GameClass/GameObj/Bullets/NullBullet.cs b/logic/GameClass/GameObj/Bullets/NullBullet.cs index f88bb1e5..12de9476 100755 --- a/logic/GameClass/GameObj/Bullets/NullBullet.cs +++ b/logic/GameClass/GameObj/Bullets/NullBullet.cs @@ -2,7 +2,8 @@ namespace GameClass.GameObj.Bullets; -internal sealed class NullBullet(Ship ship, XY Position, int radius = GameData.BulletRadius) : Bullet(ship, radius, Position) +internal sealed class NullBullet(Ship ship, XY Position, int radius = GameData.BulletRadius) + : Bullet(ship, radius, Position) { public override double BulletBombRange => 0; public override double AttackDistance => 0; diff --git a/logic/GameClass/GameObj/Bullets/Plasma.cs b/logic/GameClass/GameObj/Bullets/Plasma.cs index deca2e1a..88d35ee7 100755 --- a/logic/GameClass/GameObj/Bullets/Plasma.cs +++ b/logic/GameClass/GameObj/Bullets/Plasma.cs @@ -7,7 +7,7 @@ internal sealed class Plasma : Bullet public Plasma(Ship ship, XY pos, int radius = GameData.BulletRadius) : base(ship, radius, pos) { - this.AP.SetReturnOri(GameData.PlasmaDamage); + AP.SetReturnOri(GameData.PlasmaDamage); } public override double BulletBombRange => 0; public override double AttackDistance => GameData.PlasmaRange; diff --git a/logic/GameClass/GameObj/Bullets/Shell.cs b/logic/GameClass/GameObj/Bullets/Shell.cs index 1b01286e..40c88fc7 100755 --- a/logic/GameClass/GameObj/Bullets/Shell.cs +++ b/logic/GameClass/GameObj/Bullets/Shell.cs @@ -7,7 +7,7 @@ internal sealed class Shell : Bullet public Shell(Ship ship, XY pos, int radius = GameData.BulletRadius) : base(ship, radius, pos) { - this.AP.SetReturnOri(GameData.ShellDamage); + AP.SetReturnOri(GameData.ShellDamage); } public override double BulletBombRange => 0; public override double AttackDistance => GameData.ShellRange; diff --git a/logic/GameClass/GameObj/GameObj.cs b/logic/GameClass/GameObj/GameObj.cs index 0adbdb35..eae58e58 100755 --- a/logic/GameClass/GameObj/GameObj.cs +++ b/logic/GameClass/GameObj/GameObj.cs @@ -7,37 +7,30 @@ namespace GameClass.GameObj /// /// 一切游戏元素的总基类,与THUAI4不同,继承IMoveable接口(出于一切物体其实都是可运动的指导思想)——LHR /// - public abstract class GameObj : IGameObj + public abstract class GameObj(XY initPos, int initRadius, GameObjType initType) : IGameObj { private readonly ReaderWriterLockSlim gameObjReaderWriterLock = new(); public ReaderWriterLockSlim GameObjReaderWriterLock => gameObjReaderWriterLock; protected readonly object gameObjLock = new(); public object GameLock => gameObjLock; - protected readonly XY birthPos; - private readonly GameObjType type; + protected readonly XY birthPos = initPos; + private readonly GameObjType type = initType; public GameObjType Type => type; private static long currentMaxID = 0; // 目前游戏对象的最大ID public const long invalidID = long.MaxValue; // 无效的ID - public long ID { get; } - protected XY position; + public long ID { get; } = Interlocked.Increment(ref currentMaxID); + protected XY position = initPos; public abstract XY Position { get; } public abstract bool IsRigid { get; } public abstract ShapeType Shape { get; } - private AtomicBool isRemoved = new(false); + private readonly AtomicBool isRemoved = new(false); public AtomicBool IsRemoved { get => isRemoved; } public virtual bool TryToRemove() { return IsRemoved.TrySet(true); } - public int Radius { get; } + public int Radius { get; } = initRadius; public virtual bool IgnoreCollideExecutor(IGameObj targetObj) => false; - public GameObj(XY initPos, int initRadius, GameObjType initType) - { - this.position = this.birthPos = initPos; - this.Radius = initRadius; - this.type = initType; - ID = Interlocked.Increment(ref currentMaxID); - } } } diff --git a/logic/GameClass/GameObj/Immovable.cs b/logic/GameClass/GameObj/Immovable.cs index 07211f59..314e7063 100755 --- a/logic/GameClass/GameObj/Immovable.cs +++ b/logic/GameClass/GameObj/Immovable.cs @@ -2,11 +2,8 @@ namespace GameClass.GameObj; -public abstract class Immovable : GameObj +public abstract class Immovable(XY initPos, int initRadius, GameObjType initType) + : GameObj(initPos, initRadius, initType) { public override XY Position => position; - public Immovable(XY initPos, int initRadius, GameObjType initType) - : base(initPos, initRadius, initType) - { - } } diff --git a/logic/GameClass/GameObj/Map/Map.cs b/logic/GameClass/GameObj/Map/Map.cs index 9460b26f..1561b28f 100755 --- a/logic/GameClass/GameObj/Map/Map.cs +++ b/logic/GameClass/GameObj/Map/Map.cs @@ -11,7 +11,7 @@ namespace GameClass.GameObj { public partial class Map : IMap { - private Dictionary> gameObjDict; + private readonly Dictionary> gameObjDict; public Dictionary> GameObjDict => gameObjDict; private readonly uint height; public uint Height => height; @@ -34,7 +34,8 @@ public PlaceType GetPlaceType(IGameObj obj) { try { - return protoGameMap[obj.Position.x / GameData.NumOfPosGridPerCell, obj.Position.y / GameData.NumOfPosGridPerCell]; + var (x, y) = GameData.PosGridToCellXY(obj.Position); + return protoGameMap[x, y]; } catch { @@ -45,7 +46,8 @@ public PlaceType GetPlaceType(XY pos) { try { - return protoGameMap[pos.x / GameData.NumOfPosGridPerCell, pos.y / GameData.NumOfPosGridPerCell]; + var (x, y) = GameData.PosGridToCellXY(pos); + return protoGameMap[x, y]; } catch { @@ -56,7 +58,10 @@ public PlaceType GetPlaceType(XY pos) public bool IsOutOfBound(IGameObj obj) { - return obj.Position.x >= GameData.MapLength - obj.Radius || obj.Position.x <= obj.Radius || obj.Position.y >= GameData.MapLength - obj.Radius || obj.Position.y <= obj.Radius; + return obj.Position.x >= GameData.MapLength - obj.Radius + || obj.Position.x <= obj.Radius + || obj.Position.y >= GameData.MapLength - obj.Radius + || obj.Position.y <= obj.Radius; } public IOutOfBound GetOutOfBound(XY pos) { @@ -72,7 +77,7 @@ public IOutOfBound GetOutOfBound(XY pos) return (Ship?)GameObjDict[GameObjType.Ship].Find(gameObj => (shipID == ((Ship)gameObj).ShipID)); } - public bool WormholeInteract(Wormhole gameObj, XY Pos) + public static bool WormholeInteract(Wormhole gameObj, XY Pos) { foreach (XY xy in gameObj.Grids) { @@ -111,9 +116,11 @@ public bool CanSee(Ship ship, GameObj gameObj) return false; if (del.x > del.y) { + var beginx = GameData.PosGridToCellX(pos1) + GameData.NumOfPosGridPerCell; + var endx = GameData.PosGridToCellX(pos2); if (GetPlaceType(pos1) == PlaceType.Shadow && GetPlaceType(pos2) == PlaceType.Shadow) { - for (int x = GameData.PosGridToCellX(pos1) + GameData.NumOfPosGridPerCell; x < GameData.PosGridToCellX(pos2); x += GameData.NumOfPosGridPerCell) + for (int x = beginx; x < endx; x += GameData.NumOfPosGridPerCell) { if (GetPlaceType(pos1 + del * (x / del.x)) != PlaceType.Shadow) return false; @@ -121,7 +128,7 @@ public bool CanSee(Ship ship, GameObj gameObj) } else { - for (int x = GameData.PosGridToCellX(pos1) + GameData.NumOfPosGridPerCell; x < GameData.PosGridToCellX(pos2); x += GameData.NumOfPosGridPerCell) + for (int x = beginx; x < endx; x += GameData.NumOfPosGridPerCell) { if (GetPlaceType(pos1 + del * (x / del.x)) == PlaceType.Ruin) return false; @@ -130,9 +137,11 @@ public bool CanSee(Ship ship, GameObj gameObj) } else { + var beginy = GameData.PosGridToCellY(pos1) + GameData.NumOfPosGridPerCell; + var endy = GameData.PosGridToCellY(pos2); if (GetPlaceType(pos1) == PlaceType.Shadow && GetPlaceType(pos2) == PlaceType.Shadow) { - for (int y = GameData.PosGridToCellY(pos1) + GameData.NumOfPosGridPerCell; y < GameData.PosGridToCellY(pos2); y += GameData.NumOfPosGridPerCell) + for (int y = beginy; y < endy; y += GameData.NumOfPosGridPerCell) { if (GetPlaceType(pos1 + del * (y / del.y)) != PlaceType.Shadow) return false; @@ -140,7 +149,7 @@ public bool CanSee(Ship ship, GameObj gameObj) } else { - for (int y = GameData.PosGridToCellY(pos1) + GameData.NumOfPosGridPerCell; y < GameData.PosGridToCellY(pos2); y += GameData.NumOfPosGridPerCell) + for (int y = beginy; y < endy; y += GameData.NumOfPosGridPerCell) { if (GetPlaceType(pos1 + del * (y / del.y)) == PlaceType.Ruin) return false; @@ -174,7 +183,7 @@ public void Add(IGameObj gameObj) } public Map(MapStruct mapResource) { - gameObjDict = new Dictionary>(); + gameObjDict = []; foreach (GameObjType idx in Enum.GetValues(typeof(GameObjType))) { if (idx != GameObjType.Null) diff --git a/logic/GameClass/GameObj/Map/MapGameTimer.cs b/logic/GameClass/GameObj/Map/MapGameTimer.cs index 1adc30f6..eae1561c 100755 --- a/logic/GameClass/GameObj/Map/MapGameTimer.cs +++ b/logic/GameClass/GameObj/Map/MapGameTimer.cs @@ -1,6 +1,5 @@ using System; using System.Threading; -using Preparation.Interface; using Preparation.Utility; using ITimer = Preparation.Interface.ITimer; @@ -17,7 +16,7 @@ public class GameTimer : ITimer private long startTime; public int nowTime() => (int)(Environment.TickCount64 - startTime); - private AtomicBool isGaming = new(false); + private readonly AtomicBool isGaming = new(false); public AtomicBool IsGaming => isGaming; public bool StartGame(int timeInMilliseconds) diff --git a/logic/GameClass/GameObj/Movable.cs b/logic/GameClass/GameObj/Movable.cs index 0a157bfd..1b9922c8 100755 --- a/logic/GameClass/GameObj/Movable.cs +++ b/logic/GameClass/GameObj/Movable.cs @@ -4,7 +4,8 @@ namespace GameClass.GameObj { - public abstract class Movable : GameObj, IMovable + public abstract class Movable(XY initPos, int initRadius, GameObjType initType) + : GameObj(initPos, initRadius, initType), IMovable { protected readonly object actionLock = new(); /// @@ -92,10 +93,10 @@ public void ReSetPos(XY position) this.position = position; } } - private AtomicBool canMove = new(false); + private readonly AtomicBool canMove = new(false); public AtomicBool CanMove { get => canMove; } public bool IsAvailableForMove => !IsMoving && CanMove && !IsRemoved; // 是否能接收移动指令 - private AtomicInt moveSpeed = new(0); + private readonly AtomicInt moveSpeed = new(0); /// /// 移动速度 /// @@ -105,23 +106,21 @@ public void ReSetPos(XY position) /// 原初移动速度 /// public int OrgMoveSpeed => orgMoveSpeed; - /* /// - /// 复活时数据重置 - /// - public virtual void Reset(PlaceType place) - { - lock (gameObjLock) - { - this.FacingDirection = new XY(1, 0); - isMoving = false; - CanMove = false; - IsRemoved = true; - this.Position = birthPos; - this.Place= place; - } - }*/ - public Movable(XY initPos, int initRadius, GameObjType initType) : base(initPos, initRadius, initType) + + /*/// + /// 复活时数据重置 + /// + public virtual void Reset(PlaceType place) { - } + lock (gameObjLock) + { + this.FacingDirection = new XY(1, 0); + isMoving = false; + CanMove = false; + IsRemoved = true; + this.Position = birthPos; + this.Place = place; + } + }*/ } } diff --git a/logic/GameClass/GameObj/ObjOfShip.cs b/logic/GameClass/GameObj/ObjOfShip.cs index 83d0c5f5..39978a2f 100755 --- a/logic/GameClass/GameObj/ObjOfShip.cs +++ b/logic/GameClass/GameObj/ObjOfShip.cs @@ -7,7 +7,8 @@ namespace GameClass.GameObj /// /// 所有物,具有主人(Parent)(特定玩家)属性的对象 /// - public abstract class ObjOfShip : Movable, IObjOfShip + public abstract class ObjOfShip(XY initPos, int initRadius, GameObjType initType) + : Movable(initPos, initRadius, initType), IObjOfShip { public object ObjOfShipLock { get; } = new(); private IShip? parent = null; @@ -24,9 +25,5 @@ public IShip? Parent parent = value; } } - public ObjOfShip(XY initPos, int initRadius, GameObjType initType) : - base(initPos, initRadius, initType) - { - } } } diff --git a/logic/GameEngine/CollisionChecker.cs b/logic/GameEngine/CollisionChecker.cs index d8dddcbb..7c1e2010 100755 --- a/logic/GameEngine/CollisionChecker.cs +++ b/logic/GameEngine/CollisionChecker.cs @@ -1,22 +1,18 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; using Preparation.Interface; using Preparation.Utility; namespace GameEngine { - internal class CollisionChecker + internal class CollisionChecker(IMap gameMap) { public IGameObj? CheckCollision(IMovable obj, XY Pos) { // 在列表中检查碰撞 - Func, IGameObj?> CheckCollisionInList = - (LockedClassList lst) => - { - return lst.Find(listObj => obj.WillCollideWith(listObj, Pos)); - }; + IGameObj? CheckCollisionInList(LockedClassList lst) + { + return lst.Find(listObj => obj.WillCollideWith(listObj, Pos)); + } IGameObj? collisionObj; foreach (var list in lists) @@ -117,67 +113,65 @@ public double FindMax(IMovable obj, XY moveVec) // 如果再走一步发生碰撞 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; } } ); @@ -185,13 +179,7 @@ public double FindMax(IMovable obj, XY moveVec) return maxDistance; } - readonly IMap gameMap; - private readonly LockedClassList[] lists; - - public CollisionChecker(IMap gameMap) - { - this.gameMap = gameMap; - lists = gameMap.GameObjDict.Values.ToArray(); - } + readonly IMap gameMap = gameMap; + private readonly LockedClassList[] lists = [.. gameMap.GameObjDict.Values]; } } diff --git a/logic/GameEngine/MoveEngine.cs b/logic/GameEngine/MoveEngine.cs index 7b4b2ebd..ba227413 100755 --- a/logic/GameEngine/MoveEngine.cs +++ b/logic/GameEngine/MoveEngine.cs @@ -7,7 +7,23 @@ namespace GameEngine { - public class MoveEngine + /// + /// Constrctor + /// + /// 游戏地图 + /// + /// 发生碰撞时要做的事情 + /// - 第一个参数为移动的物体 + /// - 第二个参数为撞到的物体 + /// - 第三个参数为移动的位移向量 + /// 返回值见AfterCollision的定义 + /// + /// 结束碰撞时要做的事情 + public class MoveEngine( + IMap gameMap, + Func OnCollision, + Action EndMove + ) { /// /// 碰撞结束后要做的事情 @@ -19,33 +35,16 @@ public enum AfterCollision Destroyed = 2 // 物体已经毁坏 } - private readonly ITimer gameTimer; - private readonly Action EndMove; + private readonly ITimer gameTimer = gameMap.Timer; + private readonly Action EndMove = EndMove; public IGameObj? CheckCollision(IMovable obj, XY Pos) { return collisionChecker.CheckCollision(obj, Pos); } - private readonly CollisionChecker collisionChecker; - private readonly Func OnCollision; - /// - /// Constrctor - /// - /// 游戏地图 - /// 发生碰撞时要做的事情,第一个参数为移动的物体,第二个参数为撞到的物体,第三个参数为移动的位移向量,返回值见AfterCollision的定义 - /// 结束碰撞时要做的事情 - public MoveEngine( - IMap gameMap, - Func OnCollision, - Action EndMove - ) - { - this.gameTimer = gameMap.Timer; - this.EndMove = EndMove; - this.OnCollision = OnCollision; - this.collisionChecker = new CollisionChecker(gameMap); - } + private readonly CollisionChecker collisionChecker = new(gameMap); + private readonly Func OnCollision = OnCollision; /// /// 在无碰撞的前提下行走最远的距离 @@ -62,7 +61,7 @@ private bool MoveMax(IMovable obj, XY moveVec, long stateNum) // 尝试滑动 IGameObj? collisionObj = collisionChecker.CheckCollisionWhenMoving(obj, moveVec); XY slideVec = new(0, 0); - switch (collisionObj.Shape) + switch (collisionObj?.Shape) { case ShapeType.Circle: XY connectVec = collisionObj.Position - obj.Position; @@ -81,6 +80,8 @@ private bool MoveMax(IMovable obj, XY moveVec, long stateNum) slideVec = new XY(moveVec.x * Math.Sign(collisionObj.Position.x - obj.Position.x), 0); } break; + default: + break; } double slideLen = collisionChecker.FindMax(obj, slideVec); slideLen = Math.Min(slideLen, slideVec.Length()); @@ -110,7 +111,7 @@ private bool LoopDo(IMovable obj, double direction, ref double deltaLen, long st flag = true; break; case AfterCollision.Destroyed: - Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); + Debugger.Output(obj, $"collide with {collisionObj} and has been removed from the game."); return false; case AfterCollision.MoveMax: if (!MoveMax(obj, res, stateNum)) return false; @@ -141,7 +142,7 @@ public void MoveObj(IMovable obj, int moveTime, double direction, long stateNum) { double moveVecLength = 0.0; XY res = new(direction, moveVecLength); - double deltaLen = (double)0.0; // 转向,并用deltaLen存储行走的误差 + double deltaLen = 0.0; // 转向,并用deltaLen存储行走的误差 IGameObj? collisionObj = null; bool isEnded = false; @@ -159,7 +160,7 @@ public void MoveObj(IMovable obj, int moveTime, double direction, long stateNum) flag = true; break; case AfterCollision.Destroyed: - Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); + Debugger.Output(obj, $"collide with {collisionObj} and has been removed from the game."); isEnded = true; break; case AfterCollision.MoveMax: @@ -200,7 +201,6 @@ public void MoveObj(IMovable obj, int moveTime, double direction, long stateNum) { if (b) Console.WriteLine("Fatal Error: The computer runs so slow that the object cannot finish moving during this time!!!!!!"); - #if DEBUG else { @@ -242,7 +242,7 @@ public void MoveObj(IMovable obj, int moveTime, double direction, long stateNum) flag = true; break; case AfterCollision.Destroyed: - Debugger.Output(obj, " collide with " + collisionObj.ToString() + " and has been removed from the game."); + Debugger.Output(obj, $"collide with {collisionObj} and has been removed from the game."); isEnded = true; break; case AfterCollision.MoveMax: diff --git a/logic/Gaming/AttackManager.cs b/logic/Gaming/AttackManager.cs index 6d9898e1..4604da94 100755 --- a/logic/Gaming/AttackManager.cs +++ b/logic/Gaming/AttackManager.cs @@ -7,6 +7,7 @@ using Preparation.Utility; using Preparation.Interface; using Timothy.FrameRateTask; +using System.Linq; namespace Gaming { @@ -101,7 +102,7 @@ private void BulletBomb(Bullet bullet, GameObj? objBeingShot) beAttackedList.AddRange(gameMap.GameObjDict[kvp.Key].FindAll(gameObj => bullet.CanAttack((GameObj)gameObj))); } } - foreach (GameObj beAttackedObj in beAttackedList) + foreach (GameObj beAttackedObj in beAttackedList.Cast()) { BombObj(bullet, beAttackedObj); } diff --git a/logic/Preparation/Utility/Debugger.cs b/logic/Preparation/Utility/Debugger.cs index 8627e316..94ca944b 100755 --- a/logic/Preparation/Utility/Debugger.cs +++ b/logic/Preparation/Utility/Debugger.cs @@ -7,7 +7,7 @@ public class Debugger static public void Output(object current, string str) { #if DEBUG - Console.WriteLine(current.GetType() + " " + current.ToString() + " " + str); + Console.WriteLine($"{current.GetType()} {current} {str}"); #endif } static public void Output(string str) diff --git a/logic/Preparation/Utility/GameData.cs b/logic/Preparation/Utility/GameData.cs index c97abb4c..12141935 100755 --- a/logic/Preparation/Utility/GameData.cs +++ b/logic/Preparation/Utility/GameData.cs @@ -26,10 +26,7 @@ public static class GameData public const int InitialMoney = 50; // 初始金钱 - public static bool IsGameObjMap(GameObjType gameObjType) - { - return (uint)gameObjType > 3; - } + public static bool IsGameObjMap(GameObjType gameObjType) => (uint)gameObjType > 3; public static bool NeedCopy(GameObjType gameObjType) { return gameObjType != GameObjType.Null && @@ -39,39 +36,32 @@ public static bool NeedCopy(GameObjType gameObjType) gameObjType != GameObjType.OutOfBoundBlock; } public static XY GetCellCenterPos(int x, int y) // 求格子的中心坐标 - { - XY ret = new(x * NumOfPosGridPerCell + NumOfPosGridPerCell / 2, y * NumOfPosGridPerCell + NumOfPosGridPerCell / 2); - return ret; - } + => new(x * NumOfPosGridPerCell + NumOfPosGridPerCell / 2, + y * NumOfPosGridPerCell + NumOfPosGridPerCell / 2); + public static int PosGridToCellX(XY pos) // 求坐标所在的格子的x坐标 - { - return pos.x / NumOfPosGridPerCell; - } + => pos.x / NumOfPosGridPerCell; public static int PosGridToCellY(XY pos) // 求坐标所在的格子的y坐标 - { - return pos.y / NumOfPosGridPerCell; - } - public static XY PosGridToCellXY(XY pos) // 求坐标所在的格子的xy坐标 - { - return new XY(pos.x / NumOfPosGridPerCell, pos.y / NumOfPosGridPerCell); - } - public static bool IsInTheSameCell(XY pos1, XY pos2) - { - return PosGridToCellX(pos1) == PosGridToCellX(pos2) && PosGridToCellY(pos1) == PosGridToCellY(pos2); - } + => pos.y / NumOfPosGridPerCell; + public static CellXY PosGridToCellXY(XY pos) // 求坐标所在的格子的xy坐标 + => new(PosGridToCellX(pos), PosGridToCellY(pos)); + + public static bool IsInTheSameCell(XY pos1, XY pos2) => PosGridToCellXY(pos1) == PosGridToCellXY(pos2); public static bool PartInTheSameCell(XY pos1, XY pos2) { return Math.Abs((pos1 - pos2).x) < ShipRadius + (NumOfPosGridPerCell / 2) - && Math.Abs((pos1 - pos2).y) < ShipRadius + (NumOfPosGridPerCell / 2); + && Math.Abs((pos1 - pos2).y) < ShipRadius + (NumOfPosGridPerCell / 2); } public static bool ApproachToInteract(XY pos1, XY pos2) { - return Math.Abs(PosGridToCellX(pos1) - PosGridToCellX(pos2)) <= 1 && Math.Abs(PosGridToCellY(pos1) - PosGridToCellY(pos2)) <= 1; + return Math.Abs(PosGridToCellX(pos1) - PosGridToCellX(pos2)) <= 1 + && Math.Abs(PosGridToCellY(pos1) - PosGridToCellY(pos2)) <= 1; } public static bool ApproachToInteractInACross(XY pos1, XY pos2) { if (pos1 == pos2) return false; - return (Math.Abs(PosGridToCellX(pos1) - PosGridToCellX(pos2)) + Math.Abs(PosGridToCellY(pos1) - PosGridToCellY(pos2))) <= 1; + return (Math.Abs(PosGridToCellX(pos1) - PosGridToCellX(pos2)) + + Math.Abs(PosGridToCellY(pos1) - PosGridToCellY(pos2))) <= 1; } public const int ShipRadius = 400; @@ -175,18 +165,9 @@ public static bool ApproachToInteractInACross(XY pos1, XY pos2) public const int ScoreProducer2PerSecond = 7; public const int ScoreProducer3PerSecond = 10; public const int ScoreConstructionDamaged = 200; - public static int ScoreShipKilled(int totalScore) - { - return totalScore / 5; - } - public static int ScoreShipRecovered(int totalRecovery) - { - return totalRecovery * 6 / 5; - } - public static int ScoreShipRecycled(int remainingHP) - { - return remainingHP / 2; - } + public static int ScoreShipKilled(int totalScore) => totalScore / 5; + public static int ScoreShipRecovered(int totalRecovery) => totalRecovery * 6 / 5; + public static int ScoreShipRecycled(int remainingHP) => remainingHP / 2; public const int Constructor1Speed = 500; public const int Constructor2Speed = 750; diff --git a/logic/Preparation/Utility/Logger.cs b/logic/Preparation/Utility/Logger.cs index 27cd453f..84c1e976 100755 --- a/logic/Preparation/Utility/Logger.cs +++ b/logic/Preparation/Utility/Logger.cs @@ -8,13 +8,13 @@ public class Logger static public void Writelog(object current, string str) { string path = "log.txt"; - string log = string.Format("[{0}] {1} {2} {3}", DateTime.Now, current.GetType(), current.ToString(), str); + string log = $"[{DateTime.Now}] {current.GetType()} {current} {str}"; File.AppendAllText(path, log + Environment.NewLine); } static public void Writelog(string str) { string path = "log.txt"; - string log = string.Format("[{0}] {1}", DateTime.Now, str); + string log = $"[{DateTime.Now}] {str}"; File.AppendAllText(path, log + Environment.NewLine); } } diff --git a/logic/Preparation/Utility/SafeValue/Atomic.cs b/logic/Preparation/Utility/SafeValue/Atomic.cs index f0b2a680..6a20f2d1 100755 --- a/logic/Preparation/Utility/SafeValue/Atomic.cs +++ b/logic/Preparation/Utility/SafeValue/Atomic.cs @@ -8,13 +8,10 @@ public abstract class Atomic { } - public class AtomicInt : Atomic + public class AtomicInt(int x) : Atomic { - protected int v; - public AtomicInt(int x) - { - v = x; - } + protected int v = x; + public override string ToString() => Interlocked.CompareExchange(ref v, -1, -1).ToString(); public int Get() => Interlocked.CompareExchange(ref v, -1, -1); public static implicit operator int(AtomicInt aint) => Interlocked.CompareExchange(ref aint.v, -1, -1); @@ -42,15 +39,11 @@ public AtomicInt(int x) /// 在发生正向的变化时,自动给Score加上正向变化的差乘以speed(取整)。 /// 注意:AtomicIntOnlyAddScore本身为AtomicInt,提供的Score可能构成环而死锁。 /// - public class AtomicIntOnlyAddScore : AtomicInt + public class AtomicIntOnlyAddScore(int x, double speed = 1.0) : AtomicInt(x) { - public AtomicInt Score { get; set; } - public AtomicDouble speed; - public AtomicIntOnlyAddScore(int x, double speed = 1.0) : base(x) - { - this.speed = new(speed); - this.Score = new(0); - } + public AtomicInt Score { get; set; } = new(0); + public AtomicDouble speed = new(speed); + public void SetScore(AtomicInt score) => Score = score; /// 返回操作前的值 public override int SetReturnOri(int value) @@ -127,15 +120,11 @@ public int CompareExReturnOriNotAddScore(int newV, int compareTo) /// 可(在构造时)使用SetScore以设定AtomicLong类的Score(取整) /// 在发生正向的变化时,自动给Score加上正向变化的差乘以speed。 /// - public class AtomicIntOnlyAddLongScore : AtomicInt + public class AtomicIntOnlyAddLongScore(int x, double speed = 1.0) : AtomicInt(x) { - public AtomicLong Score { get; set; } - public AtomicDouble speed; - public AtomicIntOnlyAddLongScore(int x, double speed = 1.0) : base(x) - { - this.Score = new(0); - this.speed = new(speed); - } + public AtomicLong Score { get; set; } = new(0); + public AtomicDouble speed = new(speed); + public void SetScore(AtomicLong score) => Score = score; /// 返回操作前的值 public override int SetReturnOri(int value) @@ -206,15 +195,11 @@ public int CompareExReturnOriNotAddScore(int newV, int compareTo) /// 在发生变化时,自动给Score加上变化的差乘以speed取整。 /// 注意:AtomicIntChangeAffectScore本身为AtomicInt,提供的Score可能构成环而死锁。 /// - public class AtomicIntChangeAffectScore : AtomicInt + public class AtomicIntChangeAffectScore(int x, double speed = 1.0) : AtomicInt(x) { - public AtomicInt Score { get; set; } - public AtomicDouble speed; - public AtomicIntChangeAffectScore(int x, double speed = 1.0) : base(x) - { - this.Score = new(0); - this.speed = new(speed); - } + public AtomicInt Score { get; set; } = new(0); + public AtomicDouble speed = new(speed); + public void SetScore(AtomicInt score) => Score = score; /// 返回操作前的值 public override int SetReturnOri(int value) @@ -294,13 +279,10 @@ public int CompareExReturnOriNotAddScore(int newV, int compareTo) } } - public class AtomicLong : Atomic + public class AtomicLong(long x) : Atomic { - protected long v; - public AtomicLong(long x) - { - v = x; - } + protected long v = x; + public override string ToString() => Interlocked.CompareExchange(ref v, -1, -1).ToString(); public long Get() => Interlocked.CompareExchange(ref v, -1, -1); public static implicit operator long(AtomicLong along) => Interlocked.CompareExchange(ref along.v, -1, -1); @@ -328,15 +310,11 @@ public AtomicLong(long x) /// 在发生正向的变化时,自动给Score加上正向变化的差乘以speed取整。 /// 注意:AtomicLongOnlyAddScore本身为AtomicLong,提供的Score可能构成环而死锁。 /// - public class AtomicLongOnlyAddScore : AtomicLong + public class AtomicLongOnlyAddScore(long x, double speed = 1.0) : AtomicLong(x) { - public AtomicLong Score { get; set; } - public AtomicDouble speed; - public AtomicLongOnlyAddScore(long x, double speed = 1.0) : base(x) - { - this.Score = new(0); - this.speed = new(speed); - } + public AtomicLong Score { get; set; } = new(0); + public AtomicDouble speed = new(speed); + public void SetScore(AtomicLong score) => Score = score; /// 返回操作前的值 @@ -402,13 +380,10 @@ public long CompareExReturnOriNotAddScore(long newV, long compareTo) } } - public class AtomicDouble : Atomic + public class AtomicDouble(double x) : Atomic { - private double v; - public AtomicDouble(double x) - { - v = x; - } + private double v = x; + public override string ToString() => Interlocked.CompareExchange(ref v, -2.0, -2.0).ToString(); public double Get() => Interlocked.CompareExchange(ref v, -2.0, -2.0); public static implicit operator double(AtomicDouble adouble) => Interlocked.CompareExchange(ref adouble.v, -2.0, -2.0); @@ -418,13 +393,10 @@ public AtomicDouble(double x) public double CompareExReturnOri(double newV, double compareTo) => Interlocked.CompareExchange(ref v, newV, compareTo); } - public class AtomicBool : Atomic + public class AtomicBool(bool x) : Atomic { - private int v;//v&1==0为false,v&1==1为true - public AtomicBool(bool x) - { - v = x ? 1 : 0; - } + private int v = x ? 1 : 0;//v&1==0为false,v&1==1为true + public override string ToString() => ((Interlocked.CompareExchange(ref v, -2, -2) & 1) == 0) ? "false" : "true"; public bool Get() => ((Interlocked.CompareExchange(ref v, -2, -2) & 1) == 1); public static implicit operator bool(AtomicBool abool) => abool.Get(); diff --git a/logic/Preparation/Utility/Tools/XY.cs b/logic/Preparation/Utility/Tools/XY.cs index 6495839b..5a2a1e89 100644 --- a/logic/Preparation/Utility/Tools/XY.cs +++ b/logic/Preparation/Utility/Tools/XY.cs @@ -2,10 +2,12 @@ namespace Preparation.Utility; -public class XY +public readonly struct XY { - public int x; - public int y; + public readonly int x; + public readonly int y; + + #region ctor public XY(int x, int y) { this.x = x; @@ -29,89 +31,139 @@ public XY(XY Direction, double length) this.y = (int)(length * Math.Sin(Direction.Angle())); } } - public override string ToString() - { - return "(" + x.ToString() + "," + y.ToString() + ")"; - } - public static int operator *(XY v1, XY v2) - { - return (v1.x * v2.x) + (v1.y * v2.y); - } - public static XY operator *(int a, XY v2) + #endregion + + public override string ToString() => $"({x}, {y})"; + /// 数量积 + public static int operator *(XY v1, XY v2) => (v1.x * v2.x) + (v1.y * v2.y); + /// 左数乘 + public static XY operator *(int a, XY v2) => new(a * v2.x, a * v2.y); + /// 右数乘 + public static XY operator *(XY v2, int a) => new(a * v2.x, a * v2.y); + public static XY operator +(XY v1, XY v2) => new(v1.x + v2.x, v1.y + v2.y); + public static XY operator -(XY v1, XY v2) => new(v1.x - v2.x, v1.y - v2.y); + public static bool operator ==(XY v1, XY v2) => (v1.x == v2.x) && (v1.y == v2.y); + public static bool operator !=(XY v1, XY v2) => (v1.x != v2.x) || (v1.y != v2.y); + + #region Distance + public static double DistanceFloor3(XY p1, XY p2) { - return new XY(a * v2.x, a * v2.y); + long c = (((long)(p1.x - p2.x) * (p1.x - p2.x)) + ((long)(p1.y - p2.y) * (p1.y - p2.y))) * 1000000; + long t = c / 2 + 1; + while (t * t > c || (t + 1) * (t + 1) <= c) + t = (c / t + t) / 2; + return t / 1000.0; } - public static XY operator *(XY v2, int a) + public static double DistanceCeil3(XY p1, XY p2) { - return new XY(a * v2.x, a * v2.y); + long c = (((long)(p1.x - p2.x) * (p1.x - p2.x)) + ((long)(p1.y - p2.y) * (p1.y - p2.y))) * 1000000; + long t = c / 2 + 1; + while (t * t > c || (t + 1) * (t + 1) <= c) + t = (c / t + t) / 2; + if (t * t == c) return t / 1000.0; + else return (t + 1) / 1000.0; } - public static XY operator +(XY v1, XY v2) + #endregion + + public double Length() => Math.Sqrt(((long)x * x) + ((long)y * y)); + public double Angle() => Math.Atan2(y, x); + + /// + /// 逆时针旋转90° + /// + public XY Perpendicular() => new(-y, x); + + public override bool Equals(object? obj) => (obj is not null) && (obj is XY xy) && (this == xy); + public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode(); + + /// + /// 解包 + /// + public void Deconstruct(out int x, out int y) { - return new XY(v1.x + v2.x, v1.y + v2.y); + x = this.x; y = this.y; } - public static XY operator -(XY v1, XY v2) +} + +public readonly struct CellXY +{ + public readonly int x; + public readonly int y; + + #region ctor + public CellXY(int x, int y) { - return new XY(v1.x - v2.x, v1.y - v2.y); + this.x = x; + this.y = y; } - public static bool operator ==(XY v1, XY v2) + public CellXY(double angle, double length) { - return v1.x == v2.x && v1.y == v2.y; + this.x = (int)(length * Math.Cos(angle)); + this.y = (int)(length * Math.Sin(angle)); } - public static bool operator !=(XY v1, XY v2) + public CellXY(XY Direction, double length) { - return v1.x != v2.x || v1.y != v2.y; + if (Direction.x == 0 && Direction.y == 0) + { + this.x = 0; + this.y = 0; + } + else + { + this.x = (int)(length * Math.Cos(Direction.Angle())); + this.y = (int)(length * Math.Sin(Direction.Angle())); + } } + #endregion - public static double DistanceFloor3(XY p1, XY p2) + public override string ToString() => $"({x}, {y})"; + /// 数量积 + public static int operator *(CellXY v1, CellXY v2) => (v1.x * v2.x) + (v1.y * v2.y); + /// 左数乘 + public static CellXY operator *(int a, CellXY v2) => new(a * v2.x, a * v2.y); + /// 右数乘 + public static CellXY operator *(CellXY v2, int a) => new(a * v2.x, a * v2.y); + public static CellXY operator +(CellXY v1, CellXY v2) => new(v1.x + v2.x, v1.y + v2.y); + public static CellXY operator -(CellXY v1, CellXY v2) => new(v1.x - v2.x, v1.y - v2.y); + public static bool operator ==(CellXY v1, CellXY v2) => (v1.x == v2.x) && (v1.y == v2.y); + public static bool operator !=(CellXY v1, CellXY v2) => (v1.x != v2.x) || (v1.y != v2.y); + + #region Distance + public static double DistanceFloor3(CellXY p1, CellXY p2) { long c = (((long)(p1.x - p2.x) * (p1.x - p2.x)) + ((long)(p1.y - p2.y) * (p1.y - p2.y))) * 1000000; long t = c / 2 + 1; while (t * t > c || (t + 1) * (t + 1) <= c) t = (c / t + t) / 2; - return (double)t / 1000.0; + return t / 1000.0; } - public static double DistanceCeil3(XY p1, XY p2) + public static double DistanceCeil3(CellXY p1, CellXY p2) { long c = (((long)(p1.x - p2.x) * (p1.x - p2.x)) + ((long)(p1.y - p2.y) * (p1.y - p2.y))) * 1000000; long t = c / 2 + 1; while (t * t > c || (t + 1) * (t + 1) <= c) t = (c / t + t) / 2; - if (t * t == c) return (double)t / 1000.0; - else return (double)(t + 1) / 1000.0; - } - public double Length() - { - return Math.Sqrt(((long)x * x) + ((long)y * y)); - } - public double Angle() - { - return Math.Atan2(y, x); + if (t * t == c) return t / 1000.0; + else return (t + 1) / 1000.0; } + #endregion + + public double Length() => Math.Sqrt(((long)x * x) + ((long)y * y)); + public double Angle() => Math.Atan2(y, x); /// /// 逆时针旋转90° /// - public XY Perpendicular() - { - return new XY(-y, x); - } + public CellXY Perpendicular() => new(-y, x); - public override bool Equals(object? obj) => obj is not null && obj is XY xy && this == xy; + public override bool Equals(object? obj) => (obj is not null) && (obj is CellXY xy) && (this == xy); + public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode(); - public override int GetHashCode() + /// + /// 解包 + /// + public void Deconstruct(out int x, out int y) { - return this.x.GetHashCode() ^ this.y.GetHashCode(); + x = this.x; y = this.y; } } -public class GridXY : XY -{ - public GridXY(int x, int y) : base(x, y) { } - public GridXY(double angle, double length) : base(angle, length) { } - public GridXY(XY Direction, double length) : base(Direction, length) { } -} -public class CellXY : XY -{ - public CellXY(int x, int y) : base(x, y) { } - public CellXY(double angle, double length) : base(angle, length) { } - public CellXY(XY Direction, double length) : base(Direction, length) { } -} diff --git a/logic/Server/ArgumentOptions.cs b/logic/Server/ArgumentOptions.cs index 972f3678..5280fe25 100755 --- a/logic/Server/ArgumentOptions.cs +++ b/logic/Server/ArgumentOptions.cs @@ -4,10 +4,10 @@ namespace Server { public class DefaultArgumentOptions { - public static string FileName = "xxxxxxxxxx";// - public static string Token = "xxxxxxxxxx";// - public static string Url = "xxxxxxxxxx";// - public static string MapResource = "xxxxxxxxxx"; // + public const string FileName = "xxxxxxxxxx";// + public const string Token = "xxxxxxxxxx";// + public const string Url = "xxxxxxxxxx";// + public const string MapResource = "xxxxxxxxxx"; // } public class ArgumentOptions { @@ -64,7 +64,7 @@ public class ArgumentOptions [Option('u', "url", Required = false, HelpText = "Web Url")] public string Url { get; set; } = "114514"; [Option('m', "mapResource", Required = false, HelpText = "Map Resource Path")] - public string mapResource { get; set; } = DefaultArgumentOptions.MapResource; + public string MapResource { get; set; } = DefaultArgumentOptions.MapResource; [Option("requestOnly", Required = false, HelpText = "Only send web requests")] public bool RequestOnly { get; set; } = false; [Option("finalGame", Required = false, HelpText = "Whether it is the final game")] diff --git a/logic/Server/CopyInfo.cs b/logic/Server/CopyInfo.cs index 25c0dc0e..23068fe4 100755 --- a/logic/Server/CopyInfo.cs +++ b/logic/Server/CopyInfo.cs @@ -1,5 +1,7 @@ using GameClass.GameObj; +using GameClass.GameObj.Areas; using Preparation.Utility; +using Utility = Preparation.Utility; using Protobuf; namespace Server @@ -14,24 +16,24 @@ public static class CopyInfo case GameObjType.Ship: return Ship((Ship)gameObj, time); case GameObjType.Home: - return Home((GameClass.GameObj.Areas.Home)gameObj, time); + return Home((Home)gameObj, time); case GameObjType.Bullet: return Bullet((Bullet)gameObj); case GameObjType.BombedBullet: return BombedBullet((BombedBullet)gameObj); case GameObjType.Resource: - return Resource((GameClass.GameObj.Areas.Resource)gameObj); + return Resource((Resource)gameObj); case GameObjType.Construction: - GameClass.GameObj.Areas.Construction construction = (GameClass.GameObj.Areas.Construction)gameObj; - if (construction.ConstructionType == Preparation.Utility.ConstructionType.Factory) + Construction construction = (Construction)gameObj; + if (construction.ConstructionType == Utility.ConstructionType.Factory) return Factory(construction); - else if (construction.ConstructionType == Preparation.Utility.ConstructionType.Community) + else if (construction.ConstructionType == Utility.ConstructionType.Community) return Community(construction); - else if (construction.ConstructionType == Preparation.Utility.ConstructionType.Fort) + else if (construction.ConstructionType == Utility.ConstructionType.Fort) return Fort(construction); return null; case GameObjType.Wormhole: - return Wormhole((GameClass.GameObj.Areas.Wormhole)gameObj); + return Wormhole((Wormhole)gameObj); default: return null; } } @@ -72,7 +74,7 @@ public static class CopyInfo return msg; } - private static MessageOfObj? Home(GameClass.GameObj.Areas.Home player, long time) + private static MessageOfObj? Home(Home player, long time) { MessageOfObj msg = new() { @@ -125,7 +127,7 @@ private static MessageOfObj BombedBullet(BombedBullet bombedBullet) return msg; } - private static MessageOfObj Resource(GameClass.GameObj.Areas.Resource resource) + private static MessageOfObj Resource(Resource resource) { MessageOfObj msg = new() { @@ -138,7 +140,7 @@ private static MessageOfObj Resource(GameClass.GameObj.Areas.Resource resource) }; return msg; } - private static MessageOfObj Factory(GameClass.GameObj.Areas.Construction construction) + private static MessageOfObj Factory(Construction construction) { MessageOfObj msg = new() { @@ -153,7 +155,7 @@ private static MessageOfObj Factory(GameClass.GameObj.Areas.Construction constru return msg; } - private static MessageOfObj Community(GameClass.GameObj.Areas.Construction construction) + private static MessageOfObj Community(Construction construction) { MessageOfObj msg = new() { @@ -168,7 +170,7 @@ private static MessageOfObj Community(GameClass.GameObj.Areas.Construction const return msg; } - private static MessageOfObj Fort(GameClass.GameObj.Areas.Construction construction) + private static MessageOfObj Fort(Construction construction) { MessageOfObj msg = new() { @@ -182,7 +184,7 @@ private static MessageOfObj Fort(GameClass.GameObj.Areas.Construction constructi }; return msg; } - private static MessageOfObj Wormhole(GameClass.GameObj.Areas.Wormhole wormhole) + private static MessageOfObj Wormhole(Wormhole wormhole) { MessageOfObj msg = new() { diff --git a/logic/Server/GameServer.cs b/logic/Server/GameServer.cs index 7d7a7a06..00e3337c 100755 --- a/logic/Server/GameServer.cs +++ b/logic/Server/GameServer.cs @@ -13,16 +13,16 @@ namespace Server { partial class GameServer : ServerBase { - private ConcurrentDictionary semaDict = new(); + private readonly ConcurrentDictionary semaDict = new(); // private object semaDictLock = new(); protected readonly ArgumentOptions options; - private HttpSender? httpSender; + private readonly HttpSender? httpSender; private readonly object gameLock = new(); private MessageToClient currentGameInfo = new(); - private MessageOfObj currentMapMsg = new(); + private readonly MessageOfObj currentMapMsg = new(); private readonly object newsLock = new(); - private List currentNews = []; - private SemaphoreSlim endGameSem = new(0); + private readonly List currentNews = []; + private readonly SemaphoreSlim endGameSem = new(0); protected readonly Game game; private readonly uint spectatorMinPlayerID = 2023; public int playerNum; @@ -30,7 +30,7 @@ partial class GameServer : ServerBase protected long[][] communicationToGameID; // 通信用的ID映射到游戏内的ID,0指向队伍1,1指向队伍2,通信中0为大本营,1-5为船 private readonly object messageToAllClientsLock = new(); public static readonly long SendMessageToClientIntervalInMilliseconds = 50; - private MessageWriter? mwr = null; + private readonly MessageWriter? mwr = null; private readonly object spectatorJoinLock = new(); public void StartGame() @@ -96,13 +96,9 @@ private void SaveGameResult(string path) result.Add("RedTeam", score[0]); result.Add("BlueTeam", score[1]); JsonSerializer serializer = new(); - using (StreamWriter sw = new(path)) - { - using (JsonWriter writer = new JsonTextWriter(sw)) - { - serializer.Serialize(writer, result); - } - } + using StreamWriter sw = new(path); + using JsonTextWriter writer = new(sw); + serializer.Serialize(writer, result); } protected void SendGameResult(int[] scores, int mode) // 天梯的 Server 给网站发消息记录比赛结果 @@ -115,7 +111,9 @@ private void OnGameEnd() game.ClearAllLists(); mwr?.Flush(); if (options.ResultFileName != DefaultArgumentOptions.FileName) - SaveGameResult(options.ResultFileName.EndsWith(".json") ? options.ResultFileName : options.ResultFileName + ".json"); + SaveGameResult(options.ResultFileName.EndsWith(".json") + ? options.ResultFileName + : options.ResultFileName + ".json"); int[] scores = GetScore(); SendGameResult(scores, options.Mode); endGameSem.Release(); @@ -248,7 +246,7 @@ private MessageOfMap MapMsg() public GameServer(ArgumentOptions options) { this.options = options; - if (options.mapResource == DefaultArgumentOptions.MapResource) + if (options.MapResource == DefaultArgumentOptions.MapResource) game = new(MapInfo.defaultMapStruct, options.TeamCount); else { @@ -257,33 +255,31 @@ public GameServer(ArgumentOptions options) { string? line; int i = 0, j = 0; - using (StreamReader sr = new(options.mapResource)) + using StreamReader sr = new(options.MapResource); + while (!sr.EndOfStream && i < GameData.MapRows) { - while (!sr.EndOfStream && i < GameData.MapRows) + if ((line = sr.ReadLine()) != null) { - if ((line = sr.ReadLine()) != null) + string[] nums = line.Split(' '); + foreach (string item in nums) { - string[] nums = line.Split(' '); - foreach (string item in nums) + if (item.Length > 1)//以兼容原方案 + { + map[i, j] = (uint)int.Parse(item); + } + else + { + //2022-04-22 by LHR 十六进制编码地图方案(防止地图编辑员瞎眼x + map[i, j] = (uint)MapEncoder.Hex2Dec(char.Parse(item)); + } + j++; + if (j >= GameData.MapCols) { - if (item.Length > 1)//以兼容原方案 - { - map[i, j] = (uint)int.Parse(item); - } - else - { - //2022-04-22 by LHR 十六进制编码地图方案(防止地图编辑员瞎眼x - map[i, j] = (uint)MapEncoder.Hex2Dec(char.Parse(item)); - } - j++; - if (j >= GameData.MapCols) - { - j = 0; - break; - } + j = 0; + break; } - i++; } + i++; } } } @@ -318,7 +314,7 @@ public GameServer(ArgumentOptions options) { try { - mwr = new MessageWriter(options.FileName, options.TeamCount, options.ShipCount); + mwr = new(options.FileName, options.TeamCount, options.ShipCount); } catch { @@ -328,7 +324,7 @@ public GameServer(ArgumentOptions options) if (options.Url != DefaultArgumentOptions.Url && options.Token != DefaultArgumentOptions.Token) { - this.httpSender = new HttpSender(options.Url, options.Token); + httpSender = new(options.Url, options.Token); } } } diff --git a/logic/Server/HttpSender.cs b/logic/Server/HttpSender.cs index fe8f349a..41a99aa7 100755 --- a/logic/Server/HttpSender.cs +++ b/logic/Server/HttpSender.cs @@ -4,8 +4,8 @@ namespace Server { class HttpSender(string url, string token) { - private string url = url; - private string token = token; + private readonly string url = url; + private readonly string token = token; // void Test() // { @@ -17,19 +17,17 @@ public async Task SendHttpRequest(int[] scores, int mode) { var request = new HttpClient(); request.DefaultRequestHeaders.Authorization = new("Bearer", token); - using (var response = await request.PutAsync(url, JsonContent.Create(new + using var response = await request.PutAsync(url, JsonContent.Create(new { result = new TeamScore[] { - new() { team_id = 0, score = scores[0], }, - new() { team_id = 1, score = scores[1], }, + new() { TeamID = 0, Score = scores[0], }, + new() { TeamID = 1, Score = scores[1], }, }, - mode = mode - }))) - { - Console.WriteLine("Send to web successfully!"); - Console.WriteLine($"Web response: {await response.Content.ReadAsStringAsync()}"); - } + mode + })); + Console.WriteLine("Send to web successfully!"); + Console.WriteLine($"Web response: {await response.Content.ReadAsStringAsync()}"); } catch (Exception e) { @@ -41,7 +39,7 @@ public async Task SendHttpRequest(int[] scores, int mode) internal class TeamScore { - public int team_id { get; set; } = 0; - public int score { get; set; } = 0; + public int TeamID { get; set; } = 0; + public int Score { get; set; } = 0; } } diff --git a/logic/Server/PlaybackServer.cs b/logic/Server/PlaybackServer.cs index d00361d5..923b5827 100755 --- a/logic/Server/PlaybackServer.cs +++ b/logic/Server/PlaybackServer.cs @@ -9,15 +9,15 @@ namespace Server class PlaybackServer(ArgumentOptions options) : ServerBase { protected readonly ArgumentOptions options = options; - private int[] teamScore = new int[0]; - private ConcurrentDictionary semaDict = new(); + private int[] teamScore = []; + private readonly ConcurrentDictionary semaDict = new(); // private object semaDictLock = new(); private MessageToClient? currentGameInfo = new(); private MessageOfObj currentMapMsg = new(); - private uint spectatorMinPlayerID = 2023; + private const uint spectatorMinPlayerID = 2023; // private List spectatorList = new List(); public int TeamCount => options.TeamCount; - private object spectatorJoinLock = new(); + private readonly object spectatorJoinLock = new(); protected object spectatorLock = new(); protected bool isSpectatorJoin = false; protected bool IsSpectatorJoin @@ -35,7 +35,7 @@ protected bool IsSpectatorJoin } } private bool IsGaming { get; set; } = true; - private int[] finalScore = new int[0]; + private int[] finalScore = []; public int[] FinalScore { get @@ -43,10 +43,12 @@ public int[] FinalScore return finalScore; } } - public override int[] GetMoney() => new int[0]; + public override int[] GetMoney() => []; public override int[] GetScore() => FinalScore; - public override async Task AddPlayer(PlayerMsg request, IServerStreamWriter responseStream, ServerCallContext context) + public override async Task AddPlayer(PlayerMsg request, + IServerStreamWriter responseStream, + ServerCallContext context) { Console.WriteLine($"AddPlayer: {request.PlayerId}"); if (request.PlayerId >= spectatorMinPlayerID && options.NotAllowSpectator == false) @@ -207,117 +209,115 @@ public override void WaitForEnd() options.PlaybackSpeed = Math.Max(0.25, Math.Min(4.0, options.PlaybackSpeed)); timeInterval = (int)Math.Round(timeInterval / options.PlaybackSpeed); } - using (MessageReader mr = new(options.FileName)) - { - teamScore = new int[mr.teamCount]; - finalScore = new int[mr.teamCount]; - int infoNo = 0; - object cursorLock = new(); - var msgCurTop = Console.CursorTop; - var msgCurLeft = Console.CursorLeft; - var frt = new FrameRateTaskExecutor - ( - loopCondition: () => true, - loopToDo: () => - { - MessageToClient? msg = null; + using MessageReader mr = new(options.FileName); + teamScore = new int[mr.teamCount]; + finalScore = new int[mr.teamCount]; + int infoNo = 0; + object cursorLock = new(); + var msgCurTop = Console.CursorTop; + var msgCurLeft = Console.CursorLeft; + var frt = new FrameRateTaskExecutor + ( + loopCondition: () => true, + loopToDo: () => + { + MessageToClient? msg = null; - msg = mr.ReadOne(); - if (msg == null) - { - Console.WriteLine("The game doesn't come to an end because of timing up!"); - IsGaming = false; - ReportGame(msg); - return false; - } + msg = mr.ReadOne(); + if (msg == null) + { + Console.WriteLine("The game doesn't come to an end because of timing up!"); + IsGaming = false; ReportGame(msg); - lock (cursorLock) - { - var curTop = Console.CursorTop; - var curLeft = Console.CursorLeft; - Console.SetCursorPosition(msgCurLeft, msgCurTop); - Console.WriteLine($"Sending messages... Current message number: {infoNo}."); - Console.SetCursorPosition(curLeft, curTop); - } - if (msg != null) + return false; + } + ReportGame(msg); + lock (cursorLock) + { + var curTop = Console.CursorTop; + var curLeft = Console.CursorLeft; + Console.SetCursorPosition(msgCurLeft, msgCurTop); + Console.WriteLine($"Sending messages... Current message number: {infoNo}."); + Console.SetCursorPosition(curLeft, curTop); + } + if (msg != null) + { + foreach (var item in msg.ObjMessage) { - foreach (var item in msg.ObjMessage) - { - if (item.TeamMessage != null) - teamScore[item.TeamMessage.TeamId] = item.TeamMessage.Score; + if (item.TeamMessage != null) + teamScore[item.TeamMessage.TeamId] = item.TeamMessage.Score; - } } + } - ++infoNo; - if (msg == null) - { - Console.WriteLine("No game information in this file!"); - IsGaming = false; - ReportGame(msg); - return false; - } - if (msg.GameState == GameState.GameEnd) - { - Console.WriteLine("Game over normally!"); - IsGaming = false; - finalScore[0] = msg.AllMessage.BlueTeamScore; - finalScore[1] = msg.AllMessage.RedTeamScore; - ReportGame(msg); - return false; - } - return true; - }, - timeInterval: timeInterval, - finallyReturn: () => 0 - ) - { AllowTimeExceed = true, MaxTolerantTimeExceedCount = 5 }; + ++infoNo; + if (msg == null) + { + Console.WriteLine("No game information in this file!"); + IsGaming = false; + ReportGame(msg); + return false; + } + if (msg.GameState == GameState.GameEnd) + { + Console.WriteLine("Game over normally!"); + IsGaming = false; + finalScore[0] = msg.AllMessage.BlueTeamScore; + finalScore[1] = msg.AllMessage.RedTeamScore; + ReportGame(msg); + return false; + } + return true; + }, + timeInterval: timeInterval, + finallyReturn: () => 0 + ) + { AllowTimeExceed = true, MaxTolerantTimeExceedCount = 5 }; - Console.WriteLine("The server is well prepared! Please MAKE SURE that you have opened all the clients to watch the game!"); - Console.WriteLine("If ALL clients have opened, press any key to start."); - Console.ReadKey(); + Console.WriteLine("The server is well prepared! Please MAKE SURE that you have opened all the clients to watch the game!"); + Console.WriteLine("If ALL clients have opened, press any key to start."); + Console.ReadKey(); - new Thread - ( - () => + new Thread + ( + () => + { + var rateCurTop = Console.CursorTop; + var rateCurLeft = Console.CursorLeft; + lock (cursorLock) + { + rateCurTop = Console.CursorTop; + rateCurLeft = Console.CursorLeft; + Console.WriteLine($"Send message to clients frame rate: {frt.FrameRate}"); + } + while (!frt.Finished) { - var rateCurTop = Console.CursorTop; - var rateCurLeft = Console.CursorLeft; lock (cursorLock) { - rateCurTop = Console.CursorTop; - rateCurLeft = Console.CursorLeft; + var curTop = Console.CursorTop; + var curLeft = Console.CursorLeft; + Console.SetCursorPosition(rateCurLeft, rateCurTop); Console.WriteLine($"Send message to clients frame rate: {frt.FrameRate}"); + Console.SetCursorPosition(curLeft, curTop); } - while (!frt.Finished) - { - lock (cursorLock) - { - var curTop = Console.CursorTop; - var curLeft = Console.CursorLeft; - Console.SetCursorPosition(rateCurLeft, rateCurTop); - Console.WriteLine($"Send message to clients frame rate: {frt.FrameRate}"); - Console.SetCursorPosition(curLeft, curTop); - } - Thread.Sleep(1000); - } + Thread.Sleep(1000); } - ) - { IsBackground = true }.Start(); + } + ) + { IsBackground = true }.Start(); - lock (cursorLock) - { - msgCurLeft = Console.CursorLeft; - msgCurTop = Console.CursorTop; - Console.WriteLine("Sending messages..."); - } - frt.Start(); + lock (cursorLock) + { + msgCurLeft = Console.CursorLeft; + msgCurTop = Console.CursorTop; + Console.WriteLine("Sending messages..."); } + frt.Start(); } } finally { - teamScore ??= new int[0]; + teamScore ??= []; } } } diff --git a/logic/Server/Program.cs b/logic/Server/Program.cs index a85fe979..ad4cf179 100755 --- a/logic/Server/Program.cs +++ b/logic/Server/Program.cs @@ -50,12 +50,12 @@ static int Main(string[] args) { Console.WriteLine(welcome); } - Console.WriteLine("Server begins to run: " + options.ServerPort.ToString()); + Console.WriteLine($"Server begins to run: {options.ServerPort}"); try { var server = CreateServer(options); - Grpc.Core.Server rpcServer = new(new[] { new ChannelOption(ChannelOptions.SoReuseport, 0) }) + Grpc.Core.Server rpcServer = new([new ChannelOption(ChannelOptions.SoReuseport, 0)]) { Services = { AvailableService.BindService(server) }, Ports = { new ServerPort(options.ServerIP, options.ServerPort, ServerCredentials.Insecure) }