开源的仿红色警戒OpenRA经典RPG游戏, 源码解读world.cs

microPython Python最小内核源码解析
NI-motion运动控制c语言示例代码解析
python编程示例系列 python编程示例系列二
python的Web神器Streamlit
如何应聘高薪职位

代码注释与解读

在这里插入图片描述

这段代码是OpenRA游戏引擎的核心World类的实现,它负责管理游戏世界的所有方面,包括角色(Actors)、效果(Effects)、地图、玩家等。以下是带有详细中文注释的代码解读:

// 版权信息区域
#region Copyright & License Information
/*
 * Copyright (c) The OpenRA Developers and Contributors
 * This file is part of OpenRA, which is free software. It is made
 * available to you under the terms of the GNU General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version. For more
 * information, see COPYING.
 */
#endregion

// 导入必要的命名空间
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.Effects;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Network;
using OpenRA.Orders;
using OpenRA.Primitives;
using OpenRA.Support;
using OpenRA.Traits;

namespace OpenRA
{
    // 定义世界类型枚举:常规游戏世界、展示地图和编辑器
    public enum WorldType { Regular, Shellmap, Editor }

    // World类是游戏的核心类,管理所有游戏实体和逻辑
    public sealed class World : IDisposable
    {
        // 特性字典,用于快速查找拥有特定特性的Actor
        internal readonly TraitDictionary TraitDict = new();
        // 存储所有Actor的字典,以ActorID为键
        readonly SortedDictionary<uint, Actor> actors = new();
        // 存储所有效果的列表
        readonly List<IEffect> effects = new();
        // 存储未分区的效果(不参与空间分区系统)
        readonly List<IEffect> unpartitionedEffects = new();
        // 存储需要同步的效果
        readonly List<ISync> syncedEffects = new();
        // 游戏设置
        readonly GameSettings gameSettings;
        // 模组数据
        readonly ModData modData;

        // 帧结束时执行的动作队列
        readonly Queue<Action<World>> frameEndActions = new();

        // 游戏速度配置
        public readonly GameSpeed GameSpeed;

        // 游戏时间步长
        public readonly int Timestep;

        // 回放时间步长,用于回放模式
        public int ReplayTimestep;

        // 订单管理器,负责处理玩家命令
        internal readonly OrderManager OrderManager;
        // 大厅信息快捷访问
        public Session LobbyInfo => OrderManager.LobbyInfo;

        // 共享随机数生成器(用于所有客户端保持同步)
        public readonly MersenneTwister SharedRandom;
        // 本地随机数生成器(用于不需要同步的本地效果)
        public readonly MersenneTwister LocalRandom;
        // 所有玩家的位掩码
        public LongBitSet<PlayerBitMask> AllPlayersMask = default;
        // 无玩家的位掩码
        public readonly LongBitSet<PlayerBitMask> NoPlayersMask = default;

        // 游戏中的玩家数组
        public Player[] Players = Array.Empty<Player>();

        // 渲染玩家改变事件
        public event Action<Player> RenderPlayerChanged;

        // 设置玩家数组和本地玩家
        public void SetPlayers(IEnumerable<Player> players, Player localPlayer)
        {
            // 一旦设置,玩家数组不可更改
            if (Players.Length > 0)
                throw new InvalidOperationException("Players are fixed once they have been set.");
            Players = players.ToArray();
            SetLocalPlayer(localPlayer);
        }

        // 本地玩家(当前控制的玩家)
        public Player LocalPlayer { get; private set; }

        // 游戏结束事件
        public event Action GameOver = () => { };

        /// <summary>表示游戏已结束</summary>
        /// <remarks>只应在EndGame方法中设置</remarks>
        public bool IsGameOver { get; private set; }
        
        // 结束游戏的方法
        public void EndGame()
        {
            if (!IsGameOver)
            {
                // 暂停游戏
                SetPauseState(true);
                IsGameOver = true;

                // 通知所有关心游戏结束的特性
                foreach (var t in WorldActor.TraitsImplementing<IGameOver>())
                    t.GameOver(this);

                // 记录最终游戏刻度
                gameInfo.FinalGameTick = WorldTick;
                // 触发游戏结束事件
                GameOver();
            }
        }

        // 渲染视角的玩家
        Player renderPlayer;
        public Player RenderPlayer
        {
            get => renderPlayer;

            set
            {
                // 仅当本地玩家为null或允许切换渲染视角时才能更改
                if (LocalPlayer == null || LocalPlayer.UnlockedRenderPlayer)
                {
                    renderPlayer = value;
                    // 触发渲染玩家变更事件
                    RenderPlayerChanged?.Invoke(value);
                }
            }
        }

        // 检查某个Actor是否被战争迷雾遮挡
        public bool FogObscures(Actor a) { return RenderPlayer != null && !a.CanBeViewedByPlayer(RenderPlayer); }
        // 检查某个单元格是否被战争迷雾遮挡
        public bool FogObscures(CPos p) { return RenderPlayer != null && !RenderPlayer.Shroud.IsVisible(p); }
        // 检查某个世界位置是否被战争迷雾遮挡
        public bool FogObscures(WPos pos) { return RenderPlayer != null && !RenderPlayer.Shroud.IsVisible(pos); }
        // 检查某个单元格是否被阴影遮挡
        public bool ShroudObscures(CPos p) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(p); }
        // 检查某个地图位置是否被阴影遮挡
        public bool ShroudObscures(MPos uv) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(uv); }
        // 检查某个世界位置是否被阴影遮挡
        public bool ShroudObscures(WPos pos) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(pos); }
        // 检查某个预测位置是否被阴影遮挡
        public bool ShroudObscures(PPos uv) { return RenderPlayer != null && !RenderPlayer.Shroud.IsExplored(uv); }

        // 是否处于回放模式
        public bool IsReplay => OrderManager.Connection is ReplayConnection;

        // 是否正在加载保存的游戏
        public bool IsLoadingGameSave => OrderManager.NetFrameNumber <= OrderManager.GameSaveLastFrame;

        // 游戏加载进度百分比
        public int GameSaveLoadingPercentage => OrderManager.NetFrameNumber * 100 / OrderManager.GameSaveLastFrame;

        // 设置本地玩家
        void SetLocalPlayer(Player localPlayer)
        {
            if (localPlayer == null)
                return;

            // 确保本地玩家是游戏中的玩家
            if (!Players.Contains(localPlayer))
                throw new ArgumentException("The local player must be one of the players in the world.", nameof(localPlayer));

            // 回放模式下不设置本地玩家
            if (IsReplay)
                return;

            LocalPlayer = localPlayer;

            // 直接设置渲染玩家为本地玩家
            renderPlayer = LocalPlayer;
        }

        // 世界Actor,代表整个游戏世界的特殊Actor
        public readonly Actor WorldActor;

        // 游戏地图
        public readonly Map Map;

        // Actor地图,用于空间查询
        public readonly IActorMap ActorMap;
        // 屏幕地图,用于优化渲染
        public readonly ScreenMap ScreenMap;
        // 世界类型(常规/展示/编辑器)
        public readonly WorldType Type;

        // 订单验证器数组
        public readonly IValidateOrder[] OrderValidators;
        // 玩家断开连接通知数组
        readonly INotifyPlayerDisconnected[] notifyDisconnected;

        // 游戏信息
        readonly GameInformation gameInfo;

        // 向订单管理器发出订单
        public void IssueOrder(Order o) { OrderManager.IssueOrder(o); }

        // 默认订单生成器类型
        readonly Type defaultOrderGeneratorType;

        // 当前订单生成器
        IOrderGenerator orderGenerator;
        public IOrderGenerator OrderGenerator
        {
            get => orderGenerator;

            set
            {
                // 确保在非同步代码中更改订单生成器
                Sync.AssertUnsynced("The current order generator may not be changed from synced code");
                // 停用旧订单生成器
                orderGenerator?.Deactivate();

                orderGenerator = value;
            }
        }

        // 选择系统
        public readonly ISelection Selection;
        // 控制组系统
        public readonly IControlGroups ControlGroups;

        // 取消当前输入模式,恢复默认订单生成器
        public void CancelInputMode() { OrderGenerator = (IOrderGenerator)modData.ObjectCreator.CreateBasic(defaultOrderGeneratorType); }

        // 切换特定类型的输入模式
        public bool ToggleInputMode<T>() where T : IOrderGenerator, new()
        {
            if (OrderGenerator is T)
            {
                // 如果当前已是该模式,则取消
                CancelInputMode();
                return false;
            }
            else
            {
                // 否则切换到该模式
                OrderGenerator = new T();
                return true;
            }
        }

        // 规则是否包含临时阻挡物
        public bool RulesContainTemporaryBlocker { get; }

        // 标记是否刚从游戏存档加载完成
        bool wasLoadingGameSave;

        // World类构造函数
        internal World(Map map, ModData modData, OrderManager orderManager, WorldType type)
        {
            this.modData = modData;
            Type = type;
            OrderManager = orderManager;
            Map = map;

            // 确保定义了默认订单生成器
            if (string.IsNullOrEmpty(modData.Manifest.DefaultOrderGenerator))
                throw new InvalidDataException("mod.yaml must define a DefaultOrderGenerator");

            // 查找默认订单生成器类型
            defaultOrderGeneratorType = modData.ObjectCreator.FindType(modData.Manifest.DefaultOrderGenerator);
            if (defaultOrderGeneratorType == null)
                throw new InvalidDataException($"{modData.Manifest.DefaultOrderGenerator} is not a valid DefaultOrderGenerator");

            // 创建默认订单生成器
            orderGenerator = (IOrderGenerator)modData.ObjectCreator.CreateBasic(defaultOrderGeneratorType);

            // 获取游戏速度设置
            var gameSpeeds = modData.Manifest.Get<GameSpeeds>();
            var gameSpeedName = orderManager.LobbyInfo.GlobalSettings.OptionOrDefault("gamespeed", gameSpeeds.DefaultSpeed);
            GameSpeed = gameSpeeds.Speeds[gameSpeedName];
            Timestep = ReplayTimestep = GameSpeed.Timestep;

            // 初始化随机数生成器
            SharedRandom = new MersenneTwister(orderManager.LobbyInfo.GlobalSettings.RandomSeed);
            LocalRandom = new MersenneTwister();

            // 创建世界Actor
            var worldActorType = type == WorldType.Editor ? SystemActors.EditorWorld : SystemActors.World;
            WorldActor = CreateActor(worldActorType.ToString(), new TypeDictionary());
            // 获取关键系统组件
            ActorMap = WorldActor.Trait<IActorMap>();
            ScreenMap = WorldActor.Trait<ScreenMap>();
            Selection = WorldActor.Trait<ISelection>();
            ControlGroups = WorldActor.Trait<IControlGroups>();
            OrderValidators = WorldActor.TraitsImplementing<IValidateOrder>().ToArray();
            notifyDisconnected = WorldActor.TraitsImplementing<INotifyPlayerDisconnected>().ToArray();

            // 重置玩家位掩码
            LongBitSet<PlayerBitMask>.Reset();

            // 创建隔离的随机数生成器用于玩家创建
            var playerRandom = new MersenneTwister(orderManager.LobbyInfo.GlobalSettings.RandomSeed);
            foreach (var cmp in WorldActor.TraitsImplementing<ICreatePlayers>())
                cmp.CreatePlayers(this, playerRandom);

            // 设置音效音量
            Game.Sound.SoundVolumeModifier = 1.0f;

            // 初始化游戏信息
            gameInfo = new GameInformation
            {
                Mod = Game.ModData.Manifest.Id,
                Version = Game.ModData.Manifest.Metadata.Version,

                MapUid = Map.Uid,
                MapTitle = Map.Title
            };

            // 检查规则是否包含临时阻挡物
            RulesContainTemporaryBlocker = Map.Rules.Actors.Any(a => a.Value.HasTraitInfo<ITemporaryBlockerInfo>());
            gameSettings = Game.Settings.Game;
        }

        // 将Actor添加到地图系统中
        public void AddToMaps(Actor self, IOccupySpace ios)
        {
            ActorMap.AddInfluence(self, ios);
            ActorMap.AddPosition(self, ios);
            ScreenMap.AddOrUpdate(self);
        }

        // 更新Actor在地图系统中的位置
        public void UpdateMaps(Actor self, IOccupySpace ios)
        {
            if (!self.IsInWorld)
                return;

            ScreenMap.AddOrUpdate(self);
            ActorMap.UpdatePosition(self, ios);
        }

        // 从地图系统中移除Actor
        public void RemoveFromMaps(Actor self, IOccupySpace ios)
        {
            ActorMap.RemoveInfluence(self, ios);
            ActorMap.RemovePosition(self, ios);
            ScreenMap.Remove(self);
        }

        // 世界加载完成后的初始化
        public void LoadComplete(WorldRenderer wr)
        {
            // 游戏存档加载处理
            if (IsLoadingGameSave)
            {
                wasLoadingGameSave = true;
                Game.Sound.DisableAllSounds = true;
                foreach (var nsr in WorldActor.TraitsImplementing<INotifyGameLoading>())
                    nsr.GameLoading(this);
            }

            // 初始化屏幕地图(最先初始化)
            using (new PerfTimer("ScreenMap.WorldLoaded"))
                ScreenMap.WorldLoaded(this, wr);

            // 初始化其他实现IWorldLoaded接口的特性
            foreach (var iwl in WorldActor.TraitsImplementing<IWorldLoaded>())
            {
                // 跳过已初始化的屏幕地图
                if (iwl == ScreenMap)
                    continue;

                using (new PerfTimer(iwl.GetType().Name + ".WorldLoaded"))
                    iwl.WorldLoaded(this, wr);
            }

            // 初始化玩家Actor的IWorldLoaded特性
            foreach (var p in Players)
                foreach (var iwl in p.PlayerActor.TraitsImplementing<IWorldLoaded>())
                    using (new PerfTimer(iwl.GetType().Name + ".WorldLoaded"))
                        iwl.WorldLoaded(this, wr);

            // 添加玩家信息到游戏信息中
            foreach (var player in Players)
                gameInfo.AddPlayer(player, OrderManager.LobbyInfo);

            // 记录禁用的出生点
            gameInfo.DisabledSpawnPoints = OrderManager.LobbyInfo.DisabledSpawnPoints;

            // 记录游戏开始时间
            gameInfo.StartTimeUtc = DateTime.UtcNow;

            // 设置回放元数据
            if (OrderManager.Connection is NetworkConnection nc && nc.Recorder != null)
                nc.Recorder.Metadata = new ReplayMetadata(gameInfo);
        }

        // 世界加载后的第二阶段初始化
        public void PostLoadComplete(WorldRenderer wr)
        {
            // 初始化IPostWorldLoaded特性
            foreach (var iwl in WorldActor.TraitsImplementing<IPostWorldLoaded>())
                using (new PerfTimer(iwl.GetType().Name + ".PostWorldLoaded"))
                    iwl.PostWorldLoaded(this, wr);

            // 初始化玩家Actor的IPostWorldLoaded特性
            foreach (var p in Players)
                foreach (var iwl in p.PlayerActor.TraitsImplementing<IPostWorldLoaded>())
                    using (new PerfTimer(iwl.GetType().Name + ".PostWorldLoaded"))
                        iwl.PostWorldLoaded(this, wr);
        }

        // 设置世界所有者
        public void SetWorldOwner(Player p)
        {
            WorldActor.Owner = p;
        }

        // 创建Actor的简化方法
        public Actor CreateActor(string name, TypeDictionary initDict)
        {
            return CreateActor(true, name, initDict);
        }

        // 通过ActorReference创建Actor
        public Actor CreateActor(bool addToWorld, ActorReference reference)
        {
            return CreateActor(addToWorld, reference.Type, reference.InitDict);
        }

        // 创建Actor的完整方法
        public Actor CreateActor(bool addToWorld, string name, TypeDictionary initDict)
        {
            var a = new Actor(this, name, initDict);
            a.Initialize(addToWorld);
            return a;
        }

        // 将Actor添加到世界
        public void Add(Actor a)
        {
            a.IsInWorld = true;
            actors.Add(a.ActorID, a);
            ActorAdded(a);

            // 通知Actor已添加到世界
            foreach (var t in a.TraitsImplementing<INotifyAddedToWorld>())
                t.AddedToWorld(a);
        }

        // 从世界中移除Actor
        public void Remove(Actor a)
        {
            a.IsInWorld = false;
            actors.Remove(a.ActorID);
            ActorRemoved(a);

            // 通知Actor已从世界移除
            foreach (var t in a.TraitsImplementing<INotifyRemovedFromWorld>())
                t.RemovedFromWorld(a);
        }

        // 添加效果到世界
        public void Add(IEffect e)
        {
            effects.Add(e);

            // 如果效果不参与空间分区,添加到未分区效果列表
            if (e is not ISpatiallyPartitionable)
                unpartitionedEffects.Add(e);

            // 如果效果需要同步,添加到同步效果列表
            if (e is ISync se)
                syncedEffects.Add(se);
        }

        // 从世界移除效果
        public void Remove(IEffect e)
        {
            effects.Remove(e);

            // 如果效果不参与空间分区,从未分区效果列表移除
            if (e is not ISpatiallyPartitionable)
                unpartitionedEffects.Remove(e);

            // 如果效果需要同步,从同步效果列表移除
            if (e is ISync se)
                syncedEffects.Remove(se);
        }

        // 根据条件移除所有符合的效果
        public void RemoveAll(Predicate<IEffect> predicate)
        {
            effects.RemoveAll(predicate);
            unpartitionedEffects.RemoveAll(e => predicate(e));
            syncedEffects.RemoveAll(e => predicate((IEffect)e));
        }

        // 添加帧结束时执行的动作
        public void AddFrameEndTask(Action<World> a) { frameEndActions.Enqueue(a); }

        // Actor添加和移除事件
        public event Action<Actor> ActorAdded = _ => { };
        public event Action<Actor> ActorRemoved = _ => { };

        // 世界是否暂停
        public bool Paused { get; internal set; }
        // 预测的暂停状态(用于客户端预测)
        public bool PredictedPaused { get; internal set; }

        // 当前世界刻度(游戏内时间)
        public int WorldTick { get; private set; }

        // 游戏存档特性数据
        readonly Dictionary<int, MiniYaml> gameSaveTraitData = new();
        // 添加游戏存档特性数据
        internal void AddGameSaveTraitData(int traitIndex, MiniYaml yaml)
        {
            gameSaveTraitData[traitIndex] = yaml;
        }

        // 设置游戏暂停状态
        public void SetPauseState(bool paused)
        {
            if (IsGameOver)
                return;

            // 发送暂停游戏订单
            IssueOrder(Order.FromTargetString("PauseGame", paused ? "Pause" : "UnPause", false));
            PredictedPaused = paused;
        }

        // 设置本地暂停状态
        public void SetLocalPauseState(bool paused)
        {
            Paused = PredictedPaused = paused;
        }

        // 世界逻辑更新(每帧调用)
        public void Tick()
        {
            // 处理游戏存档加载完成后的逻辑
            if (wasLoadingGameSave && !IsLoadingGameSave)
            {
                // 解析特性数据
                foreach (var kv in gameSaveTraitData)
                {
                    var tp = TraitDict.ActorsWithTrait<IGameSaveTraitData>()
                        .Skip(kv.Key)
                        .FirstOrDefault();

                    if (tp.Actor == null)
                        break;

                    tp.Trait.ResolveTraitData(tp.Actor, kv.Value);
                }

                // 清空特性数据
                gameSaveTraitData.Clear();

                // 恢复音效
                Game.Sound.DisableAllSounds = false;
                // 通知游戏加载完成
                foreach (var nsr in WorldActor.TraitsImplementing<INotifyGameLoaded>())
                    nsr.GameLoaded(this);

                wasLoadingGameSave = false;
            }

            // 如果世界未暂停,或是展示地图但不暂停展示地图,或是首帧,则更新世界
            if (!Paused && (Type != WorldType.Shellmap || !gameSettings.PauseShellmap || WorldTick == 0))
            {
                // 增加世界刻度
                WorldTick++;

                // 更新所有Actor
                using (new PerfSample("tick_actors"))
                    foreach (var a in actors.Values)
                        a.Tick();

                // 调用所有实现ITick接口的特性
                ApplyToActorsWithTraitTimed<ITick>((actor, trait) => trait.Tick(actor), "Trait");

                // 更新所有效果
                effects.DoTimed(e => e.Tick(this), "Effect");
            }

            // 执行帧结束动作
            while (frameEndActions.Count != 0)
                frameEndActions.Dequeue()(this);
        }

        // 渲染更新(每帧调用,不受暂停状态影响)
        public void TickRender(WorldRenderer wr)
        {
            // 调用所有实现ITickRender接口的特性
            ApplyToActorsWithTraitTimed<ITickRender>((actor, trait) => trait.TickRender(wr, actor), "Render");
            // 更新屏幕地图
            ScreenMap.TickRender();
        }

        // 所有Actor的枚举器
        public IEnumerable<Actor> Actors => actors.Values;
        // 所有效果的枚举器
        public IEnumerable<IEffect> Effects => effects;
        // 所有未分区效果的枚举器
        public IEnumerable<IEffect> UnpartitionedEffects => unpartitionedEffects;
        // 所有同步效果的枚举器
        public IEnumerable<ISync> SyncedEffects => syncedEffects;

        // 通过ID获取Actor
        public Actor GetActorById(uint actorId)
        {
            if (actors.TryGetValue(actorId, out var a))
                return a;
            return null;
        }

        // Actor ID生成器
        uint nextAID = 0;
        internal uint NextAID()
        {
            return nextAID++;
        }

        // 计算同步哈希值(用于检测不同客户端之间的游戏状态是否同步)
        public int SyncHash()
        {
            // using (new PerfSample("synchash"))
            {
                var n = 0;
                var ret = 0;

                // 对所有Actor进行哈希
                foreach (var a in Actors)
                    ret += n++ * (int)(1 + a.ActorID) * Sync.HashActor(a);

                // 对标记为ISync的字段进行哈希
                foreach (var actor in ActorsHavingTrait<ISync>())
                    foreach (var syncHash in actor.SyncHashes)
                        ret += n++ * (int)(1 + actor.ActorID) * syncHash.Hash();

                // 对游戏状态相关效果(如投射物)进行哈希
                foreach (var sync in SyncedEffects)
                    ret += n++ * Sync.Hash(sync);

                // 对共享随机数生成器进行哈希
                ret += SharedRandom.Last;

                // 对玩家渲染状态进行哈希
                foreach (var p in Players)
                    if (p.UnlockedRenderPlayer)
                        ret += Sync.HashPlayer(p);

                return ret;
            }
        }

        // 获取所有具有特定特性的Actor和特性对
        public IEnumerable<TraitPair<T>> ActorsWithTrait<T>()
        {
            return TraitDict.ActorsWithTrait<T>();
        }

        // 对所有具有特定特性的Actor应用操作,并计时
        public void ApplyToActorsWithTraitTimed<T>(Action<Actor, T> action, string text)
        {
            TraitDict.ApplyToActorsWithTraitTimed(action, text);
        }

        // 对所有具有特定特性的Actor应用操作
        public void ApplyToActorsWithTrait<T>(Action<Actor, T> action)
        {
            TraitDict.ApplyToActorsWithTrait(action);
        }

        // 获取所有具有特定特性的Actor
        public IEnumerable<Actor> ActorsHavingTrait<T>()
        {
            return TraitDict.ActorsHavingTrait<T>();
        }

        // 获取所有具有特定特性且满足条件的Actor
        public IEnumerable<Actor> ActorsHavingTrait<T>(Func<T, bool> predicate)
        {
            return TraitDict.ActorsHavingTrait(predicate);
        }

        // 玩家胜利状态改变时更新游戏信息
        public void OnPlayerWinStateChanged(Player player)
        {
            var pi = gameInfo.GetPlayer(player);
            if (pi != null)
            {
                pi.Outcome = player.WinState;
                pi.OutcomeTimestampUtc = DateTime.UtcNow;
            }
        }

        // 客户端断开连接时处理
        internal void OnClientDisconnected(int clientId)
        {
            // 查找属于该客户端的可玩玩家
            foreach (var player in Players.Where(p => p.ClientIndex == clientId && p.PlayerReference.Playable))
            {
                // 通知玩家断开连接
                foreach (var np in notifyDisconnected)
                    np.PlayerDisconnected(WorldActor, player);

                // 通知所有其他玩家
                foreach (var p in Players)
                    p.PlayerDisconnected(player);

                // 更新游戏信息中的断开帧
                var pi = gameInfo.GetPlayer(player);
                if (pi != null)
                    pi.DisconnectFrame = OrderManager.NetFrameNumber;
            }
        }

        // 请求游戏存档
        public void RequestGameSave(string filename)
        {
            // 允许特性保存任意数据,这些数据将在存档恢复时通过IGameSaveTraitData.ResolveTraitData传回
            var i = 0;
            foreach (var tp in TraitDict.ActorsWithTrait<IGameSaveTraitData>())
            {
                var data = tp.Trait.IssueTraitData(tp.Actor);
                if (data != null)
                {
                    var yaml = new List<MiniYamlNode>() { new(i.ToStringInvariant(), new MiniYaml("", data)) };
                    IssueOrder(Order.FromTargetString("GameSaveTraitData", yaml.WriteToString(), true));
                }

                i++;
            }

            // 发出创建游戏存档订单
            IssueOrder(Order.FromTargetString("CreateGameSave", filename, true));
        }

        // 标记世界是否正在销毁
        public bool Disposing;

        // 销毁世界及其所有组件
        public void Dispose()
        {
            Disposing = true;

            // 停用订单生成器
            OrderGenerator?.Deactivate();

            // 清空帧结束动作
            frameEndActions.Clear();

            // 停止音频和视频
            Game.Sound.StopAudio();
            Game.Sound.StopVideo();
            if (IsLoadingGameSave)
                Game.Sound.DisableAllSounds = false;

            // 先销毁较新的Actor,最后销毁世界Actor
            foreach (var a in actors.Values.Reverse())
                a.Dispose();

            // Actor销毁操作在帧结束任务中完成
            while (frameEndActions.Count != 0)
                frameEndActions.Dequeue()(this);

            // 展示地图的OrderManager由其世界拥有,需要在这里销毁
            if (Type == WorldType.Shellmap)
                OrderManager.Dispose();

            // 销毁地图
            Map.Dispose();

            // 完成基准测试
            Game.FinishBenchmark();
        }

        // 处理回放不同步情况
        public void OutOfSync()
        {
            // 结束游戏
            EndGame();

            // 在回放不同步事件中,回放不再可用。为了保持体验,永久暂停世界。
            ReplayTimestep = 0;
        }
    }

    // 特性对结构,用于存储Actor和其特性的配对
    public readonly struct TraitPair<T> : IEquatable<TraitPair<T>>
    {
        public readonly Actor Actor;
        public readonly T Trait;

        public TraitPair(Actor actor, T trait) { Actor = actor; Trait = trait; }

        // 重载相等运算符
        public static bool operator ==(TraitPair<T> me, TraitPair<T> other) { return me.Actor == other.Actor && Equals(me.Trait, other.Trait); }
        public static bool operator !=(TraitPair<T> me, TraitPair<T> other) { return !(me == other); }

        // 获取哈希码
        public override int GetHashCode() { return Actor.GetHashCode() ^ Trait.GetHashCode(); }

        // 实现IEquatable接口
        public bool Equals(TraitPair<T> other) { return this == other; }
        public override bool Equals(object obj) { return obj is TraitPair<T> pair && Equals(pair); }

        // 重写ToString方法
        public override string ToString() { return Actor.Info.Name + "->" + Trait.GetType().Name; }
    }
}

逻辑解读

这段代码实现了OpenRA游戏引擎的World类,它是整个游戏的核心类,负责管理游戏世界的所有方面:

  1. 世界管理:管理游戏中的所有实体(Actor)、效果(Effect)、地图和玩家
  2. 游戏循环:实现游戏的主循环,包括逻辑更新(Tick)和渲染更新(TickRender)
  3. Actor生命周期:负责Actor的创建、添加到世界和从世界中移除
  4. 订单处理:处理玩家的命令(Order)
  5. 战争迷雾系统:管理每个玩家的视野
  6. 同步系统:确保多玩家游戏中各客户端的游戏状态保持同步
  7. 游戏状态管理:管理游戏的开始、暂停、结束等状态

核心工作流程:

  1. 初始化世界(构造函数):加载地图、创建世界Actor、初始化各系统组件
  2. 加载完成(LoadComplete):初始化所有Actor和特性
  3. 游戏循环(Tick):更新所有Actor和效果的状态
  4. 渲染循环(TickRender):更新所有渲染相关的组件
  5. 游戏结束(EndGame):处理游戏结束逻辑
  6. 资源清理(Dispose):清理所有资源

流程图

World构造函数
创建WorldActor
初始化关键系统
ActorMap
ScreenMap
Selection
ControlGroups
OrderValidators
创建玩家
LoadComplete
初始化所有Actor和特性
游戏主循环
世界暂停?
更新世界刻度
调用所有特性的Tick方法
更新所有Actor
更新所有效果
执行帧结束动作
TickRender
调用所有特性的TickRender方法
更新ScreenMap
CreateActor
创建Actor实例
初始化Actor
添加到世界?
调用World.Add
将Actor添加到actors字典
触发ActorAdded事件
调用INotifyAddedToWorld
Remove Actor
从actors字典移除
触发ActorRemoved事件
调用INotifyRemovedFromWorld
EndGame
设置暂停状态
设置IsGameOver为true
调用IGameOver特性
触发GameOver事件
SyncHash
对所有Actor计算哈希
对所有ISync字段计算哈希
对所有同步效果计算哈希
返回同步哈希值
Dispose
停用OrderGenerator
停止音频和视频
销毁所有Actor
执行所有帧结束动作
销毁地图

这个流程图展示了World类的主要工作流程,包括初始化、游戏循环、Actor生命周期管理以及游戏结束和资源清理过程。图中体现了代码中的核心逻辑关系和控制流程。

OpenRA 代码中的 C# 特殊语法和技术技巧

在这段 OpenRA 游戏引擎的 World 类实现中,使用了多种 C# 的特殊语法和编程技巧。以下是这些技术的详细解读:

1. 属性表达式体(Expression-bodied members)

public Session LobbyInfo => OrderManager.LobbyInfo;
public bool IsReplay => OrderManager.Connection is ReplayConnection;
public IEnumerable<Actor> Actors => actors.Values;

解读:使用 => 运算符定义属性的简洁语法,适用于只需要一个表达式就能返回值的属性,相当于以下完整语法:

public Session LobbyInfo { get { return OrderManager.LobbyInfo; } }

2. 自动实现的属性(Auto-implemented properties)

public Player LocalPlayer { get; private set; }
public bool IsGameOver { get; private set; }
public bool Paused { get; internal set; }

解读:简化属性声明的语法,编译器会自动生成对应的私有字段。private set 表示只有类内部代码能修改这些属性,而 internal set 表示只有同一程序集内的代码能修改。

3. 属性访问器的不同访问级别

public Player RenderPlayer
{
    get => renderPlayer;
    set
    {
        if (LocalPlayer == null || LocalPlayer.UnlockedRenderPlayer)
        {
            renderPlayer = value;
            RenderPlayerChanged?.Invoke(value);
        }
    }
}

解读:属性的 getter 和 setter 可以有不同的访问修饰符,这里 getter 是公开的,而 setter 有自定义逻辑,只在特定条件下修改 renderPlayer 字段。

4. 空条件运算符(Null-conditional operator - ?)

RenderPlayerChanged?.Invoke(value);

解读?. 操作符仅在左侧对象非空时调用右侧方法,避免了空引用异常。相当于:

if (RenderPlayerChanged != null)
    RenderPlayerChanged.Invoke(value);

5. 泛型(Generics)

readonly SortedDictionary<uint, Actor> actors = new();
public IEnumerable<TraitPair<T>> ActorsWithTrait<T>()
public bool ToggleInputMode<T>() where T : IOrderGenerator, new()

解读:泛型允许定义类型参数化的代码,提高代码复用性。where T : IOrderGenerator, new() 是泛型约束,表示 T 类型必须实现 IOrderGenerator 接口并具有无参构造函数。

6. 目标类型的 new 表达式(Target-typed new expressions)

readonly TraitDictionary TraitDict = new();
readonly SortedDictionary<uint, Actor> actors = new();
readonly List<IEffect> effects = new();

解读:C# 9.0 引入的语法,可以省略 new 后面的类型,编译器会根据左侧变量类型推断右侧应创建的对象类型。

7. 委托和事件(Delegates and events)

public event Action<Player> RenderPlayerChanged;
public event Action<Actor> ActorAdded = _ => { };
public event Action GameOver = () => { };

解读

  • event 关键字定义事件,允许类外部代码注册对特定事件的响应
  • Action<Player> 是委托类型,表示接受一个 Player 参数但不返回值的方法引用
  • _ => { } 是一个匿名函数,使用 lambda 表达式语法,忽略参数 (_) 且不执行任何操作

8. 只读字段(Readonly fields)

readonly TraitDictionary TraitDict = new();
readonly List<IEffect> effects = new();
readonly GameSettings gameSettings;
readonly ModData modData;

解读readonly 关键字表示字段只能在声明时或构造函数中赋值,之后不能修改,提高程序的安全性和可预测性。

9. 隐式类型局部变量(var)

var gameSpeeds = modData.Manifest.Get<GameSpeeds>();
var gameSpeedName = orderManager.LobbyInfo.GlobalSettings.OptionOrDefault("gamespeed", gameSpeeds.DefaultSpeed);
var worldActorType = type == WorldType.Editor ? SystemActors.EditorWorld : SystemActors.World;

解读:使用 var 关键字让编译器自动推断变量类型,简化代码而不失类型安全性。

10. 只读结构体(Readonly structs)

public readonly struct TraitPair<T> : IEquatable<TraitPair<T>>
{
    public readonly Actor Actor;
    public readonly T Trait;
    // ...
}

解读readonly struct 声明一个不可变的值类型,所有字段都是只读的,有助于优化性能(减少防御性复制)并确保不可变性。

11. LINQ 查询(Language Integrated Query)

OrderValidators = WorldActor.TraitsImplementing<IValidateOrder>().ToArray();
notifyDisconnected = WorldActor.TraitsImplementing<INotifyPlayerDisconnected>().ToArray();
RulesContainTemporaryBlocker = Map.Rules.Actors.Any(a => a.Value.HasTraitInfo<ITemporaryBlockerInfo>());
foreach (var player in Players.Where(p => p.ClientIndex == clientId && p.PlayerReference.Playable))

解读:LINQ 提供了声明式查询语法,简化集合操作:

  • ToArray() 将查询结果转换为数组
  • Any() 检查是否存在满足条件的元素
  • Where() 筛选满足条件的元素

12. Lambda 表达式

effects.RemoveAll(predicate);
unpartitionedEffects.RemoveAll(e => predicate(e));
syncedEffects.RemoveAll(e => predicate((IEffect)e));

解读:Lambda 表达式 (e => predicate(e)) 是一种简洁定义匿名函数的方式,常用于传递给接受委托参数的方法。

13. 类型模式匹配(Type pattern matching)

if (e is not ISpatiallyPartitionable)
    unpartitionedEffects.Add(e);

if (e is ISync se)
    syncedEffects.Add(se);

解读

  • is not 模式用于检查对象不是某个类型
  • is ISync se 是类型模式匹配,如果 e 是 ISync 类型,则将其转换并赋值给变量 se

14. using 语句表达式(Using declaration)

using (new PerfTimer("ScreenMap.WorldLoaded"))
    ScreenMap.WorldLoaded(this, wr);

using (new PerfSample("tick_actors"))
    foreach (var a in actors.Values)
        a.Tick();

解读using 语句确保代码块执行完毕后调用对象的 Dispose 方法,通常用于管理需要显式释放的资源,这里用于性能计时。

15. 接口的显式实现(Explicit interface implementation)

public void Dispose()
{
    // 实现 IDisposable 接口的 Dispose 方法
}

解读World 类实现了 IDisposable 接口,提供资源清理方法。

16. 默认参数值(Default parameter values)

public LongBitSet<PlayerBitMask> AllPlayersMask = default;
public readonly LongBitSet<PlayerBitMask> NoPlayersMask = default;

解读default 关键字用于获取类型的默认值,对引用类型是 null,对值类型是 0 或等效值。

17. 泛型约束(Generic constraints)

public bool ToggleInputMode<T>() where T : IOrderGenerator, new()

解读where T : IOrderGenerator, new() 指定了泛型类型 T 必须:

  1. 实现 IOrderGenerator 接口
  2. 有一个公共的无参构造函数(new()

18. 隐式和显式类型转换

ret += n++ * (int)(1 + a.ActorID) * Sync.HashActor(a);

解读:使用 (int) 进行显式类型转换,将其他类型转换为整数类型。

19. 内部类和密封类(Internal and Sealed classes)

public sealed class World : IDisposable

解读

  • sealed 关键字表示该类不能被继承,有助于优化性能和确保设计意图
  • 整个类文件使用了命名空间 OpenRA,限制类型的可见性范围

20. 字符串内插(String interpolation)

throw new InvalidDataException($"{modData.Manifest.DefaultOrderGenerator} is not a valid DefaultOrderGenerator");

解读$"..." 是字符串内插语法,允许在字符串中嵌入表达式,比拼接字符串更简洁易读。

21. 命名参数(Named arguments)

gameInfo = new GameInformation
{
    Mod = Game.ModData.Manifest.Id,
    Version = Game.ModData.Manifest.Metadata.Version,
    MapUid = Map.Uid,
    MapTitle = Map.Title
};

解读:初始化对象时显式指定属性名称,提高代码可读性并允许按任意顺序设置属性。

22. 元组和弃元(Tuples and discards)

ActorAdded = _ => { };

解读:下划线 _ 是弃元,表示不使用的参数,在这里用于简化只需满足委托签名但不使用参数的 lambda 表达式。

这些 C# 的特殊语法和技巧展示了 OpenRA 游戏引擎代码的现代化、简洁性和高效性,充分利用了 C# 语言的强大特性来构建复杂的游戏系统。

OpenAI ChatGPT 可用的第三方插件可能成为威胁行为者寻求未经授权访问敏感数据的新攻击面
C#开发串口通讯软件如何如何捕获和处理串口通讯中的异常?
量化交易系统如何设计系统架构以确保高可用性和高性能?
OpenAI还有什么有趣的功能
python web应用开发神器 入门三
Python的opencv库使用SIFT 进行特征检测
NI-Motion 如何在二维向量空间内进行轮廓加工(contouring)c语言示例代码
Python如何使用pickle库来复制、保存和加载一个空间
python可以执行字符串形式的 Python 代码的库exec
microPython的源码解析之 modmath.c
c#视觉应用开发中如何在C#中进行图像去色散?
车载系统软件工程师如何集成车载系统与云服务和数据分析
车载系统软件工程师如何处理车载系统的兼容性测试和验证
microPython的源码解析之 modbuiltins.c
C#进行串口应用开发如何通过串口下载程序在设备上进行远程调试
量化交易系统中如何处理回测中的数据一致性问题?
智能农业设备软件工程师如何集成和管理农业设备的环境监测系统
python 把字符串当数组来操作就对了
WordStream 选择 Python 作为他们的平台
量化交易系统中+如何连接交易所API进行交易?
Python在科学数据可视化中的应用
Python如何为Journyx Timesheet提供动力。
git如何使用以及和svn的区别
3D人物说话时的嘴部动作与表情与语音如何配合到一起的
NI-Motion如何在运动控制器上设置高速捕获,并通过RTSI线将其路由出去的C语言示例代码
python如何分析 图的最短路径
python读取和编写配置文件库ConfigObj和ConfigParser
python的string 竟然有这么多用法
c#视觉应用开发中如何在C#中实现光流(Optical Flow)算法?
python如何绘制树状图
C#进行串口应用开发如何实现串口热插拔的自动检测
智能农业设备软件工程师如何集成和管理农业物联网(IoT)平台
c#视觉应用开发中如何在C#中进行图像饱和度调整?
openai的plaNet 如何使用,请给出示例代码,并解读
python的Ren’Py 库如何安装使用以及功能和用途
python进行因子分析(Factor Analysis,简称FA)
量化交易系统中+如何构建和管理多策略组合?
C#进行串口应用开发如何实现串口通信的校验与数据校正
c#视觉应用开发中如何在C#中进行图像细节增强?
气象学家如何利用Python
python 只用20行代码完成一个web应用开发
python用于创建和管理 IoT 物联网设备的工作流程库aiobotocore_iotthingsgraph
python如何自动创建python代码
C++加QT中的RS232通信如何实现自动重连和断线重连功能?
NI-Motion 如何使用圆弧插补功能来移动控制器上的轴,C语言示例代码
NI-Motion如何设置一个周期性断点,当运动轴到达预设的目标位置时,会在周期性断点位置暂停,然后继续运动直到再次到达目标位置的C语言代码示例
python可操作wps文档
智能农业设备软件工程师如何实现农业设备的能耗优化
Python如何创造可变形的地形的完整示例.
智能农业设备软件工程师如何处理设备的电源管理和优化
python的Arcade 库如何安装使用以及功能和用途
利用qt及 c++语言如何计算KDJ技术指标,请给出示例代码
C#进行串口应用开发如何修改串口通信缓冲区的大小
c#Entity Framework 复杂查询
智能农业设备软件工程师如何确保设备的高可靠性和可用性
详细解读一下哈夫曼树,并给出搜索示例代码
python如何快速创建交互式应用程序
python的Cirq库如何使用
智能农业设备软件工程师如何实现智能温室环境控制
c#视觉应用开发中如何在C#中实现图像拼接?
详细解读一下B树,及如何进行搜索
几种设计模式在Python开发中的应用
microPython的源码解析之 objstr.c
C#进行串口应用开发如何实现串口通信的线程处理
C#进行串口应用开发如何关闭一个已经打开的串口
量化交易策略 做多做空策略
python有哪些定时触发的框架
Python 的抽象语法树库ast
智能农业设备软件工程师如何集成和管理农业设备的故障日志和报告
c# 如何操作usb设备
c#视觉应用开发中如何在C#中进行图像去残影?
Python的exceptional库
智能农业设备软件工程师如何集成和管理农业设备的网络安全措施
Python的opencv库进行图像分割
量化交易系统中+如何扩展系统以支持更多用户和更大交易量?
microPython的源码解析之 objclosure.c
量化交易系统中+如何处理系统故障和异常情况?
量子计算Simon算法
车载系统软件工程师如何实现车载系统的紧急呼叫服务(eCall)
python的markdown2库的使用
C#进行串口应用开发如何通过串口实现设备固件的远程升级
C#进行串口应用开发如何实现串口通信双机热备份的无缝切换
量化交易系统中+如何处理交易所的延迟和网络延迟?
C#进行串口应用开发如何实现串口的数据透传
车载系统软件工程师如何实现车载系统的防盗和安全系统
量化交易策略 做多做空策略
车载系统软件工程师如何处理车载系统的内存管理和优化
python web应用开发神器 入门十五
python 如何写入文本文件?
Python 如何获取文件路径?
智能农业设备软件工程师如何实现农业设备的人工智能和机器学习应用
QT 的自定义宏 #define QT_ANNOTATE_CLASS(type, …)什么意思
量化交易系统中+如何实现止损和止盈机制?
c++加QT如何操作RS485接口
智能农业设备软件工程师如何集成和管理农业设备的无线通信系统
车载系统软件工程师如何处理车载系统的用户数据和偏好管理
python如何操作excel
python的filelock库是做什么的
c#自定义异常
c#视觉应用开发中如何在C#中使用卷积神经网络(CNN)进行图像分类?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

openwin_top

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值