OpenRA开源红色警戒游戏RPG源码MapDirectoryTracker.cs解读

python编程示例系列
python编程示例系列二
python的Web神器Streamlit
如何应聘高薪职位
C#视觉应用开发问题系列
c#串口应用开发问题系列
microPython Python最小内核源码解析
NI-motion运动控制c语言示例代码解析
OpenRA开源红色警戒游戏RPG源码解读
# MapDirectoryTracker 代码解析

以下是带有详细中文注释的代码:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.FileSystem;

namespace OpenRA
{
            
    // MapDirectoryTracker类:用于跟踪地图目录变化的类,实现IDisposable接口以便正确释放资源
    public sealed class MapDirectoryTracker : IDisposable
    {
            
        // 文件系统监视器,用于监控目录变化
        readonly FileSystemWatcher watcher;
        // 只读包,表示要监控的地图包
        readonly IReadOnlyPackage package;
        // 地图分类信息
        readonly MapClassification classification;

        // 地图操作枚举:添加、删除、更新
        enum MapAction {
             Add, Delete, Update }
        // 地图操作队列:存储路径和对应的操作类型
        readonly Dictionary<string, MapAction> mapActionQueue = new();

        // 脏标记:表示是否有未处理的变更
        bool dirty = false;

        // 构造函数:初始化跟踪器并设置文件系统监视器
        public MapDirectoryTracker(IReadOnlyPackage package, MapClassification classification)
        {
            
            this.package = package;
            this.classification = classification;

            // 创建文件系统监视器,监控指定的包目录
            watcher = new FileSystemWatcher(package.Name);
            // 设置各种文件变化事件的处理方法
            watcher.Changed += (_, e) => AddMapAction(MapAction.Update, e.FullPath); // 文件内容变化
            watcher.Created += (_, e) => AddMapAction(MapAction.Add, e.FullPath);    // 新建文件
            watcher.Deleted += (_, e) => AddMapAction(MapAction.Delete, e.FullPath); // 删除文件
            watcher.Renamed += (_, e) => AddMapAction(MapAction.Add, e.FullPath, e.OldFullPath); // 重命名文件

            // 启用子目录监控
            watcher.IncludeSubdirectories = true;
            // 启用事件触发
            watcher.EnableRaisingEvents = true;
        }

        // 实现IDisposable接口的Dispose方法,释放监视器资源
        public void Dispose()
        {
            
            watcher.Dispose();
        }

        // 添加地图操作到队列中
        void AddMapAction(MapAction mapAction, string fullpath, string oldFullPath = null)
        {
            
            // 使用锁保护队列的并发访问
            lock (mapActionQueue)
            {
            
                // 标记有未处理的变更
                dirty = true;

                // 获取地图根目录路径
                var path = RemoveSubDirs(fullpath);
                // 如果路径就是根目录,直接使用指定的操作类型
                if (fullpath == path)
                    mapActionQueue[path] = mapAction;
                // 如果路径不是根目录,将操作类型设为更新
                else
                    mapActionQueue[path] = MapAction.Update;

                // 处理重命名情况(有旧路径)
                if (oldFullPath != null)
                {
            
                    var oldpath = RemoveSubDirs(oldFullPath);
                    if (oldpath != null)
                        // 如果旧路径是根目录,标记为删除
                        if (oldFullPath == oldpath)
                            mapActionQueue[oldpath] = MapAction.Delete;
                        // 否则标记为更新
                        else
                            mapActionQueue[oldpath] = MapAction.Update;
                }
            }
        }

        // 更新地图缓存
        public void UpdateMaps(MapCache mapcache)
        {
            
            // 使用锁保护队列的并发访问
            lock (mapActionQueue)
            {
            
                // 如果没有变更,直接返回
                if (!dirty)
                    return;

                // 重置脏标记
                dirty = false;
                // 遍历所有待处理的地图操作
                foreach (var mapAction in mapActionQueue)
                {
            
                    // 查找对应路径的可用地图
                    var map = mapcache.FirstOrDefault(x => x.Path == mapAction.Key && x.Status == MapStatus.Available);
                    if (map != null)
                    {
            
                        // 处理已存在的地图
                        if (mapAction.Value == MapAction.Delete)
                        {
            
                            // 删除操作
                            Console.WriteLine(mapAction.Key + " was deleted");
                            map.Invalidate(); // 使地图失效
                        }
                        else
                        {
            
                            // 更新操作
                            Console.WriteLine(mapAction.Key + " was updated");
                            map.Invalidate(); // 先使地图失效
                            // 重新加载地图,保留原有的UID
                            mapcache.LoadMap(mapAction.Key.Replace(package.Name + Path.DirectorySeparatorChar, ""), package, classification, map.Uid);
                        }
                    }
                    else
                    {
            
                        // 处理新地图
                        if (mapAction.Value != MapAction.Delete)
                        {
            
                            // 添加操作
                            Console.WriteLine(mapAction.Key + " was added");
                            // 加载新地图,不指定UID(让系统生成新UID)
                            mapcache.LoadMap(mapAction.Key.Replace(package?.Name + Path.DirectorySeparatorChar, ""), package, classification, null);
                        }
                    }
                }

                // 清空操作队列
                mapActionQueue.Clear();
            }
        }

        // 获取地图根目录路径
        string RemoveSubDirs(string path)
        {
            
            // 移除包名前缀
            var endPath = path.Replace(package.Name + Path.DirectorySeparatorChar, "");

            // 如果路径没有变化,说明不在监控的目录中,返回null
            if (path == endPath)
                return null;

            // 返回包名加上第一级子目录的路径(地图根目录)
            return package.Name + Path.DirectorySeparatorChar + endPath.Split(Path.DirectorySeparatorChar)[0];
        }
    }
}

代码逻辑解读

这段代码实现了一个地图目录跟踪器,用于监控OpenRA游戏中地图目录的变化,并在地图文件发生变化时更新地图缓存。主要逻辑如下:

初始化时,创建一个FileSystemWatcher来监控指定目录中的文件变化。
当文件发生变化(创建、修改、删除、重命名)时,将相应的操作添加到队列中。
当需要更新地图缓存时,处理队列中的所有操作,更新或重新加载地图。
使用锁机制确保线程安全,防止并发访问队列导致的问题。
实现了IDisposable接口,确保资源正确释放。

流程图

特殊语法与技巧解读

sealed 类修饰符

public sealed class MapDirectoryTracker: sealed关键字防止类被继承,提高安全性和性能。

IDisposable接口实现

实现IDisposable接口并在Dispose方法中释放资源,确保资源正确清理。

readonly修饰符

readonly FileSystemWatcher watcher: 使字段只能在构造函数中赋值,增加代码安全性。

Lambda表达式

watcher.Changed += (_, e) => AddMapAction(MapAction.Update, e.FullPath): 使用简洁的Lambda表达式注册事件处理。
使用_表示不关心的参数,是C#中的一种约定。

可选参数

void AddMapAction(MapAction mapAction, string fullpath, string oldFullPath = null): oldFullPath是可选参数,简化了方法调用。

线程同步机制

lock (mapActionQueue): 使用lock语句保护共享资源,确保线程安全。

LINQ查询

mapcache.FirstOrDefault(x => x.Path == mapAction.Key && x.Status == MapStatus.Available): 使用LINQ简化集合查询。

空条件运算符

package?.Name: 如果package为null,整个表达式返回null而不是抛出异常。

字符串操作

path.Replace(package.Name + Path.DirectorySeparatorChar, ""): 字符串替换操作。
endPath.Split(Path.DirectorySeparatorChar)[0]: 字符串分割并获取第一部分。

跨平台路径处理

使用Path.DirectorySeparatorChar而不是硬编码的分隔符,确保代码在不同操作系统上正常工作。

字典作为缓存

使用Dictionary存储待处理的操作,键为路径,值为操作类型,实现高效查找和更新。

脏标记模式

使用dirty标记跟踪是否有未处理的变更,避免不必要的处理。

枚举类型

使用enum MapAction { Add, Delete, Update }定义操作类型,增强代码可读性。

早期返回模式

if (!dirty) return;: 提前检查条件并返回,减少嵌套和提高可读性。

文件系统监控

使用System.IO.FileSystemWatcher监控文件系统变化,是一种高效的文件变化通知机制。

python如何开发一个计算中国象棋下子优势的算法
量化交易系统中+如何进行大规模回测和结果分析?
python的任务调度库 Advanced Python Scheduler (APScheduler)
BNF 语法描述
python 如何统计文本里文字字数?
NI-Motion控制一个两轴舞台进行光栅扫描的C语言代码示例
智能农业设备软件工程师如何实现农业设备的用户体验优化
c#视觉应用开发中如何在C#中处理3D图像数据?
microPython的源码解析之 reader.c
量化交易系统如何获取实时市场数据?
c#视觉应用开发中如何在C#中进行图像几何变换?
车载系统软件工程师如何处理车载系统的故障检测和诊断
如何应聘光模块软件技术经理,年薪范围大约在 190,000.5 至 390,000.0 元人民币
__pragma(warning(push)) 是什么意思
microPython的源码解析之 nlrpowerpc.c
python分布式系统技术集成的应用
Python程序如何进行性能分析
量化交易系统如何处理多市场、多资产的交易需求?
量化交易系统中+如何连接交易所API进行交易?
在搜索引擎如百度上搜索合法软件(如Notepad++和VNote)的用户正成为恶意广告和伪造链接的目标
量化交易系统中+如何进行模型的验证和评估?
车载系统软件工程师如何处理车载系统的内存管理和优化
车载系统软件工程师如何实现车载系统的音频处理和优化
车载系统软件工程师如何实现车载系统的车辆健康监测
c#视觉应用开发中如何在C#中进行图像细节增强?
microPython的源码解析之 vstr.c
python如何绘制股票的K线图
C#进行串口应用开发如何实现串口设备的热插拔自动检测
智能农业设备软件工程师如何集成和管理农业设备的故障日志和报告
量子计算Shor算法
车载系统软件工程师如何实现车载系统的实时交通管理
车载系统软件工程师如何处理车载系统的电池寿命管理
python可以执行字符串形式的 Python 代码的库exec
C#进行串口应用开发如何改变串口的默认端口号
如何使用openai生成图像 请给出示例代码
车载系统软件工程师如何处理车载系统的存储管理和优化
microPython的源码解析之 obj.c
量化交易系统中如何处理大数据中的数据清洗和预处理?
c#视觉应用开发中如何在C#中进行图像去重叠?
量化交易系统中+如何设计和实现量化交易策略?
如何应聘数据标注员 ,年薪10万以上
数字化器Digitizer框架
车载系统软件工程师如何实现车载系统的驾驶习惯学习和优化
量化交易系统中+如何构建和管理多策略组合?
microPython的源码解析之 objattrtuple.c
华为的深度学习框架介绍一下
车载系统软件工程师如何实现车载系统的用户反馈和数据收集
3D人物的动作是如何制作出来的
允许从Python中调用C++函数、使用C++类和对象的库PyCXX
microPython的源码解析之 objint.c
量化交易系统中如何处理API的版本控制和兼容性?
c#视觉应用开发中如何在C#中进行图像批处理?
Python 强大的模板引擎库 Skeleton BootStrap
c#视觉应用开发中如何在C#中进行图像去残影?
车载系统软件工程师如何实现车载系统的远程软件更新
opencv多线程视频处理示例
python如何用udp协议
python 开发EZRO内容管理系统的案例介绍
智能农业设备软件工程师如何实现精准灌溉系统
microPython的源码解析之 emitinlinethumb.c
C#进行串口应用开发如何调试因串口通信异常导致的系统死机问题
构建我们的Python代码库依赖图
智能农业设备软件工程师如何实现精准播种系统
智能农业设备软件工程师如何实现农场管理软件平台
车载系统软件工程师如何实现车载系统的蓝牙和无线连接
c#视觉应用开发中如何在C#中使用神经网络进行图像生成?
车载系统软件工程师如何实现车载系统的交通信息集成和显示
如何使用pybind11,在Python中调用c++库
qt如何操作Excel文件
python的库scipy介绍
C#进行串口应用开发如何实现串口通信的调试跟踪与日志记录
车载系统软件工程师如何实现车载系统的驾驶员监控系统
python web应用开发神器 入门十七
python 生成随机数
C#进行串口应用开发如何分析系统中串口通信的实时性与稳定性
车载系统软件工程师如何处理车载系统的用户数据和偏好管理
microPython的源码解析之 nlrxtensa.c
智能农业设备软件工程师如何处理设备的数据同步和一致性
C#进行串口应用开发如何实现串口的数据透传
C#进行串口应用开发如何实现基于串口的心跳检测
智能农业设备软件工程师如何实现农业数据的云存储和备份
智能农业设备软件工程师如何集成和管理农业设备的多语言支持
microPython的源码解析之 emitbc.c
用Python构建开源跨平台的Azure CLI
c#视觉应用开发中如何在C#中进行图像去伪影?
c#垃圾回收和IDisposable
c#任务并行性进行多线程编程
python web应用开发神器 入门七
阿里巴巴研究院开源的代码库有哪些
RedisTimeSeries开源的时序数据数据库
python如何监控文件系统中的文件和目录的变化
c#视觉应用开发中如何在C#中进行图像去畸变?
python如何处理大规模的数据pyarrow
python的OS库如何使用
microPython的源码解析之 pairheap.c
c#视觉应用开发中如何在C#中进行图像去色散?
c#视觉应用开发中在C#中如何进行图像处理?
OpenAI Gym详细讲解一下,给出示例代码
halcon介绍以及与opencv比较
如何将列的数字编号,转化为EXcel的字母表示的列编号

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容