diff --git a/installer/installer/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/installer/installer/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 00000000..2217181c --- /dev/null +++ b/installer/installer/obj/Debug/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/installer/installer/obj/Debug/net8.0/installer.AssemblyInfo.cs b/installer/installer/obj/Debug/net8.0/installer.AssemblyInfo.cs new file mode 100644 index 00000000..494fbd48 --- /dev/null +++ b/installer/installer/obj/Debug/net8.0/installer.AssemblyInfo.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("installer")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+766320efb019d4e884b8edfa18de33081a87502a")] +[assembly: System.Reflection.AssemblyProductAttribute("installer")] +[assembly: System.Reflection.AssemblyTitleAttribute("installer")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/installer/installer/obj/Debug/net8.0/installer.AssemblyInfoInputs.cache b/installer/installer/obj/Debug/net8.0/installer.AssemblyInfoInputs.cache new file mode 100644 index 00000000..fddbabe7 --- /dev/null +++ b/installer/installer/obj/Debug/net8.0/installer.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +769cc5aa7bf6ff4abeb2d1325eeb86d7aeaca01abd0d0698e006095cf0112fb3 diff --git a/installer/installer/obj/Debug/net8.0/installer.GeneratedMSBuildEditorConfig.editorconfig b/installer/installer/obj/Debug/net8.0/installer.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 00000000..59a10be4 --- /dev/null +++ b/installer/installer/obj/Debug/net8.0/installer.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,17 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetFrameworkIdentifier = .NETCoreApp +build_property.TargetFrameworkVersion = v8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = installer +build_property.ProjectDir = C:\Users\贾兴道\Documents\GitHub\THUAI9\installer\installer\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/installer/installer/obj/Debug/net8.0/installer.GlobalUsings.g.cs b/installer/installer/obj/Debug/net8.0/installer.GlobalUsings.g.cs new file mode 100644 index 00000000..d12bcbc7 --- /dev/null +++ b/installer/installer/obj/Debug/net8.0/installer.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using System; +global using System.Collections.Generic; +global using System.IO; +global using System.Linq; +global using System.Net.Http; +global using System.Threading; +global using System.Threading.Tasks; diff --git a/installer/installer/obj/Release/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/installer/installer/obj/Release/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 00000000..2217181c --- /dev/null +++ b/installer/installer/obj/Release/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/installer/installer/obj/Release/net8.0/installer.AssemblyInfo.cs b/installer/installer/obj/Release/net8.0/installer.AssemblyInfo.cs new file mode 100644 index 00000000..e19c0bb3 --- /dev/null +++ b/installer/installer/obj/Release/net8.0/installer.AssemblyInfo.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("installer")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+766320efb019d4e884b8edfa18de33081a87502a")] +[assembly: System.Reflection.AssemblyProductAttribute("installer")] +[assembly: System.Reflection.AssemblyTitleAttribute("installer")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/installer/installer/obj/Release/net8.0/installer.AssemblyInfoInputs.cache b/installer/installer/obj/Release/net8.0/installer.AssemblyInfoInputs.cache new file mode 100644 index 00000000..97bbf71f --- /dev/null +++ b/installer/installer/obj/Release/net8.0/installer.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +1cb606ab90ed97054595fb1ebfec5f069c33efa5ccc93be4247ed2cba23943f3 diff --git a/installer/installer/obj/Release/net8.0/installer.GeneratedMSBuildEditorConfig.editorconfig b/installer/installer/obj/Release/net8.0/installer.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 00000000..59a10be4 --- /dev/null +++ b/installer/installer/obj/Release/net8.0/installer.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,17 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetFrameworkIdentifier = .NETCoreApp +build_property.TargetFrameworkVersion = v8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = installer +build_property.ProjectDir = C:\Users\贾兴道\Documents\GitHub\THUAI9\installer\installer\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/installer/installer/obj/Release/net8.0/installer.GlobalUsings.g.cs b/installer/installer/obj/Release/net8.0/installer.GlobalUsings.g.cs new file mode 100644 index 00000000..d12bcbc7 --- /dev/null +++ b/installer/installer/obj/Release/net8.0/installer.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using System; +global using System.Collections.Generic; +global using System.IO; +global using System.Linq; +global using System.Net.Http; +global using System.Threading; +global using System.Threading.Tasks; diff --git a/logic/GameClass/GameObj/Character.cs b/logic/GameClass/GameObj/Character.cs index 859ac9fe..a7248f26 100644 --- a/logic/GameClass/GameObj/Character.cs +++ b/logic/GameClass/GameObj/Character.cs @@ -69,6 +69,9 @@ public override bool IgnoreCollideExecutor(IGameObj targetObj) && XY.DistanceCeil3(targetObj.Position, Position) < Radius + targetObj.Radius - GameData.AdjustLength) return true; + LogicLogging.logger.LogDebug( + LoggingFunctional.CharacterLogInfo(this) + + $" IgnoreCollideExecutor with target {targetObj.ID} of type {targetObj.Type} at position {targetObj.Position}"); return false; } private long ChangeCharacterState(CharacterState value = CharacterState.NULL_CHARACTER_STATE, GameObj? gameobj = null) @@ -83,7 +86,14 @@ public long SetCharacterState(CharacterState value = CharacterState.NULL_CHARACT lock (actionLock) { CharacterState nowState = characterState; - if (nowState == value) return -1; + if (nowState == value) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.CharacterLogInfo(this) + + $" SetCharacterState called with the same state {value}, no change made"); + return -1; + } + else return ChangeCharacterState(value, gameobj); } } @@ -135,6 +145,9 @@ public bool TryToRemoveFromGame(CharacterState state) CanMove.SetROri(false); position = GameData.PosNotInGame; } + LogicLogging.logger.LogDebug( + LoggingFunctional.CharacterLogInfo(this) + + $" TryToRemoveFromGame with state {state} succeeded"); return true; } @@ -190,6 +203,9 @@ internal bool SetLoad(GoodsType type, int newValue) GoodsLoad.SetInternal(type, newValue); return true; } + LogicLogging.logger.LogDebug( + LoggingFunctional.CharacterLogInfo(this) + + $" SetLoad for {type} to {newValue} failed due to exceeding max carry"); } internal bool AddLoad(GoodsType type, int delta) { @@ -206,6 +222,9 @@ internal bool AddLoad(GoodsType type, int delta) GoodsLoad.SetInternal(type, target); return true; } + LogicLogging.logger.LogDebug( + LoggingFunctional.CharacterLogInfo(this) + + $" AddLoad for {type} by {delta} failed due to exceeding max carry"); } } diff --git a/logic/GameClass/GameObj/Map/Map.cs b/logic/GameClass/GameObj/Map/Map.cs index 09a1fed0..9575a8bf 100644 --- a/logic/GameClass/GameObj/Map/Map.cs +++ b/logic/GameClass/GameObj/Map/Map.cs @@ -134,7 +134,9 @@ public bool InAttackSize(Character character, GameObj gameObj) XY pos2 = gameObj.Position; XY del = pos1 - pos2; if (del * del > character.AttackSize * character.AttackSize) + { return false; + } return true; } public bool Remove(GameObj gameObj) @@ -145,6 +147,7 @@ public bool Remove(GameObj gameObj) ans.TryToRemove(); return true; } + LogicLogging.logger.LogInfo("fail to remove map obj"); return false; } public bool RemoveJustFromMap(GameObj gameObj) @@ -155,6 +158,7 @@ public bool RemoveJustFromMap(GameObj gameObj) return true; } return false; + LogicLogging.logger.LogInfo("fail to remove from map"); } public void Add(IGameObj gameObj) { diff --git a/logic/Gaming/ActionManager.cs b/logic/Gaming/ActionManager.cs index b5013746..82414566 100644 --- a/logic/Gaming/ActionManager.cs +++ b/logic/Gaming/ActionManager.cs @@ -101,6 +101,7 @@ public static bool Stop(Character character) return true; } } + LogicLogging.logger.LogWarning("Character is not commandable"); return false; } public bool Harvest(Character character) @@ -168,6 +169,7 @@ public bool Harvest(Character character) } ) { IsBackground = true }.Start(); + LogicLogging.logger.LogInfo("Character starts harvesting resource"); return true; } public bool Occupy(Character character) diff --git a/logic/Gaming/CharacterManager.cs b/logic/Gaming/CharacterManager.cs index a6ba7096..5cc9673b 100644 --- a/logic/Gaming/CharacterManager.cs +++ b/logic/Gaming/CharacterManager.cs @@ -34,17 +34,30 @@ public Character CreateCharacter(long teamId, long playerId, CharacterType type) teamDict[playerId] = ch; // ensure the character is also added to the map collection map.Add(ch); + LogicLogging.logger.LogInfo($"Character created: Team {teamId}, Player {playerId}, Type {type}"); return ch; } public bool RecruitCharacter(long teamId, long playerId, CharacterType type, XY birthPos) { var factory = game.GetTeamFactory(teamId); - if (factory == null) return false; - if (!factory.CanRecruit.Get()) return false; + if (factory == null) + { + LogicLogging.logger.LogError($"Factory not found for Team {teamId} when recruiting character."); + return false; + } + if (!factory.CanRecruit.Get()) + { + LogicLogging.logger.LogWarning($"Factory for Team {teamId} cannot recruit at this time."); + return false; + } var occ = OccupationFactory.FindIOccupation(type); int cost = occ.Cost; - if (factory.ComputingPower.Get() < cost) return false; + if (factory.ComputingPower.Get() < cost) + { + LogicLogging.logger.LogWarning($"Not enough computing power for Team {teamId} to recruit character. Required: {cost}, Available: {factory.ComputingPower.Get()}"); + return false; + } factory.ComputingPower.SubRNow(cost); var ch = CreateCharacter(teamId, playerId, type); ActivateCharacter(teamId, playerId, birthPos); @@ -53,8 +66,16 @@ public bool RecruitCharacter(long teamId, long playerId, CharacterType type, XY public bool ActivateCharacter(long teamId, long playerId, XY pos) { - if (!teamCharacters.TryGetValue(teamId, out var dict)) return false; - if (!dict.TryGetValue(playerId, out var ch)) return false; + if (!teamCharacters.TryGetValue(teamId, out var dict)) + { + LogicLogging.logger.LogError($"Team {teamId} not found when activating character."); + return false; + } + if (!dict.TryGetValue(playerId, out var ch)) + { + LogicLogging.logger.LogError($"Character for Team {teamId}, Player {playerId} not found when activating."); + return false; + } ch.IsRemoved.SetROri(false); ch.CanMove.SetROri(true); @@ -73,7 +94,10 @@ public bool ActivateCharacter(long teamId, long playerId, XY pos) // 如果找不到合法点则仍使用原位置(可能会导致角色被卡住),但尽量避免该情况 } } - catch { } + catch + { + LogicLogging.logger.LogError($"Error occurred while checking for collisions or finding spawn position for Team {teamId}, Player {playerId}. Defaulting to original position."); + } ch.ReSetPos(spawnPos); ch.SetCharacterState(CharacterState.IDLE); @@ -101,9 +125,13 @@ private bool IsPositionColliding(Character ch, XY pos) { if (((IMovable)ch).WillCollideWith(obj, pos)) return true; } - catch { } + catch + { + LogicLogging.logger.LogError($"Error occurred while checking collision between Character (Team {ch.TeamID.Get()}, Player {ch.PlayerID.Get()}) and object ID {obj.ID}. Ignoring this object for collision check."); + } } } + LogicLogging.logger.LogDebug($"Position {pos} is free for Character (Team {ch.TeamID.Get()}, Player {ch.PlayerID.Get()})."); return false; } @@ -138,8 +166,11 @@ private bool TryFindNearbyFreePosition(Character ch, XY center, out XY result) private void CheckTech(long teamId, Character ch) { - if (!game.teams.TryGetValue(teamId, out var t)) return; - + if (!game.teams.TryGetValue(teamId, out var t)) + { + LogicLogging.logger.LogError($"Team {teamId} not found when checking tech for character."); + return; + } int effLevel = t.GetTech("Efficiency"); int robustLevel = t.GetTech("Robust"); int warriorLevel = t.GetTech("Warrior"); @@ -178,6 +209,7 @@ public bool TryGetCharacter(long playerId, out Character character) if (teamDict.TryGetValue(playerId, out character!)) return true; } character = null!; + LogicLogging.logger.LogWarning($"Character for Player {playerId} not found in any team."); return false; } @@ -188,6 +220,7 @@ public bool TryGetCharacter(long teamId, long playerId, out Character character) { return dict.TryGetValue(playerId, out character!); } + LogicLogging.logger.LogWarning($"Team {teamId} not found when trying to get character for Player {playerId}."); return false; } @@ -200,9 +233,21 @@ public IEnumerable GetTeamCharacters(long teamId) public bool Destroy(long teamId, long playerId, CharacterState state = CharacterState.NULL_CHARACTER_STATE) { - if (!teamCharacters.TryGetValue(teamId, out var dict)) return false; - if (!dict.TryGetValue(playerId, out var ch)) return false; - if (!ch.TryToRemoveFromGame(state)) return false; + if (!teamCharacters.TryGetValue(teamId, out var dict)) + { + LogicLogging.logger.LogError($"Team {teamId} not found when trying to destroy character for Player {playerId}."); + return false; + } + if (!dict.TryGetValue(playerId, out var ch)) + { + LogicLogging.logger.LogError($"Character for Team {teamId}, Player {playerId} not found when trying to destroy."); + return false; + } + if (!ch.TryToRemoveFromGame(state)) + { + LogicLogging.logger.LogWarning($"Failed to remove Character for Team {teamId}, Player {playerId} from game."); + return false; + } ch.CanMove.SetROri(false); dict.TryRemove(playerId, out _); map.Remove(ch); @@ -213,6 +258,7 @@ public void BeAttacked(Character character, Character obj) { if (obj.TeamID.Get() == character.TeamID.Get()) { + LogicLogging.logger.LogWarning($"Character (Team {character.TeamID.Get()}, Player {character.PlayerID.Get()}) is being attacked by an ally (Team {obj.TeamID.Get()}, Player {obj.PlayerID.Get()}). No damage applied."); return; } long subHP = (long)(obj.AttackPower - character.Robust); @@ -243,7 +289,10 @@ public void BeAttacked(Character character, Character obj) public bool Recover(Character character, long recover) { if (recover <= 0) + { + LogicLogging.logger.LogWarning($"Attempted to recover non-positive HP for Character (Team {character.TeamID.Get()}, Player {character.PlayerID.Get()}). No HP recovered."); return false; + } character.HP.AddPositiveV(recover); return true; } @@ -251,7 +300,10 @@ public bool Recover(Character character, long recover) public bool ImproveATK(Character character, long ATK) { if (ATK <= 0) + { + LogicLogging.logger.LogWarning($"Attempted to improve attack power by non-positive value for Character (Team {character.TeamID.Get()}, Player {character.PlayerID.Get()}). No attack power improved."); return false; + } character.AttackPower.SetMaxV(character.AttackPower + ATK); character.AttackPower.AddPositiveV(ATK); return true; @@ -260,7 +312,10 @@ public bool ImproveATK(Character character, long ATK) public bool ImproveEfficiency(Character character, long efficiency) { if (efficiency <= 0) + { + LogicLogging.logger.LogWarning($"Attempted to improve efficiency by non-positive value for Character (Team {character.TeamID.Get()}, Player {character.PlayerID.Get()}). No efficiency improved."); return false; + } character.Efficiency.AddPositiveV(efficiency); return true; } diff --git a/logic/Gaming/Game.cs b/logic/Gaming/Game.cs index 3a41fc5c..cfc8749c 100644 --- a/logic/Gaming/Game.cs +++ b/logic/Gaming/Game.cs @@ -72,39 +72,46 @@ public bool StartGame(int milliSeconds) } if (!gameMap.Timer.Start(() => { }, () => CheckAndHandleGameEnd(), milliSeconds)) + { + LogicLogging.logger.LogError("Failed to start game timer."); return false; + } new Thread - ( - () => - { - Thread.Sleep(GameData.CheckInterval); - new Timothy.FrameRateTask.FrameRateTaskExecutor - ( - loopCondition: () => gameMap.Timer.IsGaming, - loopToDo: () => + ( + () => + { + Thread.Sleep(GameData.CheckInterval); + new Timothy.FrameRateTask.FrameRateTaskExecutor + ( + loopCondition: () => gameMap.Timer.IsGaming, + loopToDo: () => + { + foreach (var team in teams) { - foreach (var team in teams) - { - var fac = team.Value.Factory; - if (fac == null) continue; - fac.TickComputingPower(GameData.CheckInterval); - } - - return !CheckAndHandleGameEnd(); - }, - timeInterval: GameData.CheckInterval, - finallyReturn: () => 0 - ).Start(); - } - ).Start(); + var fac = team.Value.Factory; + if (fac == null) continue; + fac.TickComputingPower(GameData.CheckInterval); + } + + return !CheckAndHandleGameEnd(); + }, + timeInterval: GameData.CheckInterval, + finallyReturn: () => 0 + ).Start(); + } + ).Start(); return true; } public bool RecruitCharacterAtFactory(long teamId, long playerId, Preparation.Utility.CharacterType type) { var fac = GetTeamFactory(teamId); - if (fac == null) return false; + if (fac == null) + { + LogicLogging.logger.LogWarning($"RecruitCharacterAtFactory failed: Factory for team {teamId} not found."); + return false; + } return characterManager.RecruitCharacter(teamId, playerId, type, fac.Position); } @@ -116,8 +123,16 @@ public bool RecruitCharacterAtFactory(long teamId, long playerId, Preparation.Ut /// 是否成功受理 public bool Move(long teamId, long playerId, int timeMs, double direction) { - if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) return false; - if (character == null || character.IsRemoved) return false; + if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) + { + LogicLogging.logger.LogWarning($"Move failed: Character for team {teamId} player {playerId} not found."); + return false; + } + if (character == null || character.IsRemoved) + { + LogicLogging.logger.LogWarning($"Move failed: Character for team {teamId} player {playerId} is null or removed."); + return false; + } return actionManager.MoveCharacter(character, timeMs, direction); } @@ -130,9 +145,16 @@ public bool Move(long teamId, long playerId, int timeMs, double direction) /// 是否成功受理 public bool Attack(long teamId, long playerId) { - if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) return false; - if (character == null || character.IsRemoved) return false; - + if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) + { + LogicLogging.logger.LogWarning($"Attack failed: Character for team {teamId} player {playerId} not found."); + return false; + } + if (character == null || character.IsRemoved) + { + LogicLogging.logger.LogWarning($"Attack failed: Character for team {teamId} player {playerId} is null or removed."); + return false; + } int attackRange = (int)character.AttackSize.GetValue(); var enemies = gameMap.CharacterInTheRangeNotTeamID(character.Position, attackRange, character.TeamID.Get()); if (enemies != null && enemies.Count > 0) @@ -160,7 +182,7 @@ public bool Attack(long teamId, long playerId) { return actionManager.Attack(character, factory); } - + LogicLogging.logger.LogWarning($"Attack failed: No valid targets in range for character of team {teamId} player {playerId}."); return false; } @@ -171,9 +193,16 @@ public bool Attack(long teamId, long playerId) /// 是否成功受理 public bool Harvest(long teamId, long playerId) { - if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) return false; - if (character == null || character.IsRemoved) return false; - + if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) + { + LogicLogging.logger.LogWarning($"Harvest failed: Character for team {teamId} player {playerId} not found."); + return false; + } + if (character == null || character.IsRemoved) + { + LogicLogging.logger.LogWarning($"Harvest failed: Character for team {teamId} player {playerId} is null or removed."); + return false; + } return actionManager.Harvest(character); } @@ -183,8 +212,16 @@ public bool Harvest(long teamId, long playerId) /// public bool Trade(long teamId, long playerId, Preparation.Utility.GoodsType type, int amount, bool buy) { - if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) return false; - if (character == null) return false; + if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) + { + LogicLogging.logger.LogWarning($"Trade failed: Character for team {teamId} player {playerId} not found."); + return false; + } + if (character == null) + { + LogicLogging.logger.LogWarning($"Trade failed: Character for team {teamId} player {playerId} is null."); + return false; + } return buy ? tradeManager.Buy(character, type, amount) : tradeManager.Sell(character, type, amount); } @@ -194,9 +231,16 @@ public bool Trade(long teamId, long playerId, Preparation.Utility.GoodsType type /// public bool Occupy(long teamId, long playerId) { - if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) return false; - if (character == null || character.IsRemoved) return false; - + if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) + { + LogicLogging.logger.LogWarning($"Occupy failed: Character for team {teamId} player {playerId} not found."); + return false; + } + if (character == null || character.IsRemoved) + { + LogicLogging.logger.LogWarning($"Occupy failed: Character for team {teamId} player {playerId} is null or removed."); + return false; + } return actionManager.Occupy(character); } @@ -214,9 +258,21 @@ public bool UplevelTech(long teamId, Preparation.Utility.TechType tech) /// public bool Recover(long teamId, long playerId, long recover) { - if (recover <= 0) return false; - if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) return false; - if (character == null || character.IsRemoved) return false; + if (recover <= 0) + { + LogicLogging.logger.LogWarning($"Recover failed: Invalid recover amount {recover} for team {teamId} player {playerId}."); + return false; + } + if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) + { + LogicLogging.logger.LogWarning($"Recover failed: Character for team {teamId} player {playerId} not found."); + return false; + } + if (character == null || character.IsRemoved) + { + LogicLogging.logger.LogWarning($"Recover failed: Character for team {teamId} player {playerId} is null or removed."); + return false; + } return characterManager.Recover(character, recover); } @@ -225,9 +281,17 @@ public bool Recover(long teamId, long playerId, long recover) /// public bool Recover(long teamId, long recover) { - if (recover <= 0) return false; + if (recover <= 0) + { + LogicLogging.logger.LogWarning($"Recover failed: Invalid recover amount {recover} for team {teamId} factory."); + return false; + } var fac = GetTeamFactory(teamId); - if (fac == null) return false; + if (fac == null) + { + LogicLogging.logger.LogWarning($"Recover failed: Factory for team {teamId} not found."); + return false; + } fac.HP.AddPositiveV(recover); return true; } @@ -537,9 +601,16 @@ public TeamStatus(long teamId, long score, long factoryHp, long factoryHpMax, lo /// public CharacterStatus? GetCharacterStatus(long teamId, long playerId) { - if (!characterManager.TryGetCharacter(teamId, playerId, out var ch)) return null; - if (ch == null) return null; - + if (!characterManager.TryGetCharacter(teamId, playerId, out var ch)) + { + LogicLogging.logger.LogWarning($"GetCharacterStatus failed: Character for team {teamId} player {playerId} not found."); + return null; + } + if (ch == null) + { + LogicLogging.logger.LogWarning($"GetCharacterStatus failed: Character for team {teamId} player {playerId} is null."); + return null; + } var pos = ch.Position; long hp = 0, hpMax = 0, atk = 0, atkSize = 0, robust = 0, efficiency = 0, view = 0, carry = 0, moveSpeed = 0; @@ -808,9 +879,21 @@ public bool CheckAndHandleGameEnd() /// public bool Load(long teamId, long playerId, Preparation.Utility.GoodsType type, int amount) { - if (amount <= 0) return false; - if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) return false; - if (character == null || character.IsRemoved) return false; + if (amount <= 0) + { + LogicLogging.logger.LogWarning($"Load failed: Invalid amount {amount} for team {teamId} player {playerId}."); + return false; + } + if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) + { + LogicLogging.logger.LogWarning($"Load failed: Character for team {teamId} player {playerId} not found."); + return false; + } + if (character == null || character.IsRemoved) + { + LogicLogging.logger.LogWarning($"Load failed: Character for team {teamId} player {playerId} is null or removed."); + return false; + } return actionManager.Load(character, type, amount); } @@ -820,8 +903,16 @@ public bool Load(long teamId, long playerId, Preparation.Utility.GoodsType type, /// public bool Stop(long teamId, long playerId) { - if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) return false; - if (character == null || character.IsRemoved) return false; + if (!characterManager.TryGetCharacter(teamId, playerId, out var character)) + { + LogicLogging.logger.LogWarning($"Stop failed: Character for team {teamId} player {playerId} not found."); + return false; + } + if (character == null || character.IsRemoved) + { + LogicLogging.logger.LogWarning($"Stop failed: Character for team {teamId} player {playerId} is null or removed."); + return false; + } return ActionManager.Stop(character); } } diff --git a/logic/Gaming/Produce.cs b/logic/Gaming/Produce.cs index dd19b7f1..74ca10a0 100644 --- a/logic/Gaming/Produce.cs +++ b/logic/Gaming/Produce.cs @@ -77,7 +77,13 @@ public bool Start() while (true) { long cur = factory.Source.Get(); - if (cur < totalCost) return false; + if (cur < totalCost) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(factory) + + $" failed to start production of {amount} {type} due to insufficient source (current: {cur}, needed: {totalCost})"); + return false; + } if (factory.Source.CompareExROri(cur - totalCost, cur) == cur) break; } @@ -110,6 +116,9 @@ public bool Start() } catch (Exception) { + LogicLogging.logger.LogError( + LoggingFunctional.AutoLogInfo(factory) + + $" encountered an error during production of {amount} {type}, produced so far: {produced}"); } finally { @@ -129,17 +138,38 @@ public bool Start() public bool Produce(long teamId, GoodsType type, int amount) { - if (amount <= 0) return false; + if (amount <= 0) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(teamId) + + $" failed to start production of {amount} {type} due to non-positive amount"); + return false; + } var factory = GetTeamFactory(teamId); - if (factory == null) return false; - - if (!factory.CanProduce.Get()) return false; - + if (factory == null) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(teamId) + + $" failed to start production of {amount} {type} due to missing factory"); + return false; + } + if (!factory.CanProduce.Get()) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(factory) + + $" failed to start production of {amount} {type} because factory is currently busy"); + return false; + } long storageMax = factory.Storage.GetValue(); int currentTotal = 0; for (int i = 1; i <= 5; i++) currentTotal += factory.GetGoods((GoodsType)i); - if (currentTotal >= storageMax) return false; - + if (currentTotal >= storageMax) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(factory) + + $" failed to start production of {amount} {type} because factory storage is already full (current total: {currentTotal}, max: {storageMax})"); + return false; + } var production = new Production(this, factory, type, amount); return production.Start(); } diff --git a/logic/Gaming/Teams.cs b/logic/Gaming/Teams.cs index 6bc85dab..d0e1091d 100644 --- a/logic/Gaming/Teams.cs +++ b/logic/Gaming/Teams.cs @@ -37,8 +37,16 @@ public TeamState(long teamId, Factory factory) public bool TrySetTech(string key, int value) { - if (value < 0 || value > 2) return false; - if (!Tech.TryGetValue(key, out var atomic)) return false; + if (value < 0 || value > 2) + { + LogicLogging.logger.LogDebug($"Invalid tech level {value} for {key} of team {TeamId}"); + return false; + } + if (!Tech.TryGetValue(key, out var atomic)) + { + LogicLogging.logger.LogDebug($"Tech {key} not found for team {TeamId}"); + return false; + } atomic.SetROri(value); return true; } @@ -96,8 +104,16 @@ private void InitTeams() public bool AddTeamScore(long teamId, long delta) { - if (!teams.TryGetValue(teamId, out var t)) return false; - if (delta == 0) return true; + if (!teams.TryGetValue(teamId, out var t)) + { + LogicLogging.logger.LogDebug($"Attempted to add score for non-existent team {teamId}"); + return false; + } + if (delta == 0) + { + LogicLogging.logger.LogDebug($"Attempted to add zero score for team {teamId}, no change made"); + return true; + } if (delta > 0) t.Score.AddRNow(delta); else t.Score.SubRNow(-delta); return true; } diff --git a/logic/Gaming/Trade.cs b/logic/Gaming/Trade.cs index b5b3dbf0..486fc378 100644 --- a/logic/Gaming/Trade.cs +++ b/logic/Gaming/Trade.cs @@ -25,20 +25,56 @@ public TradeManager(Game game, Map gameMap) public bool Sell(Character character, GoodsType type, int amount) { - if (character == null) return false; + if (character == null) + { + LogicLogging.logger.LogError( + LoggingFunctional.AutoLogInfo(character) + + $" failed to sell {amount} {type} due to null character reference"); + return false; + } long teamId = character.TeamID.Get(); - if (amount <= 0) return false; - if (character.IsRemoved) return false; - + if (amount <= 0) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(character) + + $" failed to sell {amount} {type} due to non-positive amount"); + return false; + } + if (character.IsRemoved) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(character) + + $" failed to sell {amount} {type} because character is removed from the game"); + return false; + } Market? market = (Market?)gameMap.OneForInteract(character.Position, GameObjType.MARKET); - if (market == null) return false; - if (!GameData.ApproachToInteract(character.Position, market.Position)) return false; - + if (market == null) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(character) + + $" failed to sell {amount} {type} because no market is in interaction range"); + return false; + } + if (!GameData.ApproachToInteract(character.Position, market.Position)) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(character) + + $" failed to sell {amount} {type} because character is not close enough to the market"); + return false; + } int have = character.GoodsLoad.Get(type); - if (have < amount) return false; - + if (have < amount) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(character) + + $" failed to sell {amount} {type} because character only has {have}"); + return false; + } if (!character.GoodsLoad.Add(type, -amount)) { + LogicLogging.logger.LogError( + LoggingFunctional.AutoLogInfo(character) + + $" failed to sell {amount} {type} due to an unexpected error when updating goods load"); return false; } @@ -53,27 +89,70 @@ public bool Sell(Character character, GoodsType type, int amount) public bool Buy(Character character, GoodsType type, int amount) { - if (character == null) return false; + if (character == null) + { + LogicLogging.logger.LogError( + LoggingFunctional.AutoLogInfo(character) + + $" failed to buy {amount} {type} due to null character reference"); + return false; + } long teamId = character.TeamID.Get(); - if (amount <= 0) return false; - if (character.IsRemoved) return false; - + if (amount <= 0) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(character) + + $" failed to buy {amount} {type} due to non-positive amount"); + return false; + } + if (character.IsRemoved) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(character) + + $" failed to buy {amount} {type} because character is removed from the game"); + return false; + } Market? market = (Market?)gameMap.OneForInteract(character.Position, GameObjType.MARKET); - if (market == null) return false; - if (!GameData.ApproachToInteract(character.Position, market.Position)) return false; - - if (!game.teams.TryGetValue(teamId, out var teamState)) return false; + if (market == null) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(character) + + $" failed to buy {amount} {type} because no market is in interaction range"); + return false; + } + if (!GameData.ApproachToInteract(character.Position, market.Position)) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(character) + + $" failed to buy {amount} {type} because character is not close enough to the market"); + return false; + } + if (!game.teams.TryGetValue(teamId, out var teamState)) + { + LogicLogging.logger.LogError( + LoggingFunctional.AutoLogInfo(character) + + $" failed to buy {amount} {type} because team with ID {teamId} does not exist"); + return false; + } long totalCost = (long)market.GetPrice(type) * amount; while (true) { long curScore = teamState.Score.Get(); - if (curScore < totalCost) return false; + if (curScore < totalCost) + { + LogicLogging.logger.LogDebug( + LoggingFunctional.AutoLogInfo(character) + + $" failed to buy {amount} {type} because team score {curScore} is less than total cost {totalCost}"); + return false; + } if (teamState.Score.CompareExROri(curScore - totalCost, curScore) == curScore) break; } if (!character.GoodsLoad.Add(type, amount)) { teamState.Score.AddRNow(totalCost); + LogicLogging.logger.LogError( + LoggingFunctional.AutoLogInfo(character) + + $" failed to buy {amount} {type} due to an unexpected error when updating goods load"); return false; } @@ -84,14 +163,26 @@ public bool Buy(Character character, GoodsType type, int amount) public bool Sell(long teamId, long playerId, GoodsType type, int amount) { var character = gameMap.FindCharacterInPlayerID(teamId, playerId); - if (character == null) return false; + if (character == null) + { + LogicLogging.logger.LogError( + LoggingFunctional.CharacterLogInfo(teamId, playerId) + + $" failed to sell {amount} {type} due to null character reference"); + return false; + } return Sell(character, type, amount); } public bool Buy(long teamId, long playerId, GoodsType type, int amount) { var character = gameMap.FindCharacterInPlayerID(teamId, playerId); - if (character == null) return false; + if (character == null) + { + LogicLogging.logger.LogError( + LoggingFunctional.CharacterLogInfo(teamId, playerId) + + $" failed to buy {amount} {type} due to null character reference"); + return false; + } return Buy(character, type, amount); } } diff --git a/logic/Gaming/Uplevel.cs b/logic/Gaming/Uplevel.cs index b0d9074d..42a620a1 100644 --- a/logic/Gaming/Uplevel.cs +++ b/logic/Gaming/Uplevel.cs @@ -17,8 +17,11 @@ public UplevelManager(Game game) public bool UplevelTech(long teamId, TechType tech) { - if (!game.teams.TryGetValue(teamId, out var teamState)) return false; - + if (!game.teams.TryGetValue(teamId, out var teamState)) + { + LogicLogging.logger.LogError($"Failed to uplevel tech for team {teamId} because team not found"); + return false; + } string key; int cost; switch (tech) @@ -48,15 +51,25 @@ public bool UplevelTech(long teamId, TechType tech) } int curLevel = teamState.GetTech(key); - if (curLevel >= GameData.TechMaxLevel) return false; - + if (curLevel >= GameData.TechMaxLevel) + { + LogicLogging.logger.LogDebug($"Failed to uplevel tech {key} for team {teamId} because current level {curLevel} is already at or above max level"); + return false; + } var factory = game.GetTeamFactory(teamId); - if (factory == null) return false; - + if (factory == null) + { + LogicLogging.logger.LogError($"Failed to uplevel tech {key} for team {teamId} because team factory not found"); + return false; + } while (true) { long cur = factory.ComputingPower.Get(); - if (cur < cost) return false; + if (cur < cost) + { + LogicLogging.logger.LogDebug($"Failed to uplevel tech {key} for team {teamId} because current computing power {cur} is less than cost {cost}"); + return false; + } if (factory.ComputingPower.CompareExROri(cur - cost, cur) == cur) break; } @@ -64,6 +77,7 @@ public bool UplevelTech(long teamId, TechType tech) if (!setOk) { factory.AddComputingPower(cost); + LogicLogging.logger.LogError($"Failed to uplevel tech {key} for team {teamId} because failed to update tech level in team state"); return false; } diff --git a/playback/playback/obj/Debug/net8.0/playback.AssemblyInfo.cs b/playback/playback/obj/Debug/net8.0/playback.AssemblyInfo.cs index c790054d..bcf7c158 100644 --- a/playback/playback/obj/Debug/net8.0/playback.AssemblyInfo.cs +++ b/playback/playback/obj/Debug/net8.0/playback.AssemblyInfo.cs @@ -14,7 +14,7 @@ [assembly: System.Reflection.AssemblyCompanyAttribute("playback")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+4f4ca52b3761c822f00aae1a88dcc95cd050a660")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+766320efb019d4e884b8edfa18de33081a87502a")] [assembly: System.Reflection.AssemblyProductAttribute("playback")] [assembly: System.Reflection.AssemblyTitleAttribute("playback")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/playback/playback/obj/Debug/net8.0/playback.AssemblyInfoInputs.cache b/playback/playback/obj/Debug/net8.0/playback.AssemblyInfoInputs.cache index 43eca042..7f87b5f1 100644 --- a/playback/playback/obj/Debug/net8.0/playback.AssemblyInfoInputs.cache +++ b/playback/playback/obj/Debug/net8.0/playback.AssemblyInfoInputs.cache @@ -1 +1 @@ -185f31d9018964bf334d9ffb6f1cc7c5f527a42942f58ec221321bf021f24381 +e1fa7d9091f9cd2e23634d73b899e6163c7c836ed7e8eba89c84f879af2e22c0 diff --git a/playback/playback/obj/Debug/net8.0/playback.GeneratedMSBuildEditorConfig.editorconfig b/playback/playback/obj/Debug/net8.0/playback.GeneratedMSBuildEditorConfig.editorconfig index 55885a12..069e3e88 100644 --- a/playback/playback/obj/Debug/net8.0/playback.GeneratedMSBuildEditorConfig.editorconfig +++ b/playback/playback/obj/Debug/net8.0/playback.GeneratedMSBuildEditorConfig.editorconfig @@ -1,5 +1,7 @@ is_global = true build_property.TargetFramework = net8.0 +build_property.TargetFrameworkIdentifier = .NETCoreApp +build_property.TargetFrameworkVersion = v8.0 build_property.TargetPlatformMinVersion = build_property.UsingMicrosoftNETSdkWeb = build_property.ProjectTypeGuids = @@ -8,7 +10,7 @@ build_property.PlatformNeutralAssembly = build_property.EnforceExtendedAnalyzerRules = build_property._SupportedPlatformList = Linux,macOS,Windows build_property.RootNamespace = playback -build_property.ProjectDir = C:\Users\lenovo\OneDrive\桌面\THUthu\THUAI9\playback\playback\ +build_property.ProjectDir = C:\Users\贾兴道\Documents\GitHub\THUAI9\playback\playback\ build_property.EnableComHosting = build_property.EnableGeneratedComInterfaceComImportInterop = build_property.EffectiveAnalysisLevelStyle = 8.0 diff --git a/playback/playback/obj/Debug/net8.0/playback.GlobalUsings.g.cs b/playback/playback/obj/Debug/net8.0/playback.GlobalUsings.g.cs index 8578f3d0..d12bcbc7 100644 --- a/playback/playback/obj/Debug/net8.0/playback.GlobalUsings.g.cs +++ b/playback/playback/obj/Debug/net8.0/playback.GlobalUsings.g.cs @@ -1,8 +1,8 @@ // -global using global::System; -global using global::System.Collections.Generic; -global using global::System.IO; -global using global::System.Linq; -global using global::System.Net.Http; -global using global::System.Threading; -global using global::System.Threading.Tasks; +global using System; +global using System.Collections.Generic; +global using System.IO; +global using System.Linq; +global using System.Net.Http; +global using System.Threading; +global using System.Threading.Tasks; diff --git a/playback/playback/obj/Release/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/playback/playback/obj/Release/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 00000000..2217181c --- /dev/null +++ b/playback/playback/obj/Release/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/playback/playback/obj/Release/net8.0/playback.AssemblyInfo.cs b/playback/playback/obj/Release/net8.0/playback.AssemblyInfo.cs new file mode 100644 index 00000000..077800a1 --- /dev/null +++ b/playback/playback/obj/Release/net8.0/playback.AssemblyInfo.cs @@ -0,0 +1,23 @@ +//------------------------------------------------------------------------------ +// +// 此代码由工具生成。 +// 运行时版本:4.0.30319.42000 +// +// 对此文件的更改可能会导致不正确的行为,并且如果 +// 重新生成代码,这些更改将会丢失。 +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("playback")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+766320efb019d4e884b8edfa18de33081a87502a")] +[assembly: System.Reflection.AssemblyProductAttribute("playback")] +[assembly: System.Reflection.AssemblyTitleAttribute("playback")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// 由 MSBuild WriteCodeFragment 类生成。 + diff --git a/playback/playback/obj/Release/net8.0/playback.AssemblyInfoInputs.cache b/playback/playback/obj/Release/net8.0/playback.AssemblyInfoInputs.cache new file mode 100644 index 00000000..10fa6b9a --- /dev/null +++ b/playback/playback/obj/Release/net8.0/playback.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +37272408a698412826afb305df5523b72b3fe7e98098a57afabf67749878a616 diff --git a/playback/playback/obj/Release/net8.0/playback.GeneratedMSBuildEditorConfig.editorconfig b/playback/playback/obj/Release/net8.0/playback.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 00000000..069e3e88 --- /dev/null +++ b/playback/playback/obj/Release/net8.0/playback.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,17 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetFrameworkIdentifier = .NETCoreApp +build_property.TargetFrameworkVersion = v8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = playback +build_property.ProjectDir = C:\Users\贾兴道\Documents\GitHub\THUAI9\playback\playback\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/playback/playback/obj/Release/net8.0/playback.GlobalUsings.g.cs b/playback/playback/obj/Release/net8.0/playback.GlobalUsings.g.cs new file mode 100644 index 00000000..d12bcbc7 --- /dev/null +++ b/playback/playback/obj/Release/net8.0/playback.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using System; +global using System.Collections.Generic; +global using System.IO; +global using System.Linq; +global using System.Net.Http; +global using System.Threading; +global using System.Threading.Tasks;