<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Playnite on 塑料世界的玻璃球</title><link>https://hugsyf.xyz/tags/playnite/</link><description>Recent content in Playnite on 塑料世界的玻璃球</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>hugsyf</copyright><lastBuildDate>Fri, 31 Jul 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://hugsyf.xyz/tags/playnite/index.xml" rel="self" type="application/rss+xml"/><item><title>从 Dune 到 Dune Rev：一次 Playnite 主题兼容性改造记录</title><link>https://hugsyf.xyz/post/26-07-31-dune-rev/</link><pubDate>Fri, 31 Jul 2026 00:00:00 +0000</pubDate><guid>https://hugsyf.xyz/post/26-07-31-dune-rev/</guid><description>&lt;img src="https://hugsyf.xyz/post/26-07-31-dune-rev/details-view.png" alt="Featured image of post 从 Dune 到 Dune Rev：一次 Playnite 主题兼容性改造记录" /&gt;&lt;p&gt;我一直在使用 &lt;a class="link" href="https://playnite.link/" target="_blank" rel="noopener"
&gt;Playnite&lt;/a&gt; 管理游戏库。在桌面主题中，&lt;a class="link" href="https://github.com/sakasakiking/Dune" target="_blank" rel="noopener"
&gt;Dune&lt;/a&gt; 很符合我的审美：宽松的排版、圆角卡片、干净的层次，以及很明显的 WinUI 3 / Fluent Design 气质。遗憾的是，它是一个较新的主题，扩展兼容性远不如一些成熟主题；部分插件页面会出现黑底黑字，另一些插件则完全没有位置显示。&lt;/p&gt;
&lt;p&gt;于是，我和 Codex 用一天时间把它逐步改造成了 &lt;strong&gt;&lt;a class="link" href="https://github.com/hugsyf/dune-rev" target="_blank" rel="noopener"
&gt;Dune Rev&lt;/a&gt;&lt;/strong&gt;：一个由我维护、保留原作视觉语言，同时补充扩展兼容性与自定义能力的个人 fork。&lt;/p&gt;
&lt;figure&gt;
&lt;img src="https://hugsyf.xyz/post/26-07-31-dune-rev/details-view.png"
alt="Dune Rev 详情视图"
width="1200em"
&gt;
&lt;figcaption&gt;Dune Rev 的详情视图；概览卡片和扩展内容会根据可用数据自适应显示&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id="起点好看的主题不完整的生态"&gt;起点：好看的主题，不完整的生态
&lt;/h2&gt;&lt;p&gt;Dune 原本声明支持 SuccessStory、HowLongToBeat、Extra Metadata Loader 和 ScreenshotsVisualizer，基础方向已经很清楚，但我日常使用的插件远不止这些。作为参照，Mythic 对 BackgroundChanger、DuplicateHider、GameActivity、Library Management、ThemeExtras、Steam 新闻与评论、ThemeModifier 等扩展都有成熟集成。&lt;/p&gt;
&lt;p&gt;最初看到的问题只是“设置页面颜色不对”，真正开始检查 XAML 后才发现，这并不是简单补几种颜色就能结束的工作：Playnite 主题不仅负责外观，还承担了许多插件控件的宿主、资源字典、可见性条件和布局契约。一个缺失的资源键可能让文字不可读；一个名称不正确的&lt;code&gt;ContentControl&lt;/code&gt; 会让插件无法注入内容；而两个视图复用同一份播放状态，甚至会产生只有在来回切换视图后才出现的故障。&lt;/p&gt;
&lt;h2 id="把插件数据变成主题的一部分"&gt;把插件数据变成主题的一部分
&lt;/h2&gt;&lt;p&gt;这次修改并没有简单地把所有插件面板堆到页面底部。我更希望扩展数据看起来像 Dune 原生界面的一部分，因此重新组织了详情页的概览区域：最后游玩时间、累计游玩时长、完成状态、成就、活动记录、HowLongToBeat 和 SystemChecker 都使用同一套卡片语言。&lt;/p&gt;
&lt;p&gt;这些卡片遵循几个规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;插件没有安装，或当前游戏没有对应数据时，卡片自动隐藏；&lt;/li&gt;
&lt;li&gt;剩余卡片自动换行，不为缺失项目留下空洞；&lt;/li&gt;
&lt;li&gt;可以打开扩展详情的卡片带有 Hover 动画，提示它不是静态信息；&lt;/li&gt;
&lt;li&gt;HowLongToBeat 只在卡片中显示 Main Story，避免 Main、Main+ 和 100% 挤在一起；&lt;/li&gt;
&lt;li&gt;完整图表、进度条或列表仍保留在下方的独立标签页中。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Playnite Achievements 是一个特殊情况。它本身带有主题迁移机制，因此显式添加一套“原生支持”反而会与迁移后的控件重复或冲突。最终方案是让插件继续负责迁移，主题只提供它需要的颜色和控件资源。这个过程也提醒我：插件兼容并不总是“写得越多越好”，首先要理解插件已经承担了什么工作。&lt;/p&gt;
&lt;p&gt;目前 Dune Rev 覆盖的主要扩展包括：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;th&gt;扩展&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;成就&lt;/td&gt;
&lt;td&gt;SuccessStory、Playnite Achievements 自动迁移&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;替代背景&lt;/td&gt;
&lt;td&gt;BackgroundChanger&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;重复副本&lt;/td&gt;
&lt;td&gt;DuplicateHider&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;功能图标&lt;/td&gt;
&lt;td&gt;Library Management&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;收藏与完成状态&lt;/td&gt;
&lt;td&gt;ThemeExtras&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;活动记录&lt;/td&gt;
&lt;td&gt;GameActivity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;通关时间估算&lt;/td&gt;
&lt;td&gt;HowLongToBeat&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Logo 与视频&lt;/td&gt;
&lt;td&gt;Extra Metadata Loader&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;截图&lt;/td&gt;
&lt;td&gt;ScreenshotsVisualizer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Steam 新闻与在线人数&lt;/td&gt;
&lt;td&gt;Steam News and Players Viewer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Steam 评论&lt;/td&gt;
&lt;td&gt;Review Viewer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;系统需求&lt;/td&gt;
&lt;td&gt;SystemChecker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;主题调整&lt;/td&gt;
&lt;td&gt;ThemeModifier&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="最难处理的并不是显示而是状态"&gt;最难处理的并不是“显示”，而是状态
&lt;/h2&gt;&lt;p&gt;Extra Metadata Loader 的 Logo 与视频集成带来了几个很典型的问题。早期版本在详情页没有显示Logo，而是退回到了游戏图标；修正控件宿主后，视频又出现了更隐蔽的状态错误：从详情视图切换到 Grid-Details View，再切回来，英雄图区域就无法重新播放视频，而 Grid 视图始终正常。&lt;/p&gt;
&lt;p&gt;原因是两个视图同时使用了缓存的标准播放器、相同的 RadioButton 组名，并绑定到插件的全局 &lt;code&gt;IsVideoPlaying&lt;/code&gt; 状态。视图虽然切换了，播放状态和宿主却没有真正隔离。最终我为两个视图使用独立配置的播放器实例、不同的媒体选择组，并让播放按钮绑定到各自播放器的状态。这个 bug 很适合作为 WPF/XAML 的一个小例子：界面消失不代表状态也消失，名称作用域之外还可能存在由插件缓存的对象。&lt;/p&gt;
&lt;h2 id="details-view-与-grid-details-view-不是同一种布局"&gt;Details View 与 Grid-Details View 不是同一种布局
&lt;/h2&gt;&lt;p&gt;另一个持续反复的问题是宽度。详情视图适合宽屏内容：左侧有概览卡片与扩展标签页，右侧是开发者、发行商、评分和功能特色。Grid-Details View 则通常只是网格右侧的一条窄栏。如果把两者当成同一套横向布局，结果不是信息栏吞掉所有空间，就是卡片被压缩成细长的小块。&lt;/p&gt;
&lt;p&gt;因此，两种视图最终拥有了独立的尺寸和排列规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Details View 默认最大内容宽度为 1760 px，信息栏最大宽度为 480 px；&lt;/li&gt;
&lt;li&gt;Grid View 默认详情栏宽度为 640 px；&lt;/li&gt;
&lt;li&gt;Grid 中的概览卡片可以换行，信息面板移动到卡片下方；&lt;/li&gt;
&lt;li&gt;Logo、卡片、扩展面板、按钮和顶部栏尺寸都可独立调整。&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
&lt;img src="https://hugsyf.xyz/post/26-07-31-dune-rev/grid-details-view.png"
alt="Dune Rev 网格详情视图"
width="1200em"
&gt;
&lt;figcaption&gt;Grid-Details View 使用专门的窄栏布局，而不是压缩宽屏详情页&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;这些设置被暴露给 ThemeModifier。它的主题配置格式目前只有一条 &lt;code&gt;Description&lt;/code&gt; 字符串，没有按语言提供名称的机制，所以我采用了 &lt;code&gt;English / 简体中文&lt;/code&gt; 的双语标签，并统一按“全局布局、详情视图、网格视图、扩展面板、网格封面”等区域分组。最终共有 26 个经过核对、确实被主题使用的调节项，而不只是清单里看得见、实际不起作用的滑条。&lt;/p&gt;
&lt;h2 id="为什么选择-fluent-dim"&gt;为什么选择 Fluent Dim
&lt;/h2&gt;&lt;p&gt;Dune 原本的深色模式就注明可能存在问题。真正麻烦的是，Playnite 10 没有为插件注入的控件提供可靠、统一的深浅色状态：主题自己的控件可以切换，插件迁移或注入的页面却未必跟随。结果往往是浅色背景上的浅色文字，或深色背景上的黑色文字。&lt;/p&gt;
&lt;p&gt;与其维护两套始终有一部分失效的配色，我最终选择只保留一套 &lt;strong&gt;Fluent Dim&lt;/strong&gt;：比传统浅色模式更适合夜间，又不像纯黑主题那样产生强烈对比。它使用深灰蓝表面、较柔和的白色文字和 Fluent风格的半透明层次。这个决定牺牲了主题切换，但换来了主界面、设置窗口和插件内容之间稳定得多的一致性。&lt;/p&gt;
&lt;h2 id="从修改版到可以发布的-fork"&gt;从修改版到可以发布的 fork
&lt;/h2&gt;&lt;p&gt;随着修改越来越多，它已经不适合继续被当成一份本地补丁。我将项目命名为 &lt;strong&gt;Dune Rev&lt;/strong&gt;，生成了新的 GUID，更新主题名称、作者与仓库链接，并补齐 README、CHANGELOG、&lt;code&gt;.gitignore&lt;/code&gt;、许可证和 Playnite 的 Add-on / Installer manifests。&lt;/p&gt;
&lt;p&gt;原作采用 MIT License，因此 fork 和再发布是允许的，但必须保留原始版权与许可声明。Dune Rev 的许可证中保留了 sakasakiking 的原始版权信息，并加入我的修改声明。&lt;/p&gt;
&lt;p&gt;发布前还进行了几层验证：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;对全部 XAML 文件做 XML 解析；&lt;/li&gt;
&lt;li&gt;使用 Playnite 的 32 位程序集按真实资源加载顺序测试字典；&lt;/li&gt;
&lt;li&gt;执行 Release 构建并确认没有编译错误；&lt;/li&gt;
&lt;li&gt;用 Playnite Toolbox 生成 &lt;code&gt;.pthm&lt;/code&gt; 安装包并检查包内文件；&lt;/li&gt;
&lt;li&gt;核对 ThemeModifier 配置、插件清单、截图与下载 URL。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;最终的 1.0.0 安装包已经准备完成。接下来只需要建立 GitHub Release，并把 Add-on manifest 提交到官方的 &lt;a class="link" href="https://github.com/JosefNemec/PlayniteAddonDatabase" target="_blank" rel="noopener"
&gt;PlayniteAddonDatabase&lt;/a&gt;，就可以申请进入 Playnite 内置的附加组件浏览器。&lt;/p&gt;
&lt;h2 id="总结"&gt;总结
&lt;/h2&gt;&lt;p&gt;这次工作最初只是想修复几个插件页面的颜色，最后却变成了对主题布局、插件数据、状态管理和发布流程的完整梳理。它也说明了 Playnite 主题开发很有意思的一点：XAML 不只是“皮肤”，而是核心程序与多个独立扩展之间的一层用户界面协议。&lt;/p&gt;
&lt;p&gt;Dune Rev 仍然保留了我最喜欢的 Dune 外观，但现在它更像一个可以长期使用的完整主题。更重要的是，这个项目已经从我电脑上的一组修改，变成了有独立身份、可验证、可更新，也可以公开发布的开源项目。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;本篇博客由我与 GPT-5.6 Sol High 撰写&lt;/p&gt;&lt;/blockquote&gt;</description></item></channel></rss>