├── CNAME ├── .gitattributes ├── Readme.md ├── _data └── languages.yml ├── ads.txt ├── study.html ├── assets ├── images │ ├── logo.png │ ├── icon_16x16.png │ ├── icon_32x32.png │ ├── icon_180x180.png │ └── icon_32x32.svg ├── attachments │ └── uninstall-image-viewer.bat ├── js │ ├── tablesorter.js │ ├── 404.js │ ├── tags.js │ └── search.js └── css │ ├── _i18n.scss │ ├── interviews.scss │ ├── style.scss │ ├── _highlight.scss │ └── _variables_override.scss ├── jsconfig.json ├── package.json ├── study_post.html ├── _layouts ├── redirect.html ├── plain.html └── default.html ├── 404.md ├── .gitignore ├── _plugins ├── image_cdn.rb ├── algolia_hook.rb └── i18n.rb ├── Gemfile ├── _includes ├── image.html ├── video.html ├── heading.html ├── figure.html ├── header.html ├── footer.html ├── content.html └── head.html ├── pages.json ├── .prettierrc.json ├── search.html ├── _en ├── search.html ├── 2023-10-16-Suzumiya-Haruhi-no-Chokuretsu-Chinese-Localization.md └── posts.html ├── _posts ├── 2022-07-04-Ruanyifeng-No-Block-AdBlock.md ├── 2023-10-16-Suzumiya-Haruhi-no-Chokuretsu-Chinese-Localization.md ├── 2021-10-25-Buddy-Mission-Bond.md ├── 2024-11-02-Pokemon-Gen-4-Font-Patch.md ├── 2019-11-20-How-to-Insert-Formulas-in-Wechat-Articles.md ├── 2025-06-12-Premiere-Pro-Color-Range.md ├── 2024-07-10-Persona-Q2-Chinese-Localization.md ├── 2022-09-04-Take-and-Save-a-Screenshot-on-a-Windows-PC-with-Joy-Con.md ├── 2022-01-11-Automate-Portrait-Keying-in-OBS-without-Green-Screen.md ├── 2020-02-17-Danmaku-Wall.md ├── 2019-01-18-Pokemon-Surf-Glitch.md ├── 2024-11-09-Steam-Unable-to-Register.md ├── 2024-11-04-NitroPatcher.md ├── 2021-10-14-Try-to-Extract-Messages-from-Games.md ├── 2018-06-05-About.md ├── 2019-11-01-Tenki-no-ko.md ├── 2023-03-15-A-Purchase-in-Surugaya.md ├── 2020-07-31-How-to-Download-Subtitle-for-Online-Class.md ├── 2020-03-07-Update-Study-Search-and-Pdf.md ├── 2019-09-25-PKU-Disk.md ├── 2025-06-26-Remove-Intelligent-Image-Viewer.md ├── 2019-11-29-Save-Your-Unsaved-PPT-File.md ├── 2023-03-29-Paranormasight-Translation.md ├── 2020-02-02-How-to-Get-e-Textbooks.md ├── 2023-11-06-Jellyfin-Plugin-Douban.md ├── 2021-11-15-Download-Pdf-File-from-Cnki.md ├── 2019-11-26-Managing-Chinese-Literature-with-EndNote.md ├── 2019-03-02-Pokemon-Tweaking.md ├── 2020-02-16-Update-3-0.md ├── 2024-01-01-Migrate-LiverRe-comments-to-Giscus.md ├── 2020-10-30-Automatic-Numbering-in-Microsoft-Word.md ├── 2025-06-30-G-Fusion-Game-Fest-2025.md ├── 2020-07-27-Run-Ubuntu-in-Windows-10.md ├── 2025-01-01-2024-ACGN-Reviews.md ├── 2023-02-24-Summer-Time-Rendering-Another-Horizon-Translation.md ├── 2018-10-12-Luigi-Mansion-Chinese-Localization.md ├── 2021-12-28-2021-ACGN-Reviews.md ├── 2023-05-28-DIY-My-Computer.md └── 2025-04-25-Super-Princess-Peach-Chinese-Localization-4.md ├── posts.html ├── _i18n ├── zh-cn.yml └── en.yml ├── xzonn.md ├── .github └── workflows │ └── publish.yml ├── _config.yml ├── index.html └── Gemfile.lock /CNAME: -------------------------------------------------------------------------------- 1 | xzonn.top -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.bat binary 2 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | [Xzonn 的小站](https://xzonn.top/) -------------------------------------------------------------------------------- /_data/languages.yml: -------------------------------------------------------------------------------- 1 | alias: 2 | zh-cn: zh-CN 3 | en: en -------------------------------------------------------------------------------- /ads.txt: -------------------------------------------------------------------------------- 1 | google.com, pub-8317643192080236, DIRECT, f08c47fec0942fa0 -------------------------------------------------------------------------------- /study.html: -------------------------------------------------------------------------------- 1 | --- 2 | destination: /study/posts.html 3 | layout: redirect 4 | sitemap: false 5 | --- -------------------------------------------------------------------------------- /assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xzonn/xzonn.github.io/HEAD/assets/images/logo.png -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeAcquisition": { 3 | "include": [ 4 | "jquery" 5 | ] 6 | } 7 | } -------------------------------------------------------------------------------- /assets/images/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xzonn/xzonn.github.io/HEAD/assets/images/icon_16x16.png -------------------------------------------------------------------------------- /assets/images/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xzonn/xzonn.github.io/HEAD/assets/images/icon_32x32.png -------------------------------------------------------------------------------- /assets/images/icon_180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xzonn/xzonn.github.io/HEAD/assets/images/icon_180x180.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "dependencies": { 3 | "bootstrap": "^5.3.0", 4 | "bootstrap-icons": "^1.10.5" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /study_post.html: -------------------------------------------------------------------------------- 1 | --- 2 | destination: /study/ 3 | layout: redirect 4 | permalink: /posts/Study.html 5 | sitemap: false 6 | --- -------------------------------------------------------------------------------- /assets/attachments/uninstall-image-viewer.bat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xzonn/xzonn.github.io/HEAD/assets/attachments/uninstall-image-viewer.bat -------------------------------------------------------------------------------- /assets/js/tablesorter.js: -------------------------------------------------------------------------------- 1 | $.getScript("https://cdn.jsdelivr.net/npm/tablesorter@2.31.2/dist/js/jquery.tablesorter.combined.min.js", () => 2 | $(".tablesorter").tablesorter() 3 | ); 4 | -------------------------------------------------------------------------------- /_layouts/redirect.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/css/_i18n.scss: -------------------------------------------------------------------------------- 1 | html[lang="en"] { 2 | .xz-meta-infomation .xz-meta-update::before { 3 | content: "Updated on:\00a0" 4 | } 5 | 6 | .xz-meta-infomation .xz-meta-tags::before { 7 | content: "Tags:\00a0" 8 | } 9 | } -------------------------------------------------------------------------------- /404.md: -------------------------------------------------------------------------------- 1 | --- 2 | info: 你似乎来到了错误的地方…… 3 | js: 404 4 | no_comment: true 5 | no_sidenav: true 6 | sitemap: false 7 | title: 404 NOT FOUND 8 | --- 9 | 这个页面目前什么也没有。请检查您的链接是否正确。如果您是从其他页面跳转至此,请及时反馈。 10 | 11 | 您可以 **[返回首页](/)** 或者关闭本页面。 -------------------------------------------------------------------------------- /_layouts/plain.html: -------------------------------------------------------------------------------- 1 | {% capture src %}src="data:image/svg+xml;charset=utf-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201024%201024%22%3E%3C%2Fsvg%3E" data-src={% endcapture %}{{ content | replace: src, "src="}} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Jekyll 2 | _drafts/ 3 | _site/ 4 | .sass-cache/ 5 | .jekyll-cache/ 6 | .jekyll-metadata 7 | *.draft.md 8 | 9 | # Bundler 10 | .bundle/ 11 | vendor/ 12 | 13 | # Npm 14 | node_modules/ 15 | 16 | # Visual Studio 17 | .vs/ 18 | Debug/ 19 | 20 | # Visual Studio Code 21 | .vscode/ 22 | *.code-workspace -------------------------------------------------------------------------------- /_plugins/image_cdn.rb: -------------------------------------------------------------------------------- 1 | module Jekyll 2 | module ImageCdn 3 | def image_cdn(url) 4 | return nil if url.nil? 5 | @image_cdn = @context.registers[:site].config['image_cdn'] 6 | url.include?('/') ? url : "#{@image_cdn}/#{url}" 7 | end 8 | end 9 | end 10 | 11 | Liquid::Template.register_filter(Jekyll::ImageCdn) 12 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | gem "jekyll", "~> 4.3", group: :jekyll_plugins 3 | gem "webrick", "~> 1.8" 4 | gem "kramdown", "~> 2.4" 5 | gem "kramdown-parser-gfm", "~> 1.1" 6 | gem "sass-embedded", "< 1.70" 7 | group :jekyll_plugins do 8 | gem "jekyll-algolia" 9 | gem "jekyll-feed" 10 | gem "jekyll-relative-links" 11 | gem "jekyll-sass-converter" 12 | gem "jekyll-sitemap" 13 | end 14 | -------------------------------------------------------------------------------- /_layouts/default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% include head.html %} 5 | 6 | 7 | {% include header.html %} 8 | {% include heading.html %} 9 | {% include content.html %} 10 | {% include footer.html %} 11 | 12 | -------------------------------------------------------------------------------- /_includes/image.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/images/icon_32x32.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /pages.json: -------------------------------------------------------------------------------- 1 | --- 2 | layout: plain 3 | --- 4 | [{% for post in site.posts %}{"title":{{ post.title | jsonify }},"link":{{ post.url | jsonify }},"date":"{{ post.date | date : "%Y-%m-%d %H:%M" }}","update":"{{ post.last_modified_at | date : "%Y-%m-%d %H:%M" }}","head_image":{{ post.head_image | image_cdn | jsonify }},"info":{% if post.info %}{{ post.info | jsonify }}{% else %}{{ post.content | strip_html | remove: "$" | truncate: 200, "……" | jsonify }}{% endif %},"wechat_link":{{ post.wechat_link | jsonify }},"tags":{{ post.tags | jsonify }}}{% unless forloop.last %},{% endunless %}{% endfor %}] -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "always", 3 | "bracketSpacing": true, 4 | "endOfLine": "lf", 5 | "htmlWhitespaceSensitivity": "css", 6 | "insertPragma": false, 7 | "singleAttributePerLine": false, 8 | "bracketSameLine": false, 9 | "jsxBracketSameLine": false, 10 | "jsxSingleQuote": false, 11 | "printWidth": 120, 12 | "proseWrap": "preserve", 13 | "quoteProps": "preserve", 14 | "requirePragma": false, 15 | "semi": true, 16 | "singleQuote": false, 17 | "tabWidth": 2, 18 | "trailingComma": "es5", 19 | "useTabs": false, 20 | "vueIndentScriptAndStyle": false, 21 | "parser": "babel" 22 | } -------------------------------------------------------------------------------- /assets/js/404.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /* global $ */ 3 | 4 | (() => { 5 | let url = location.pathname; 6 | if (/-To-/.test(url)) { 7 | url = url.replace(/-To-/, "-to-"); 8 | } else if (/\/posts\//.test(url)) { 9 | url = url.replace(/\/posts\//, "/study/"); 10 | } else if (/\/ParanormasightChsLocalization\//.test(url) || /\/ChokuretsuChsLocalization\//.test(url)) { 11 | url = `//7.xzonn.top${url}`; 12 | } else { 13 | return; 14 | } 15 | $.ajax({ 16 | type: "HEAD", 17 | url: url, 18 | }).done((_, __, jqXHR) => { 19 | if (jqXHR.status == 200) { 20 | location.href = url; 21 | } 22 | }); 23 | })(); 24 | -------------------------------------------------------------------------------- /_plugins/algolia_hook.rb: -------------------------------------------------------------------------------- 1 | module Jekyll 2 | module Algolia 3 | module Hooks 4 | def self.before_indexing_each(record, node, context) 5 | if record[:no_list] 6 | return nil 7 | end 8 | [:categories, :collection, :css, :excerpt_text, :excerpt_html, :head_image, :head_image_height, :head_image_shown, :head_image_width, :html, :i18n, :info, :js, :last_modified_at, :license, :links, :logs, :no_comment, :no_date, :no_list, :no_sidenav, :permalink, :references, :slug, :type].each do |field| 9 | record.delete(field) 10 | end 11 | return record 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /search.html: -------------------------------------------------------------------------------- 1 | --- 2 | i18n: true 3 | i18n_en: /posts/search.html 4 | js: search 5 | no_comment: true 6 | no_sidenav: true 7 | title: 搜索 8 | --- 9 | 13 |
14 |
15 | 16 | -------------------------------------------------------------------------------- /_en/search.html: -------------------------------------------------------------------------------- 1 | --- 2 | i18n: true 3 | i18n_zh: /search.html 4 | js: search 5 | no_comment: true 6 | no_date: true 7 | no_list: true 8 | no_sidenav: true 9 | title: Search 10 | --- 11 | 15 |
16 |
17 | 18 | -------------------------------------------------------------------------------- /_posts/2022-07-04-Ruanyifeng-No-Block-AdBlock.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2022-07-04 23:16 3 | head_image: 8fac7d92a62229268f7640c3bce1ca66.png 4 | info: 一行代码实现防止阮一峰博客屏蔽AdBlock。 5 | last_modified_at: 2022-07-04 23:27 6 | tags: 杂记 7 | title: 防止阮一峰博客屏蔽AdBlock 8 | --- 9 | 阮一峰博客检测广告的核心代码为: 10 | 11 | ```javascript 12 | if ( 13 | /*isAdblocker || */ 14 | (img && window.getComputedStyle(img).display === 'none') || 15 | (img && window.getComputedStyle(img.parentElement).display === 'none') 16 | ) 17 | ``` 18 | 19 | 注意到这段代码是通过`setTimeout(checker, 1000);`执行的,因此只需要把`window.getComputedStyle`这个函数修改掉就可以了。 20 | 21 | 核心代码: 22 | 23 | ```javascript 24 | window.getComputedStyle = function() { return { "display": "block" }; } 25 | ``` 26 | 27 | [Greasy Fork](https://greasyfork.org/zh-CN):。 -------------------------------------------------------------------------------- /_posts/2023-10-16-Suzumiya-Haruhi-no-Chokuretsu-Chinese-Localization.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2023-10-16 23:05 3 | head_image: bd1489ea6f7cd8dd28613481ab6f1dcd.webp 4 | head_image_height: 384 5 | head_image_width: 768 6 | i18n: true 7 | info: 交流借鉴。 8 | last_modified_at: 2024-07-28 16:32 9 | links: 10 | - - https://github.com/Qi-Busiyi-Hanhuazu/ChokuretsuChsLocalization 11 | - 汉化相关代码 12 | references: 13 | - - https://blog.csdn.net/LuckilyYu/article/details/5424928 14 | - NDS《凉宫春日的直列》的一些破解信息 15 | - - https://haroohie.club/blog/2022-10-19-chokuretsu-compression 16 | - Chokuretsu ROM Hacking Challenges Part 1 – Cracking a Compression Algorithm! 17 | - - https://haroohie.club/blog/2022-11-02-chokuretsu-archives 18 | - Chokuretsu ROM Hacking Challenges Part 2 – Archive Archaeology 19 | tags: DS 汉化笔记 20 | title: 《凉宫春日的串联》汉化笔记 21 | --- 22 | {% include posts_i18n/zh-cn/2023-10-16-Suzumiya-Haruhi-no-Chokuretsu-Chinese-Localization.md %} -------------------------------------------------------------------------------- /_includes/video.html: -------------------------------------------------------------------------------- 1 | {{ include.blank }}
{% if include.youtube %} 2 | {{ include.blank }}
{% endif %}{% if include.aid or include.bvid %} 3 | {{ include.blank }}
{% endif %} 4 | {{ include.blank }}
-------------------------------------------------------------------------------- /_en/2023-10-16-Suzumiya-Haruhi-no-Chokuretsu-Chinese-Localization.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2023-10-16 23:05 3 | head_image: bd1489ea6f7cd8dd28613481ab6f1dcd.webp 4 | head_image_height: 384 5 | head_image_width: 768 6 | i18n: true 7 | info: Exchange and learn from each other. 8 | last_modified_at: 2024-07-28 16:32 9 | links: 10 | - - https://github.com/Qi-Busiyi-Hanhuazu/ChokuretsuChsLocalization 11 | - Chinese localization related codes 12 | references: 13 | - - https://blog.csdn.net/LuckilyYu/article/details/5424928 14 | - NDS《凉宫春日的直列》的一些破解信息 15 | - - https://haroohie.club/blog/2022-10-19-chokuretsu-compression 16 | - Chokuretsu ROM Hacking Challenges Part 1 – Cracking a Compression Algorithm! 17 | - - https://haroohie.club/blog/2022-11-02-chokuretsu-archives 18 | - Chokuretsu ROM Hacking Challenges Part 2 – Archive Archaeology 19 | tags: chinese-localization-notes ds 20 | title: Chinese localization notes of "Suzumiya Haruhi no Chokuretsu" (The Series of Haruhi Suzumiya) 21 | --- 22 | {% include posts_i18n/en/2023-10-16-Suzumiya-Haruhi-no-Chokuretsu-Chinese-Localization.md %} -------------------------------------------------------------------------------- /_en/posts.html: -------------------------------------------------------------------------------- 1 | --- 2 | i18n: true 3 | js: tags tablesorter 4 | no_comment: true 5 | no_date: true 6 | no_list: true 7 | no_sidenav: true 8 | permalink: /posts/en/ 9 | title: Article List 10 | --- 11 | 14 | 15 | 16 | 17 | 18 | {% for post in site.en %}{% unless post.no_list %} 19 | 20 | 21 | 24 | 25 | 26 | {% endunless %}{% endfor %} 27 | 28 |
TitleTagsCreated onUpdated on
{{ post.title }}{% for tag in post.tags %} 22 | {% endfor %} 23 | {{ post.date | date : "%Y-%m-%d %H:%M" }}{{ post.last_modified_at| date : "%Y-%m-%d %H:%M" }}
-------------------------------------------------------------------------------- /assets/css/interviews.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | /* 访谈 */ 4 | h2 { 5 | text-align: center; 6 | } 7 | 8 | h3 { 9 | padding: 15px 20px; 10 | border-left: 4px solid #bbb; 11 | background-color: #f2f2f2; 12 | } 13 | 14 | .question { 15 | position: relative; 16 | padding-left: 2.5em; 17 | margin-top: 60px; 18 | 19 | &::before { 20 | position: absolute; 21 | top: 0; 22 | left: 0; 23 | display: block; 24 | width: 2em; 25 | content: '——'; 26 | } 27 | 28 | h2 + &, h3 + &, h4 + & { 29 | margin-top: 0; 30 | } 31 | } 32 | 33 | .border-left { 34 | padding-left: calc(1em - 5px); 35 | border-left: 5px solid; 36 | } 37 | 38 | .border-blue { 39 | @extend .border-left; 40 | border-color: #009beb; 41 | color: #009beb; 42 | } 43 | 44 | .border-green { 45 | @extend .border-left; 46 | border-color: #009682; 47 | color: #009682; 48 | } 49 | 50 | .border-orange { 51 | @extend .border-left; 52 | border-color: #f5aa00; 53 | color: #f5aa00; 54 | } 55 | 56 | .border-purple { 57 | @extend .border-left; 58 | border-color: #6f42c1; 59 | color: #6f42c1; 60 | } 61 | 62 | .border-red { 63 | @extend .border-left; 64 | border-color: #e60012; 65 | color: #e60012; 66 | } -------------------------------------------------------------------------------- /_includes/heading.html: -------------------------------------------------------------------------------- 1 | 2 |
{% if page.head_image %} 3 |
{% endif %} 4 |
5 |
{% if page.date %}{% unless page.no_date %} 6 |
{{ page.date | date: "%Y.%-m.%-d" }}
{% endunless %}{% endif %}{% if page.title %} 7 |

{{ page.title }}

{% endif %}{% if page.info %} 8 |

{{ page.info }}

{% endif %}{% if page.last_modified_at or page.tags.size > 0 %} 9 |
{% if page.last_modified_at %}{% unless page.no_date %} 10 | {% endunless %}{% endif %}{% if page.tags.size > 0 %} 11 |
    {% for tag in page.tags %}
  • {{ tag }}
  • {% endfor %}
{% endif %} 12 |
{% endif %} 13 |
14 |
15 |
16 | -------------------------------------------------------------------------------- /posts.html: -------------------------------------------------------------------------------- 1 | --- 2 | i18n: true 3 | js: tags tablesorter 4 | no_comment: true 5 | no_sidenav: true 6 | permalink: /posts/ 7 | title: 文章列表 8 | --- 9 |
如果您在查找学习资料,请前往此处
10 | 14 | 15 | 16 | 17 | 18 | {% for post in site.posts %} 19 | 20 | 21 | 24 | 25 | 26 | {% endfor %} 27 | 28 |
标题标签创建时间修改时间
{{ post.title }}{% for tag in post.tags %} 22 | {% endfor %} 23 | {{ post.date | date : "%Y-%m-%d %H:%M" }}{{ post.last_modified_at| date : "%Y-%m-%d %H:%M" }}
-------------------------------------------------------------------------------- /_i18n/zh-cn.yml: -------------------------------------------------------------------------------- 1 | from-site-name: "来自 Xzonn 的小站" 2 | site-name: "Xzonn 的小站" 3 | mathjax-render-finished: "MathJax渲染已完成。" 4 | header-list-url: "/posts/" 5 | header-list: "列表" 6 | header-search-url: "/search.html" 7 | header-search: "搜索" 8 | lang-zh-cn: "简体中文" 9 | lang-en: "English" 10 | video-player-youtube: "YouTube 视频播放器" 11 | video-player-bilibili: "Bilibili 视频播放器" 12 | content-references: "参考资料" 13 | content-links: "外部链接" 14 | content-history: "更新记录" 15 | content-comment-info: "如果需要在留言中发布图片,请前往GitHub上的Discussions。您也可以通过bilibili的私信功能与我联系。" 16 | footer-license-by-nc-sa: "知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议" 17 | footer-license-by-nc-sa-info: "除非另有声明,本网站采用“知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议”进行许可。" 18 | footer-license-by-nc: "知识共享署名-非商业性使用 4.0 国际许可协议" 19 | footer-license-by-nc-info: "本页面采用“知识共享署名-非商业性使用 4.0 国际许可协议”进行许可。" 20 | footer-generated-by: "由Jekyll生成" 21 | footer-deployed-by: "由GitHub Pages部署" 22 | footer-about-site: "关于本站" 23 | footer-about-me: "关于我" 24 | footer-feed: "RSS订阅" 25 | footer-source-codes: "源代码" -------------------------------------------------------------------------------- /_includes/figure.html: -------------------------------------------------------------------------------- 1 | {{ include.blank }}{% assign _srcs = include.src | split: "|" %}{% if _srcs.size > 1 %}{% assign _widths = include.width | split: "|" %}{% assign _heights = include.height | split: "|" %}{% assign _links = include.link | split: "|" %} 2 | {{ include.blank }}
{% for src in _srcs %}{% assign width = _widths[forloop.index0] | default: width %}{% assign height = _heights[forloop.index0] | default: height %} 3 | {{ include.blank }} {% include image.html class="figure-image" src=src alt=include.alt width=width height=height %}{% endfor %} 4 | {{ include.blank }}
{% unless include.no_link %}{% for src in _srcs %}{% assign link = _links[forloop.index0] | default: link %} 5 | {{ include.blank }} {% endfor %}{% endunless %}{% else %} 6 | {{ include.blank }} {% include image.html class="figure-image" src=include.src alt=include.alt width=include.width height=include.height %}{% unless include.no_link %} 7 | {{ include.blank }} {% endunless %}{% endif %}{% if include.alt %} 8 | {{ include.blank }}
{{ include.alt }}
{% endif %} 9 | {{ include.blank }} -------------------------------------------------------------------------------- /_i18n/en.yml: -------------------------------------------------------------------------------- 1 | from-site-name: "Xzonn's Blog" 2 | site-name: "Xzonn's Blog" 3 | mathjax-render-finished: "MathJax rendering finished." 4 | header-list-url: "/posts/en/" 5 | header-list: "List" 6 | header-search-url: "/posts/en/search.html" 7 | header-search: "Search" 8 | lang-zh-cn: "简体中文" 9 | lang-en: "English" 10 | video-player-youtube: "YouTube video player" 11 | video-player-bilibili: "Bilibili video player" 12 | content-references: "References" 13 | content-links: "External Links" 14 | content-history: "Update History" 15 | content-comment-info: "If you need to post images in your message, please go to GitHub Discussions. You can also contact me on Bilibili." 16 | footer-license-by-nc-sa: "Attribution-NonCommercial-ShareAlike 4.0 International" 17 | footer-license-by-nc-sa-info: "Contents on this site are licensed under a “Attribution-NonCommercial-ShareAlike 4.0 International” license except where otherwise noted." 18 | footer-license-by-nc: "Attribution-NonCommercial 4.0 International" 19 | footer-license-by-nc-info: "This page is licensed under a “Attribution-NonCommercial 4.0 International” license." 20 | footer-generated-by: "Generated by Jekyll" 21 | footer-deployed-by: "Deployed by GitHub Pages" 22 | footer-about-site: "About This Blog" 23 | footer-about-me: "About Me" 24 | footer-feed: "RSS Feed" 25 | footer-source-codes: "Source Codes" -------------------------------------------------------------------------------- /xzonn.md: -------------------------------------------------------------------------------- 1 | --- 2 | class: plainlinks 3 | date: 2021-06-15 20:01 4 | info: "" 5 | last_modified_at: 2023-12-28 15:28 6 | no_comment: true 7 | no_date: true 8 | no_sidenav: true 9 | title: 关于我 10 | --- 11 | {% include image.html src="https://avatars.githubusercontent.com/u/30619816" width="200" height="200" class="float-right" %} 12 | {% include image.html src="https://images.xzonn.top/status.svg" width="200" height="50" class="float-right clear-right" %} 13 | 14 | {{ "now" | date: "%y" }}岁,是学生。专业是环境工程。 15 | {: .text-left } 16 | 17 | 任天堂爱好者,宝可梦玩家。会一点点编程。经常挖坑不填。 18 | {: .text-left } 19 | 20 | 做过的事: 21 | {: .text-left } 22 | 23 | - [《宝可梦》第四世代汉化修正](https://xzonn.top/PokemonChineseTranslationRevise/) 24 | - [《路易吉洋馆》汉化](https://xzonn.top/LuigiMansion/) 25 | - [任天堂官方中文化游戏文本](https://github.com/Xzonn/NintendoOfficialChineseGames) 26 | - [任天堂开发者访谈保存计划](https://ninterviews.xzonn.top/) 27 | - [《宝可梦 朱/紫》数据库](https://sv.xzonn.top/) 28 | - 七不思议汉化组: 29 | - [《灵异视界 FILE23 本所七大不可思议》汉化](https://xzonn.top/ParanormasightChsLocalization/) 30 | - [《凉宫春日的串联》汉化](https://xzonn.top/ChokuretsuChsLocalization/)(进行中) 31 | - ……以及其他秘密事项 32 | 33 | 联系方式: 34 | {: .text-left } 35 | 36 | - Bilibili:[Xzonn](https://space.bilibili.com/16114399) 37 | - 微博:[Xzonn2020](https://weibo.com/Xzonn2020/) 38 | - Twitter:[Xzonn2000](https://twitter.com/Xzonn2000) 39 | - Steam:[Xzonn](https://steamcommunity.com/id/xzonn/) 40 | - GitHub:[Xzonn](https://github.com/Xzonn) 41 | - 神奇宝贝百科:[Xzonn](https://wiki.52poke.com/wiki/User:Xzonn) 42 | - 萌娘百科:[Xzonn](https://zh.moegirl.org.cn/User:Xzonn) 43 | - 中文维基百科:[Xzonn2000](https://zh.wikipedia.org/wiki/User:Xzonn2000) 44 | - QQ:妙蛙种子铁炮鱼雷吉艾斯比比鸟 45 | - Nintendo Switch:SW-4444-3477-1800 46 | - 个人主页: -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | workflow_dispatch: 8 | 9 | permissions: 10 | contents: read 11 | pages: write 12 | id-token: write 13 | 14 | concurrency: 15 | group: "pages" 16 | cancel-in-progress: false 17 | 18 | jobs: 19 | build: 20 | runs-on: ubuntu-latest 21 | steps: 22 | - uses: actions/checkout@v4 23 | - uses: ruby/setup-ruby@v1 24 | with: 25 | ruby-version: '3.2' 26 | bundler-cache: true 27 | - uses: actions/setup-node@v4 28 | with: 29 | node-version: '20' 30 | cache: npm 31 | - name: Npm 32 | run: | 33 | npm install 34 | - name: Setup Pages 35 | id: pages 36 | uses: actions/configure-pages@v4 37 | - name: Build Site 38 | run: | 39 | bundle exec jekyll build --trace --profile --baseurl "${{ steps.pages.outputs.base_path }}" 40 | env: 41 | JEKYLL_ENV: production 42 | - uses: actions/upload-pages-artifact@v3 43 | - name: Update Algolia index 44 | run: | 45 | bundle exec jekyll algolia push 46 | env: 47 | ALGOLIA_API_KEY: ${{ secrets.ALGOLIA_API_KEY }} 48 | if: env.ALGOLIA_API_KEY != '' 49 | continue-on-error: true 50 | 51 | publish: 52 | if: github.event_name == 'push' && github.ref == 'refs/heads/master' 53 | environment: 54 | name: github-pages 55 | url: ${{ steps.deployment.outputs.page_url }} 56 | runs-on: ubuntu-latest 57 | needs: build 58 | steps: 59 | - name: Deploy to GitHub Pages 60 | id: deployment 61 | uses: actions/deploy-pages@v4 62 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | algolia: 2 | application_id: "ZVIOW9GL6U" 3 | index_name: "xzonn_top" 4 | files_to_exclude: 5 | - index.html 6 | - index.md 7 | - posts.html 8 | - search.html 9 | nodes_to_index: "figcaption,p,li" 10 | settings: 11 | searchableAttributes: 12 | - title 13 | - headings 14 | - unordered(tags) 15 | - unordered(content) 16 | attributesToHighlight: 17 | - content 18 | - headings 19 | - tags 20 | - title 21 | attributesForFaceting: 22 | - lang 23 | - unordered(tags) 24 | - title 25 | author: Xzonn 26 | defaults: 27 | - values: 28 | lang: "zh-cn" 29 | layout: "default" 30 | license: "by-nc-sa" 31 | head_image_width: 1280 32 | head_image_height: 720 33 | head_image_shown: true 34 | - scope: 35 | type: "posts" 36 | values: 37 | permalink: /posts/:title.html 38 | - scope: 39 | type: "en" 40 | values: 41 | lang: "en" 42 | permalink: /posts/en/:title.html 43 | exclude: 44 | - Debug/ 45 | - node_modules/ 46 | - vendor/ 47 | - Gemfile 48 | - Gemfile.lock 49 | - jsconfig.json 50 | - package.json 51 | - package-lock.json 52 | - Readme.md 53 | markdown: kramdown 54 | kramdown: 55 | syntax_highlighter_opts: 56 | css_class: 'highlight' 57 | name: Xzonn的小站 58 | plugins: 59 | - jekyll-feed 60 | - jekyll-sitemap 61 | - jekyll-sass-converter 62 | timezone: Asia/Shanghai 63 | theme: 64 | repository: Xzonn/xzonn.github.io 65 | url: https://xzonn.top 66 | image_cdn: https://images.xzonn.top/github 67 | static_cdn: https://cdn.jsdelivr.net/gh/Xzonn/xzonn.github.io@master 68 | version: v5.0 69 | sass: 70 | sass_dir: assets/css 71 | load_paths: 72 | - assets/css 73 | - node_modules 74 | sourcemap: always 75 | style: compressed 76 | collections: 77 | en: 78 | output: true 79 | languages: 80 | - zh-cn 81 | - en -------------------------------------------------------------------------------- /_posts/2021-10-25-Buddy-Mission-Bond.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2021-10-25 19:42 3 | head_image: e5df04a14afbaa3c83e134bc3090597b.png 4 | head_image_height: 1080 5 | head_image_width: 1920 6 | info: 《搭档任务 秘密搜查组》主题曲。 7 | last_modified_at: 2021-10-25 19:43 8 | tags: Switch 翻译 9 | title: 《Meteorite》歌词 10 | --- 11 | ## 原文 12 |
13 | Can you hear me? I've been singing a prayer for you and me 14 | 15 | Waiting for the meteorite to fall again and light up our world 16 | あなたに逢える日を 奇跡を 信じてる 17 | 18 | When the night comes I look up to the moonless sky from my bed 19 | 奇跡の流れ星 Why so far away? Why won't my wish come true? 20 | 21 | I never cry but I really miss your smile 22 | 暗い雲間を漂いながら I'm recalling our dear days and happiness you shared with me 23 | 24 | Waiting for the meteorite to fall again and light up our world 25 | あなたに逢える日を 奇跡を 信じてる 26 | 27 | When the sun comes, I'm gonna open up my hands 'cuz I will pray no more 28 | I will reach out for my future to see you 29 | 30 | Do you remember when I felt I lost myself 31 | そっと手と手を繋いだだけで All my tears dried away 'cuz you gave me hopes and dreams 32 | 33 | Let me be the meteorite if no more stars will fall from the sky 34 | あなたに逢いに行く 奇跡はもう待たない 35 | 36 | Won't you please call my name just like you used to? 37 | 光集めて舞い降りる I swear 38 |
39 | 40 | ## 译文 41 |
42 | 你能否听到我的声音?我一直为你我歌唱祈祷 43 | 44 | 等待陨石再次坠落照亮世界 45 | 我坚信与你相遇的那天是个奇迹 46 | 47 | 夜幕降临 我从床上仰望无月的天空 48 | 奇迹般的流星 为何如此遥远?为何我的愿望无法实现? 49 | 50 | 我从未哭泣 但我十分想念你的微笑 51 | 在黑暗的云间漂浮 我回想起你与我的亲密时光和欢声笑语 52 | 53 | 等待陨石再次坠落照亮世界 54 | 我坚信与你相遇的那天是个奇迹 55 | 56 | 太阳升起 我张开双手不再祈祷 57 | 我将在未来前去见你 58 | 59 | 你是否记得我曾迷失自我 60 | 只是轻轻地牵着手 我的眼泪就已干涸 因为你给了我希望和梦想 61 | 62 | 如果天空已不再有星星落下 就让我成为陨石 63 | 前去与你相见 不再等待奇迹 64 | 65 | 你能否像过去一样呼唤我的名字? 66 | 我将聚集光芒飞舞而下 我发誓 67 |
-------------------------------------------------------------------------------- /_includes/header.html: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /_posts/2024-11-02-Pokemon-Gen-4-Font-Patch.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2024-11-02 00:18 3 | head_image: https://raw.githubusercontent.com/Xzonn/PokemonGen4FontPatch/refs/heads/master/assets/images/social.png 4 | head_image_height: 384 5 | head_image_width: 768 6 | info: 显示中文。 7 | last_modified_at: 2024-11-03 12:07 8 | links: 9 | - - https://github.com/Xzonn/PokemonGen4FontPatch 10 | - 项目地址 11 | - - Pokemon-DP-Chinese-Localization-Based-on-Pret-Project.html 12 | - 基于pret项目的《宝可梦 钻石/珍珠》汉化 13 | tags: DS 作品发布 宝可梦 14 | title: 《宝可梦》第四世代字库扩容补丁 15 | --- 16 | 本项目用于对《宝可梦》第四世代游戏的字库进行扩容,以支持更多的汉字和符号。本补丁不包含汉化文本,如需汉化文本请使用**[《宝可梦》第四世代汉化修正补丁](/PokemonChineseTranslationRevise/)**。 17 | 18 | ## 这是什么? 19 | 20 | 这是《宝可梦》第四世代汉化修正补丁中与字库相关的部分,用于扩容游戏的字库以支持汉字。由于第四世代原版游戏的字库空间有限,而汉化所需的汉字在2000字以上,原有的可执行文件无法满足要求。因此,需要通过[修改可执行文件的方法]({% link _posts/2023-09-19-Pokemon-DP-Chinese-Localization-Based-on-Pret-Project.md %}),使其支持更大的字库。第五世代的日文版游戏提供了汉字版本,因此不再需要这个补丁。 21 | 22 | 这个补丁对于大多数人来说没有什么用,因为我制作好的修正补丁已经满足大多数人的需求了。但是有些人希望汉化其他语言版本的宝可梦游戏,这时就需要用到这个补丁了。 23 | 24 | **注意:本补丁并不一定适用于所有语言版本的游戏。如果基于[pret项目](https://github.com/pret)修改过代码,那么与字库相关的函数位置可能会发生改变。** 25 | 26 | ## 使用方法 27 | ### `arm9.bin` 补丁 28 | 29 | 1. 提取`arm9.bin`,可使用[ndstool](https://github.com/devkitPro/ndstool)或[CrystalTile2](https://www.romhacking.net/utilities/818/)。**注意:《心金/魂银》的`arm9.bin`被压缩过,需要对其进行解压缩。可使用[ndspy](https://github.com/RoadrunnerWMC/ndspy)或CrystalTile2自带的解压功能。** 30 | 2. 根据游戏版本和语言版本导航到对应的目录下,并对前一步提取的`arm9.bin`应用相应的IPS补丁,可使用[Lunar IPS](https://www.romhacking.net/utilities/240/)或[Rom Patcher JS](https://www.marcrobledo.com/RomPatcher.js/)。 31 | 3. 将`arm9.bin`重新导入游戏ROM,可使用ndstool或CrystalTile2。**注意:如果对《心金/魂银》的`arm9.bin`重新压缩,可能需要同步修改[arm9.bin中存储的文件大小](https://github.com/Xzonn/PokemonChineseTranslationRevise/issues/16)。** 32 | 33 | ### 字体补丁 34 | 35 | (二者选其一) 36 | 37 | 1. 根据游戏版本和语言版本导航到对应的目录下,采用[NitroPatcher](https://github.com/Xzonn/NitroPatcher)应用相应的XZP补丁。 38 | 2. 也可使用[PCTRTools](https://github.com/Xzonn/PCTRTools)自行创建字体并导入,但请确保使用[《宝可梦》第四世代汉化修正补丁所用的码表](https://github.com/Xzonn/PokemonChineseTranslationRevise/blob/master/files/CharTable.txt)。 39 | -------------------------------------------------------------------------------- /assets/css/style.scss: -------------------------------------------------------------------------------- 1 | --- 2 | --- 3 | :root { 4 | --author: xzonn; 5 | } 6 | 7 | // 1. Include functions first (so you can manipulate colors, SVGs, calc, etc) 8 | @import "../../node_modules/bootstrap/scss/functions"; 9 | 10 | // 2. Include any default variable overrides here 11 | @import "variables_override"; 12 | 13 | // 3. Include remainder of required Bootstrap stylesheets (including any separate color mode stylesheets) 14 | @import "../../node_modules/bootstrap/scss/variables"; 15 | @import "../../node_modules/bootstrap/scss/variables-dark"; 16 | 17 | // 4. Include any default map overrides here 18 | 19 | // 5. Include remainder of required parts 20 | @import "../../node_modules/bootstrap/scss/maps"; 21 | @import "../../node_modules/bootstrap/scss/mixins"; 22 | @import "../../node_modules/bootstrap/scss/root"; 23 | 24 | // 6. Optionally include any other parts as needed 25 | @import "../../node_modules/bootstrap/scss/utilities"; 26 | @import "../../node_modules/bootstrap/scss/reboot"; 27 | @import "../../node_modules/bootstrap/scss/type"; 28 | @import "../../node_modules/bootstrap/scss/images"; 29 | @import "../../node_modules/bootstrap/scss/containers"; 30 | @import "../../node_modules/bootstrap/scss/grid"; 31 | @import "../../node_modules/bootstrap/scss/helpers"; 32 | 33 | @import "../../node_modules/bootstrap/scss/alert"; 34 | @import "../../node_modules/bootstrap/scss/badge"; 35 | @import "../../node_modules/bootstrap/scss/buttons"; 36 | @import "../../node_modules/bootstrap/scss/card"; 37 | @import "../../node_modules/bootstrap/scss/forms"; 38 | @import "../../node_modules/bootstrap/scss/modal"; 39 | @import "../../node_modules/bootstrap/scss/nav"; 40 | @import "../../node_modules/bootstrap/scss/navbar"; 41 | @import "../../node_modules/bootstrap/scss/pagination"; 42 | @import "../../node_modules/bootstrap/scss/popover"; 43 | @import "../../node_modules/bootstrap/scss/tables"; 44 | @import "../../node_modules/bootstrap/scss/transitions"; 45 | 46 | // 7. Optionally include utilities API last to generate classes based on the Sass map in `_utilities.scss` 47 | @import "../../node_modules/bootstrap/scss/utilities/api"; 48 | 49 | // 8. Add additional custom code here 50 | @import "custom_styles"; 51 | @import "highlight"; 52 | @import "i18n"; 53 | @import "../../node_modules/bootstrap-icons/font/bootstrap-icons"; 54 | -------------------------------------------------------------------------------- /_posts/2019-11-20-How-to-Insert-Formulas-in-Wechat-Articles.md: -------------------------------------------------------------------------------- 1 | --- 2 | class: auto-numbering 3 | date: 2019-11-20 12:00 4 | head_image: https://mmbiz.qpic.cn/mmbiz_jpg/Qh7FH95PRnuloHxksOxTetZaQtOicZ5boXOu9szzEziaUHWtyO0PeHg3PB5xv1oWUlVfib6ITYKhqpkia3CuEpma9w/0 5 | head_image_height: 544 6 | head_image_width: 1280 7 | info: 用截图插入公式,或许不是优雅的选择。 8 | last_modified_at: 2022-01-05 14:23 9 | tags: 技术指南 10 | title: 如何在微信推送中优雅地插入公式 11 | wechat_link: https://mp.weixin.qq.com/s/mYzdirgQjLwqXrfpri8lgw 12 | --- 13 | 14 | ## 前言 15 | 推送讲座早在 10 月 19 日就举办过了,但是一直没有出总结。最近趁着我自己开了个公众号,我也抽出一点时间把讲座的内容整理一下,以方便广大没能来听讲座的朋友们。 16 | 17 | 这次讲座的视频: 18 | 19 | {% include video.html aid="71734762" page="1" %} 20 | 21 | 这次讲座的资料: 22 | 23 | 24 | 25 | 在培训时,我留下了一个技术难题:如何在微信推送中插入公式?当时我并没有得出很好的解决方法,唯一的方法就是——截图。但是,当我偶然网上冲浪时,才发现了插入公式的(或许是最佳的)解决方案。 26 | 27 | ## 排版工具的新选择——Markdown Nice 28 | 对于微信推送,网络上有许多排版工具。 29 | 30 | 最简单的排版工具就是微信自带的排版工具,其功能大多都是基础功能,适合喜欢自己创作的高端玩家。另外,由于微信自带的排版工具是富文本编辑,因此可以直接从别的排版工具复制粘贴过来。 31 | 32 | 我个人使用的排版工具就是“[秀米](https://xiumi.us/)”,这也是我大一刚入学的时候就从前学术部部长观音姐姐那里学到的。本公众号最近的几篇文章也都是用秀米排版的。秀米为用户提供了各种各样的模板,既有基础模板可供创作发挥,也有已经修饰过的模板可直接使用,而且还会根据不同的时间提供最新的时令模板。对于个人公众号和环院学生会公众号来说绰绰有余了。 33 | 34 | 但是今天我要介绍的主角不是秀米,而是我在整理资料的时候发现的另一个排版工具:[Markdown Nice](https://www.mdnice.com/)。它使用Markdown语法进行编辑,其预览结果可以直接复制粘贴到微信自带的排版工具中,适合那些喜欢Markdown做笔记写文章的朋友。最重要的是,它可以直接输入公式,并复制粘贴到微信自带的排版工具中。而且,渲染出的公式是svg矢量图,无论如何缩放都不会糊,目前来看是我能找到的最佳解决方式。 35 | 36 | {% include figure.html src="bd1a2f87762fdabdcf277e8433bf0c94.png" alt="Markdown Nice公式渲染示例" width="640" height="480" %} 37 | 38 | 我个人认为,这个排版工具的显示效果还是不错的。那么问题来了:公式要如何输入呢? 39 | 40 | ## 公式的输入方式 41 | 如所示,Markdown Nice中的公式需要放在美元符号“\$”之间,若为一个美元符号“\$”则是行内公式(即文字和公式在同一行),若为两个美元符号“\$\$”则是块公式(即公式单独成行并居中)。而美元符号之间的代码则是通过“MathJax”渲染的,其语法类似于TeX,但并不完全相同。如果你有TeX输入公式的基础,那么上手MathJax并不算难。MathJax中可使用的TeX命令可在如下网页中找到: 42 | 43 | 当然,对于完全没有学过TeX语法(而且可能也不想学)的朋友,其实还有一些比较简单的方法。 44 | 45 | 参见:[何在Word中修改公式字体]({% link _posts/2022-01-05-How-to-Beautify-Formulas-in-Word.md %}#tex公式的获取) 46 | 47 | ## 后记 48 | 虽然写了这么多,但是我觉得在公众号中输入公式可能不是什么硬性需求(或许也就是学生会学术部的“环迹”等栏目需要吧)。当然,如果我之后分享学习资料的话也不会选择直接输入公式,而是会分享截图或者pdf文件。 49 | 50 | 最后送给大家一句话:Practice makes perfect, 熟能生巧,只看不练永远是学不会的。 -------------------------------------------------------------------------------- /_posts/2025-06-12-Premiere-Pro-Color-Range.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2025-06-12 21:02 3 | info: 没研究出来如何让Premiere Pro导出Full色彩范围的视频。 4 | last_modified_at: 2025-06-12 22:21 5 | tags: 杂记 6 | title: Premiere Pro中的颜色范围(Color Range)的失败记录 7 | --- 8 | 最近我做视频一直在用Premiere Pro + Voukoder Pro的组合,一直没发现问题,直到我今天做了一个白色背景、黑色文字的视频导出后,才发现视频有很严重的偏色。右键打开视频一看,色彩范围是Limited而不是Full,这就导致了视频的色彩范围被压缩,白色(255)变成了灰色(235),黑色(0)变成了灰色(16)。于是,我就开始寻找解决方法。 9 | 10 | {% include figure.html src="c03d1247ce2552f1af5f44e4b04c7770.webp" width="640" height="180" alt="原图(左)与导出后的视频截图(右)颜色对比" %} 11 | 12 | ## 检查Voukoder Pro的设置 13 | 14 | 先介绍一下[Voukoder Pro](https://www.voukoder.org/),这是一个导出视频和音频的工具,可以与Premiere Pro等视频编辑软件配合使用。它支持多种编码格式和导出选项。相较于Premiere Pro自带的导出功能,Voukoder Pro提供了更多的自定义选项。 15 | 16 | 我所用的编码设定是NVENC AV1,因为我现在所用的显卡支持AV1硬编码。在Voukoder Pro的设置中,我强制设置了输入的色彩范围为“Full”,按理来说应该是没问题的才对。 17 | 18 | {% include figure.html src="fd3d0a6cdaf0c63a8943c0c1938f9667.webp" width="379" height="444" alt="Voukoder Pro视频输入设置" %} 19 | 20 | 难不成是NVENC AV1的编码器设置有问题?然而我在NVENC AV1的设置中并没有找到与色彩范围相关的选项。我甚至用IDA Pro查看了一下Voukoder Pro的二进制文件,发现它并没有直接处理色彩范围,而是将色彩范围的设置传递给了FFmpeg。在配置文件(`%LOCALAPPDATA%\VoukoderPro\scenes.json`)种有如下设置: 21 | 22 | ``` json 23 | { 24 | "rc": "constqp", 25 | "qp": 23, 26 | "g": 60, 27 | "bf": 0, 28 | "multipass": 2 29 | } 30 | ``` 31 | 32 | 这些参数是直接传给FFmpeg的,而FFmpeg的色彩范围设置是通过`-color_range`参数来控制的。Voukoder Pro并没有在配置文件中显式设置这个参数。既然如此,我就尝试在Voukoder Pro的设置中添加`"color_range": "full"`,然后重新导出视频。结果很意外,虽然视频的色彩范围变成了“Full”,但是偏色更严重了: 33 | 34 | {% include figure.html src="dec6c48c159aa5959d4608692035020e.webp" width="320" height="180" alt="手动添加参数之后的视频截图" %} 35 | 36 | 白色从255变成了218,黑色从0变成了30,显然这应该是又经历了一次色彩范围的压缩。这是怎么回事呢? 37 | 38 | ## 检查Premiere Pro的设置 39 | 40 | 既然如此,试试Premiere Pro自带的导出功能吧。我使用了Premiere Pro自带的HEVC编码,勾选了“以最大深度渲染”“使用最高渲染质量”,配置文件选择了“主配置 10”,色彩空间选择了“Rec. 709”。导出设置中并没有找到色彩范围的选项。打开导出后的视频,发现偏色问题解决了,然而色彩范围仍然是“Limited”。 41 | 42 | {% include figure.html src="fe0ee00d2c2fb8bccc0bf7f572ccb2b6.webp" width="320" height="180" alt="使用Premiere Pro自带的HEVC编码器导出的视频截图" %} 43 | 44 | 这下看明白了,Premiere Pro输出的视频流的色彩范围就是“Limited”,如果强制在Voukoder Pro中设置为“Full”,反而会导致色彩范围被压缩。将视频输入中的色彩范围设置为“Auto”并删去手动添加的参数之后,视频偏色问题解决了,但色彩范围还是“Limited”。 45 | 46 | 我尝试用Google搜索、ChatGPT和DeepSeek等AI工具提问,都没有找到能让Premiere Pro导出“Full”色彩范围视频的解决方案。 47 | 48 | ## 结语 49 | 50 | 目前看来,Premiere Pro导出的视频色彩范围只能是“Limited”,如果需要“Full”色彩范围的视频,可能需要使用其他工具或编码器。Voukoder Pro虽然提供了更多的自定义选项,但受限于Premiere Pro提供的视频流,它在处理色彩范围时似乎并没有提供足够的灵活性。 51 | -------------------------------------------------------------------------------- /_posts/2024-07-10-Persona-Q2-Chinese-Localization.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2024-07-10 11:38 3 | head_image: 5c52b3c327fc15bb18174c55784b4787.webp 4 | head_image_height: 480 5 | head_image_width: 1200 6 | info: 格式复杂。 7 | last_modified_at: 2024-07-28 14:23 8 | tags: 3DS Atlus 汉化笔记 9 | title: 《女神异闻录Q2 迷宫电影院》汉化笔记 10 | --- 11 | 《女神异闻录Q2 迷宫电影院》(简称“PQ2”)发售以来已经将近6年了,这期间一直没有汉化。最近经人介绍,我参考了前辈们的经验,研究了一下本作的文件结构,在这里也分享一下我的经验。 12 | 13 | {% include video.html bvid="BV15m421V7Bt" title="3DS《女神异闻录Q2 新电影迷宫》汉化预览" %} 14 | 15 | ## 拆包/打包 16 | 3DS游戏的拆包其实没什么难的,一般情况下要完成汉化只需要修改romfs里的文件,而romfs使用Citra模拟器就能提取,然后只需要利用Luma的重定向补丁功能即可。当然,之所以我说是“一般情况”,是因为本作属于“不一般情况”——首先,部分文本是在可执行文件(`code.bin`)中的,而可执行文件位于exefs里,Citra提取不了,还是需要[3dstool](https://github.com/dnasdw/3dstool)。 17 | 18 | 除此之外,可能是为了节省空间,romfs里只有3个cpk文件,这是Criware的打包格式。这3个文件分别是`data.cpk`、`patch101.cpk`和`patch102.cpk`,其中`data.cpk`是游戏本体,而`patch101.cpk`和`patch102.cpk`是更新文件。更新文件中包含的文件会覆盖游戏本体的文件,而游戏本体有2 GiB以上,更新文件只有几个MiB,所以很容易就想到,可以先把所有的cpk解包,然后筛选需要汉化的文件,修改后统一放到更新文件里,最后再打包,这样可以减小打包的工作量。 19 | 20 | 到这里还算简单,而且打包好的文件放在Citra的补丁文件夹中也能被正常识别,但是——实机运行会死机。分析了一下,既然Citra能运行,说明整个流程是没有问题的;而实机运行会死机,推测是修改后的文件太大了,导致了某种内存溢出。所以,对于实际运行,似乎只能放弃这种方法,改为把所有的文件都放到游戏本体里,然后打包。 21 | 22 | ## 字库 23 | 本作的字库是3DS游戏常见的`.bcfnt`文件格式,这个文件格式处理起来都有现成的工具,我选用了[3dstools](https://github.com/ObsidianX/3dstools),因为这个工具是拿python写的,修改起来比较方便。只不过游戏使用的编码方案是Shift-JIS,而3dstools默认是UTF-16-LE,所以需要稍微修改一下。 24 | 25 | 在字体方面,原版的字体选用了Fontworks公司开发的[ハミング](https://fontplus.jp/font-list/hummingstd-b)系列字体,而方正字库恰好和Fontworks合作开发了[方正FW轻吟体](https://www.foundertype.com/index.php/FontInfo/index/id/4985),可以直接拿来用。略微有些美中不足的就是,方正FW轻吟体的部分字形仍然是日本标准,例如“今”中的点是横着写的,而大陆标准是从左上到右下的点。 26 | 27 | ## 文本/图片 28 | 本作的文本可谓是地狱。这些文本以不同的格式分散在了不同的文件里,而每个文件的后缀名和打包方式也不完全一样,修改起来非常费力。 29 | 30 | 最初我参考了[lraty-li](https://github.com/lraty-li)的方法,采用[Atlus-Script-Tools](https://github.com/tge-was-taken/Atlus-Script-Tools)对游戏脚本反编译后,修改文本再重新编译。但是这样会遇到一些问题——部分脚本反编译出来的结果有问题,无法被重新导入。之后我分析了文件结构,发现并不需要做反编译这件事——因为我所需要的只是修改文本,而不用修改游戏的逻辑。因此,我改用了[PersonaEditor](https://github.com/Meloman19/PersonaEditor),这个工具可以直接修改文本,而不用反编译。 31 | 32 | 除此之外,PersonaEditor还提供了对归档文件解包/打包的功能,这对于汉化来说也很有帮助。前文已经说过,有些文本是被打包进了归档文件中,而通过PersonaEditor遍历文件夹下的文件,可以方便地提取需要编辑的文本,同时也可以导出需要修改的图片。不过,PersonaEditor对于PQ2文件格式的支持不完全,cgfx、ctpx和spr3格式无法支持。而我又懒得重头开始写工具处理,因此我又引用了[Kuriimu](https://github.com/IcySon55/Kuriimu)的库,对这些格式进行处理。 33 | 34 | 当然,还有一些文本是硬编码在`code.bin`里的,还有一些特殊格式的文件,这些文件都可以用python来处理。 35 | 36 | ## 总结 37 | 总结一下,本作的汉化工作主要分为以下几个步骤: 38 | 39 | - 解包`patch102.cpk`,作为补丁包的基底。 40 | - 采用修改后的PersonaEditor提取需要编辑的文本和图片,并用python脚本处理其他格式的文件。 41 | - 根据已翻译的文本生成字库,同时生成简体中文汉字到Shift-JIS的映射表。 42 | - 根据映射表导入文本。 43 | - 导入图片。 44 | - 将修改后的文件与`patch102.cpk`中原有的文件一起打包,生成补丁。 45 | -------------------------------------------------------------------------------- /_posts/2022-09-04-Take-and-Save-a-Screenshot-on-a-Windows-PC-with-Joy-Con.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2022-09-04 15:53 3 | head_image: 72680fb66a9297a84f962648bec1c0fd.jpg 4 | head_image_height: 1080 5 | head_image_width: 1920 6 | info: 一键完成。 7 | last_modified_at: 2022-09-04 21:07 8 | tags: Switch Windows 作品发布 9 | title: 用Joy-Con在Windows电脑上捕获并保存截图 10 | --- 11 | 简而言之,[JoyConScreenShot](https://github.com/Xzonn/JoyConScreenShot)软件通过调用Xbox Game Bar软件,可以在按下Joy-Con的截图键时捕获当前运行的游戏或软件的截图并保存,或录制之前30秒的视频。 12 | 13 | 为方便介绍,除非另有说明,本文的“Joy-Con”均同时包含Switch Pro手柄。 14 | 15 | ## 灵感来源 16 | 在Nintendo Switch和Steam平台上都有“一键截图”功能,只需按下Joy-Con手柄或是Switch Pro手柄的“截图”键就可以直接截图并保存下来,非常方便,而Switch上甚至可以长按截图键录制之前30秒的游戏视频。然而最近我接触了Windows电脑上的Xbox游戏(准确来说应该是Microsoft Store应用),却发现这些游戏无法识别Joy-Con手柄和Switch Pro手柄;Steam虽然可以将这些游戏作为“非Steam游戏”添加并启动,但无法像普通的Win32游戏一样映射手柄按键和提供截图功能。 17 | 18 | 手柄按键映射比较好解决,例如[BetterJoy](https://github.com/Davidobot/BetterJoy)、[XJoy](https://github.com/DuroSoft/XJoy)都可以将Joy-Con映射为一个虚拟的Xbox 360手柄;但截图功能的实现就比较复杂了。虽然Windows 10系统自带了[“截图和草图”](https://apps.microsoft.com/store/detail/snipping-tool/9MZ95KL8MR0L)软件,按`PrintScreen`键就可以调出,但调出后仍需要选择截图范围,无法一键实现“截图&保存”功能,在打游戏的时候非常不方便。 19 | 20 | 好在,Windows 10系统还包含了一个[“Xbox Game Bar”](https://apps.microsoft.com/store/detail/xbox-game-bar/9NZKPSTSNW4P)软件,默认按`Windows + G`键可以调出,有些类似于Steam的游戏内按`Shift + Tab`调出的界面。这个软件可以通过`Windows + Alt + PrintScreen`键捕获活跃窗口的截图并直接保存,且可以通过`Windows + Alt + G`键录制之前30秒的视频(初次使用可能需要设置)。加上BetterJoy和XJoy都是开源软件,只需要研究一下源代码就可以明白是如何读取Joy-Con的输入并映射成虚拟手柄的。因此想到,可以通过监听Joy-Con的截图键,当截图键按下时间较短时模拟`Windows + Alt + PrintScreen`键捕获截图,按下时间较长时模拟`Windows + Alt + G`键录制视频。 21 | 22 | ## 解决方案 23 | 首先需要了解软件是如何读取Joy-Con的输入的。Joy-Con手柄可以通过蓝牙与Windows电脑连接,然后被识别为HID设备(人体学接口设备)。HID的相关处理使用了[HidLibrary](https://github.com/mikeobrien/HidLibrary)。每个设备均具有制造商ID(Vendor ID)和产品ID(Product ID),而Joy-Con的制造商为任天堂,其制造商ID为`0x057e`,产品ID为`0x2006`(左Joy-Con)、`0x2007`(右Joy-Con)、`0x2009`(Switch Pro手柄)。通过遍历所有HID设备并比对制造商ID和产品ID可以筛选出所有Joy-Con。 24 | 25 | Joy-Con的状态可以通过读取设备信息来获取。GitHub上有对Nintendo Switch的逆向分析,名为[“Nintendo_Switch_Reverse_Engineering”](https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering),其中具体介绍了Joy-Con作为HID设备的数据格式及其含义,详情可以[在此链接](https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering/blob/master/bluetooth_hid_notes.md)查看。按键的相关数据在标准报告的第4字节的`0x20`(`0b00100000`)位,只需读取这一位的数据即可。另外需要注意的是ID为`0x3f`的报告数据结构与标准报告不同,其按键数据为第2字节。 26 | 27 | 在获取到按键状态后,就可以模拟Windows的按键了。按键相关处理使用了[WindowsInput](https://github.com/MediatedCommunications/WindowsInput)。根据按键时间的不同,对按键较短(0.8秒以内)的情况视为捕获截图,按下`Windows + Alt + PrintScreen`键;按键较长的情况视为捕获视频,按下`Windows + Alt + G`键。 28 | 29 | ## 源代码 30 | [JoyConScreenShot](https://github.com/Xzonn/JoyConScreenShot),按[GPL-3.0](https://github.com/Xzonn/JoyConScreenShot/blob/master/LICENSE.md)授权。 -------------------------------------------------------------------------------- /_posts/2022-01-11-Automate-Portrait-Keying-in-OBS-without-Green-Screen.md: -------------------------------------------------------------------------------- 1 | --- 2 | class: auto-numbering 3 | date: 2022-01-11 09:56 4 | head_image: 92d8a2e6743c175fb8753b2a69fac79b.png 5 | head_image_height: 1141 6 | head_image_width: 1623 7 | info: 利用腾讯会议的“虚拟背景”功能,无绿幕零成本自动抠人像。 8 | last_modified_at: 2022-02-14 17:12 9 | tags: Windows 技术指南 10 | title: 在OBS中不使用绿幕完成自动抠人像 11 | --- 12 | 在使用[OBS](https://obsproject.com/)直播或录屏的时候,有时会有主播出镜的需求。为了避免人像的背景对视频其他内容产生干扰,自动抠人像便非常有必要。传统的抠人像方法是在人物背后放置一张绿幕,然后使用颜色键将背景去除设为透明,但这需要购买并设置绿幕,比较麻烦。好在,借助[腾讯会议](https://meeting.tencent.com/)等软件的虚拟背景功能,与OBS相结合,可以达到无绿幕零成本自动抠人像的效果。 13 | 14 | ## 设置腾讯会议 15 | 腾讯会议在疫情期间被广泛用作会议、上课等用途,而“虚拟背景”是该软件提供的一个功能,可以自动识别摄像头捕捉到的人物面部,然后去除多余的背景。恰好这一功能是免费的,只需设置一下就可以被OBS所利用。 16 | 17 | 腾讯会议的安装比较简单,在[官网](https://meeting.tencent.com/)下载后按照说明安装即可。安装完毕后打开,按照提示登录,然后点击初始界面右上角的齿轮图标进入设置,选择“虚拟背景和美颜”,然后自定义图片为纯绿色的图片即可。如果找不到的话,可以用我这张图: 18 | 19 | {% include figure.html src="f13b001cc7b4090cab1c604b01902835.png" alt="纯绿色的图片" width="640" height="360" %} 20 | 21 | 设置完毕后,就可以在预览画面中看到背景为绿色的人像。 22 | 23 | {% include figure.html src="44eb59803e3d68366ecb66fcdad0b8b4.png" alt="设置完成后的预览效果" width="640" height="553.7" %} 24 | 25 | 这个视频预览窗口可能无法被OBS正常读取,因此可以使用“快速会议”功能,创建一个只有自己的会议。此时需要打开摄像头(可以不打开麦克风),在窗口中会显示人像和绿色的背景,此时腾讯会议的设置就完成了。 26 | 27 | {% include figure.html src="ac38e47e392037678e8f8d63da699ad0.png" alt="创建快速会议" width="640" height="426.7" %} 28 | 29 | 为了减少之后的工作量,请尽可能不要开启腾讯会议中其他的功能,以免后续设置OBS时窗口出现问题。同样,请不要让腾讯会议的窗口最小化。 30 | 31 | ## 设置OBS 32 | OBS的安装也比较简单,同样可以在[官网](https://obsproject.com/)下载然后按照说明安装。初次使用时会弹出安装向导,可以根据自己的需求(直播或是录屏)进行设置。 33 | 34 | 设置完成后,在左下角的“来源”区添加一个“窗口采集”,然后选择“新建”,命名为自己喜欢的名字。 35 | 36 | {% include figure.html src="6814d83a116a98d3938693e0ff2cf354.png" alt="添加窗口采集" width="640" height="449.9" %} 37 | 38 | {% include figure.html src="9c8ecf15d6f96f2ae2f11760ad28f7d8.png" alt="新建来源" width="532" height="517" %} 39 | 40 | 在窗口中选择“腾讯会议”,取消勾选“显示鼠标指针”,然后确认。 41 | 42 | {% include figure.html src="568ed120fe967976f819a1e0f49b8e48.png" alt="添加腾讯会议" width="640" height="504.8" %} 43 | 44 | 为了去除腾讯会议的UI,需要对画面进行裁剪,方法是对OBS预览中的该区域点击右键,选择“变换”→“编辑变换”,然后输入裁剪范围。我推荐的数值是:左右300,上下100。 45 | 46 | {% include figure.html src="58f7513e14e12247f08b11dc5e822d1c.png" alt="选择编辑变换" width="640" height="449.9" %} 47 | 48 | {% include figure.html src="64d3683ed225f2192ef2f7755438b1f3.png" alt="输入裁剪范围" width="640" height="449.9" %} 49 | 50 | 完成后确认,然后再次右键,选择“滤镜”,添加“色度键”,其默认值即为“绿色”。 51 | 52 | {% include figure.html src="8d8df8884eee574685afcf560916cce8.png" alt="添加色度键" width="640" height="560.5" %} 53 | 54 | 完成后确认,画布中就会出现包含透明背景的人像了。然后根据需要添加其他源(如显示器采集、窗口采集、视频采集设备)等,即可开始直播或录屏。 55 | 56 | {% include figure.html src="92d8a2e6743c175fb8753b2a69fac79b.png" alt="自动抠人像效果" width="640" height="449.9" %} -------------------------------------------------------------------------------- /_posts/2020-02-17-Danmaku-Wall.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2020-02-17 19:48 3 | info: 宗旨:让使用电脑全屏演示的老师能够与同学们实时互动。 4 | last_modified_at: 2020-08-02 11:24 5 | tags: 作品发布 技术指南 6 | title: 酷Q 弹幕墙插件 7 | wechat_link: https://mp.weixin.qq.com/s/kskgb-AIWp0rVEEhn3i4KA 8 | --- 9 | 10 | 11 | ## 前言 12 | 13 | 今天(2020/02/17)是北大2020年春季学期开学的日子,由于疫情影响,大部分课采取了网络教学的方式。但我在上课的时候发现,当老师全屏演示的时候,他将无法及时看到同学们情况的反馈。正好我想到我曾经开发过的酷Q弹幕墙插件,而且上学期结束时也有老师问我能不能在这学期开课的时候尝试用弹幕墙增加同学们的互动热情,因此我在今晚略微修改了一下代码以适应教学需求,同时写下这篇文档帮助想要使用的老师快速掌握用法。 14 | 15 | {% include figure.html src="7440dcaa115def87d2f67498b7d8c5de.png" alt="弹幕墙预览" width="640" height="360" %} 16 | 17 | ## 准备工作 18 | 19 | - 本插件基于酷Q,这是一个与QQ相关的软件,因此使用者需要先[注册一个可以正常使用的QQ号](https://zc.qq.com/chs/index.html)。为降低风险,可以注册一个新的账号专门供弹幕墙使用。 20 | - 在手机或电脑的QQ或TIM软件上,设置验证方式为“允许任何人”或“需要正确回答问题”。 21 | - 手机QQ的设置方式:“设置”→“隐私”→“加我为好友时的验证设置”→“允许任何人”或“需要正确回答问题”。 22 | - 电脑QQ的设置方式:“设置”→“权限设置”→“防骚扰”→“请选择适合你的验证方式”→“允许任何人”或“需要正确回答问题”。 23 | - *(可选)创建一个QQ群,所有发送弹幕者加入该群,并记住群号。* 24 | 25 | ## 下载地址 26 | 27 | - 北大网盘:。 28 | - GitHub:。(仅包含插件) 29 | 30 | 如果您之前**没有使用过**酷Q,可以直接从北大网盘下载“弹幕墙(已包含酷Q).zip”文件,解压后即可使用。 31 | 32 | 如果您之前**使用过**酷Q,可以仅下载插件,并按照压缩包中的说明将插件保存在相应位置。 33 | 34 | ## 使用方式 35 | 36 | ### 1. 打开插件 37 | 38 | {% include figure.html src="ec5600ec1bb076b8952116bf3f724493.png" alt="应用管理页面" width="595" height="453" %} 39 | 40 | 将压缩包解压,双击“酷Q Air”文件夹下的“CQA.exe”运行程序,输入QQ号和密码登录。 41 | 42 | 登录成功后,右键单击右下角任务栏的“酷Q Air”图标(![酷Q Air\|none](9c5c16e5a127a8aaaaf72bf79faebe0d.png)),选择“应用”→“应用管理”。 43 | 44 | 在弹出的窗口中选中“QQ 弹幕墙”(未开启时应为灰色),然后在右侧选择“启用”。 45 | 46 | *(此处建议将其它插件均设为“禁用”,以防冲突。)* 47 | 48 | 如果屏幕上方飘过“弹幕墙已经开启!”,说明开启成功。 49 | 50 | 如果软件卡死,请尝试删除配置文件,或重新下载本插件。 51 | 52 | ### 2. 设置 53 | 54 | {% include figure.html src="37ce589316b8676c6e7ec9e2ffd2e918.png" alt="设置页面" width="382" height="277" %} 55 | 56 | 在右侧的“菜单”→“设置”中可以设置管理员(输入QQ号)、需要显示弹幕的QQ群(QQ群号)、是否显示图片、是否显示昵称,也可查看帮助文档。 57 | 58 | 目前管理员的权限仅有显示、关闭、清屏三种。输入指令的方式为“# *<指令>*”,如: 59 | 60 | ``` 61 | # 显示 62 | # 关闭 63 | # 清屏 64 | ``` 65 | 66 | 如果设置了需要显示弹幕的QQ群,那么该群中的所有信息都会被显示出来。 67 | 68 | ### 3. 发送者使用方式 69 | 70 | 有两种使用方式: 71 | 72 | - 直接向弹幕墙开启的QQ号发送私信。 73 | - 在上述第2步设置的QQ群中发送消息。 74 | 75 | ## 其它 76 | 77 | 本插件基于[酷Q](https://cqp.cc/),及其开发SDK:[Native.Framework](https://github.com/Jie2GG/Native.Framework)。 78 | 79 | 本插件开放源代码,地址:。 80 | 81 | 如有使用方面的问题,可在本页面下方的[留言区](#xz-content-comment)中留言,或在GitHub上[提交Issue](https://github.com/Xzonn/DanmakuWall/issues)。 82 | 83 | -------------------------------------------------------------------------------- /_includes/footer.html: -------------------------------------------------------------------------------- 1 | 2 | 6 | 29 | 30 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /assets/js/tags.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /* global $ */ 3 | const lang_default = "zh-cn"; 4 | const i18n = { 5 | "zh-cn": { 6 | "tag-all": "全部", 7 | }, 8 | "en": { 9 | "tag-all": "ALL", 10 | }, 11 | }; 12 | 13 | window.addEventListener("load", () => { 14 | const lang = document.body.lang || document.querySelector("html").lang || lang_default; 15 | const t = function (key, _lang = lang) { 16 | return (i18n[_lang] || i18n[lang_default])[key] || i18n[lang_default][key] || key; 17 | } 18 | 19 | /* 手动生成各标签 */ 20 | let tags_dict = {}; 21 | let lines = Array.from($(".xz-postlist > tbody > tr")).map((x) => x.dataset["tags"].split(" ")); 22 | lines.forEach((line) => { 23 | line.forEach((tag) => { 24 | tags_dict[tag] = (tags_dict[tag] || 0) + 1; 25 | }); 26 | }); 27 | let tags = Object.keys(tags_dict); 28 | tags.sort((a, b) => tags_dict[b] - tags_dict[a]); 29 | $(".xz-taglist") 30 | .empty() 31 | .append( 32 | $("
  • ") 33 | .addClass("nav-item") 34 | .attr({ 35 | id: "tag-", 36 | "data-sort": lines.length, 37 | }) 38 | .html(`${t("tag-all")} ${lines.length}`) 39 | ); 40 | tags.forEach((tag) => { 41 | if (!tag) return; 42 | let tag_count = tags_dict[tag]; 43 | $("
  • ") 44 | .addClass("nav-item") 45 | .attr({ 46 | id: `tag-${tag}`, 47 | "data-sort": tag_count, 48 | }) 49 | .html(`${tag} ${tag_count}`) 50 | .appendTo($(".xz-taglist")); 51 | }); 52 | 53 | /* 标签页处理 */ 54 | let handleHashChange = (e) => { 55 | if (e) e.preventDefault(); 56 | let hash = decodeURIComponent(location.hash).slice(1); 57 | $(".xz-taglist > li > a").removeClass("active"); 58 | $(`#tag-${hash} > a`).addClass("active"); 59 | if (hash) { 60 | $(".xz-postlist > tbody > tr").each((i, row) => { 61 | if ( 62 | $(row) 63 | .find(".post-tag-simp") 64 | .toArray() 65 | .some((x) => x.innerText == hash) 66 | ) { 67 | $(row).show(); 68 | } else { 69 | $(row).hide(); 70 | } 71 | }); 72 | } else { 73 | $(".xz-postlist > tbody > tr").show(); 74 | } 75 | window.windowScroll(); 76 | }; 77 | 78 | $(".xz-taglist > li") 79 | .sort((a, b) => b.dataset.sort - a.dataset.sort) 80 | .detach() 81 | .appendTo($(".xz-taglist")); 82 | window.addEventListener("hashchange", handleHashChange); 83 | handleHashChange(); 84 | $(".xz-taglist").addClass("show"); 85 | $(".xz-postlist").addClass("show"); 86 | }); 87 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | --- 2 | i18n: true 3 | i18n_en: /posts/ 4 | js: posts 5 | no_comment: true 6 | no_sidenav: true 7 | title: 欢迎来到 Xzonn 的小站! 8 | --- 9 |

    导航

    10 | 18 | 清除缓存 19 |

    文章一览

    20 |
    21 | 22 | 23 | 24 | 25 |
    26 |
    27 |
    本站共有 篇文章,共 页。
    28 |
    29 |
    30 |
      31 |
      32 |
      33 |
      34 | 页码: 35 | 36 | 37 |
      38 |
      39 |
      -------------------------------------------------------------------------------- /_posts/2019-01-18-Pokemon-Surf-Glitch.md: -------------------------------------------------------------------------------- 1 | --- 2 | class: auto-numbering 3 | date: 2019-01-18 21:03 4 | head_image: b165db3b8779b7b7a651765b992fd48b.png 5 | head_image_height: 384 6 | head_image_width: 256 7 | infobox: pokemon pokemonGlitch 8 | last_modified_at: 2020-01-03 23:02 9 | tags: DS 任天堂 宝可梦 10 | title: 《精灵宝可梦》四天王房间冲浪漏洞 11 | --- 12 | {% include figure.html src="b165db3b8779b7b7a651765b992fd48b.png" alt="漏洞触发后的效果" width="256" height="384" %} 13 | 14 | ## 概述 15 | **四天王房间冲浪漏洞**是存在于第四世代《精灵宝可梦》系列游戏《钻石/珍珠》日本发行版中的游戏漏洞。此漏洞在海外发行版和《精灵宝可梦 白金》中被修复。该漏洞被任天堂官方称为“壁の中から戻れなくなる”,即“无法从墙壁内返回”,并在当时[提供了免费修复的服务](https://www.nintendo.co.jp/ds/adaj/info/index.html)(服务已于 2018 年 2 月结束)。 16 | 17 | ## 触发方式 18 | 在四天王的房间入口,玩家可以对门使用冲浪招式。而玩家向下移动一格后,将会解除冲浪状态,玩家会走出地图外。此时按照一定的操作移动,可能会使玩家移动到其它地图,从而触发一些事件。例如:跳过四天王和冠军直接登入名人堂,前往新月岛收服达克莱伊,或是前往花之乐园收服谢米。 19 | 20 |

      注意:如果出现移动错误,可能会卡在“谜之空间”中,因此触发前请备份存档,并在移动过程中使用计步器。

      21 | 22 | ### 前往新月岛 23 | 使用冲浪招式出门后,依次按照以下方式移动:右 146 步,下 254 步。使用探险套装后返回地面,或存档后重启。向左进入深处可遇到达克莱伊。捕捉完毕后,可乘船返回。[[3](#ref-3)] 24 | 25 | 由于官方从未向《钻石/珍珠》配信“会员卡”道具,即两作中没有正常途径可以捕捉到达克莱伊,因此通过此漏洞获得的达克莱伊不合法。下文所述的谢米同理。 26 | 27 | 参考视频: 28 | 29 | {% include video.html aid="35191961" page="1" %} 30 | 31 | ### 前往花之乐园 32 | 使用冲浪招式出门后,依次按照以下方式移动:右 904 步,下 363 步。使用探险套装后返回地面,或存档后重启。此时向上一格可到达分海之路,向上一直走可到达花之乐园遇到谢米。[[4](#ref-4)] 33 | 34 | 参考视频: 35 | 36 | {% include video.html aid="35191961" page="2" %} 37 | 38 | ### 登入名人堂 39 | 使用冲浪招式出门后,从房间外绕到房间上方。在门的上方清空计步器,然后向上走64步,保存并重启。重启后,向任意方向移动,会触发与竹兰的对话。对话结束后,玩家登入名人堂。[[5](#ref-5)] 40 | 41 | 参考视频: 42 | 43 | {% include video.html aid="35192217" page="1" %} 44 | 45 | ## 说明 46 | 此漏洞的触发与地图图块漏洞都进入了“**谜之场所**”(日文:**なぞの場所**,英文:**Mystery Zone**)。该区域是第四世代游戏未使用的区域。在正常情况下,由于地图边界的限制,玩家无法前往这些区域。但是,由于漏洞的存在,玩家可以越过地图边界进入谜之场所并在其中移动,因而可以进入正常情况下无法进入的地图。 47 | 48 | ## 参考资料 49 | 1. 神奇宝贝百科. 冲浪(漏洞)[OL]. (2018-11-29) [2019-01-18]. . 50 | 2. Bulbapedia. Surf glitch[OL]. (2018-07-24) [2019-01-18]. . 51 | 3. Crystalmourne. Tweaking/Void Glitch: Darkrai with Surf Glitch (JAPANESE ONLY)[OL]. (2014-08-16) [2019-01-18]. . 52 | 4. Crystalmourne. Tweaking/Void Glitch: Shaymin with Surf Glitch (JAPANESE ONLY)[OL]. (2014-08-16) [2019-01-18]. . 53 | 5. ChickasaurusGL. Skipping the Elite Four - Elite Four door glitch methods (Diamond/Pearl JP)[OL]. (2016-08-22) [2019-01-18]. . -------------------------------------------------------------------------------- /_posts/2024-11-09-Steam-Unable-to-Register.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2024-11-09 20:52 3 | head_image: fac6b8c5d6bd92dfa3416eae3644af85.webp 4 | head_image_height: 720 5 | head_image_width: 1280 6 | info: 您对 CAPTCHA 的响应似乎无效。请在下方重新验证您不是机器人。 7 | last_modified_at: 2024-11-09 21:24 8 | no_sidenav: true 9 | tags: 技术指南 10 | title: 解决Content-Security-Policy安全策略导致Steam无法注册的问题 11 | --- 12 | 师兄想玩《双人成行》,问我有什么好办法。我说这还不好办嘛,[注册个Steam账号](https://store.steampowered.com/join/)就好了。然而,Steam不知道抽了什么风,不管验证码有没有完成,得到的都只有一句话: 13 | 14 | > 您对 CAPTCHA 的响应似乎无效。请在下方重新验证您不是机器人。 15 | 16 | 在确认了师兄不是机器人之后,我尝试更改浏览器、更改网络、更改设备、更改邮箱,都没有解决问题。心好累,看看为什么报错吧。按F12打开控制台,看到了错误输出: 17 | 18 | {% include figure.html src="0faa80589e7bc65ea0c6ce1e76b9bd91.webp" alt="控制台输出" width="960" height="513" %} 19 | 20 | 按起来似乎是和浏览器的安全策略有冲突,在控制台的“网络”标签页可以看到当前页面相应的标头(Headers): 21 | 22 | ``` 23 | Content-Security-Policy: 24 | default-src blob: data: https: 'unsafe-inline' 'unsafe-eval'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://store.cloudflare.steamstatic.com/ https://store.cloudflare.steamstatic.com/ https://recaptcha.net https://www.google.com/recaptcha/ https://www.gstatic.cn/recaptcha/ https://www.gstatic.com/recaptcha/ https://www.youtube.com/ https://s.ytimg.com https://recaptcha.net https://google.com/recaptcha/ https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://www.gstatic.cn/recaptcha/ https://js.hcaptcha.com; object-src 'none'; connect-src 'self' http://store.steampowered.com https://store.steampowered.com http://127.0.0.1:27060 ws://127.0.0.1:27060 https://community.cloudflare.steamstatic.com/ https://steamcommunity.com/ https://steamcommunity.com/ wss://community.steam-api.com/websocket/ https://api.steampowered.com/ https://login.steampowered.com/ https://help.steampowered.com/ https://steam.tv/ https://shared.cloudflare.steamstatic.com/ https://checkout.steampowered.com/; frame-src 'self' steam: http://www.youtube.com https://www.youtube.com https://www.google.com https://sketchfab.com https://player.vimeo.com https://steamcommunity.com/ https://login.steampowered.com/ https://help.steampowered.com/ https://checkout.steampowered.com/ https://www.google.com/recaptcha/ https://recaptcha.net/recaptcha/ https://recaptcha.net https://google.com/recaptcha/ https://www.google.com/recaptcha/ https://*.hcaptcha.com; frame-ancestors 'none'; 25 | ``` 26 | 27 | 这里的[`Content-Security-Policy`](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP)是一个安全策略,限制了页面的资源加载。其中`connect-src`限制了可以连接的服务器,由于这个页面要访问hCaptcha的服务器`newassets.hcaptcha.com`,但这个域名并未包含在`connect-src`中,所以浏览器拒绝了这个请求。虽然`*.hcaptcha.com`在标头里,但它是在`frame-src`中的,它限制的是当前页面可以被嵌入的域名,在此处并不生效。不知道是不是某次更新导致的配置错误。 28 | 29 | 解决方法也很简单,Chrome浏览器的控制台现在已经支持修改标头了,直接在控制台的“网络”标签页选择当前页面,点击`Content-Security-Policy`右边的铅笔图标,然后删除所有内容即可。当然,更安全的办法应该是把`*.hcaptcha.com`添加到`connect-src`中,但是我不确定当前网页是不是还会访问其他域名,所以干脆全删掉就完事了。修改完成后按Ctrl + R重新载入页面,如果控制台不再报错说明hCaptcha加载成功,可以正常注册Steam账号了。 30 | 31 | 当然,这个方法不能保证一定不会出现“您对 CAPTCHA 的响应似乎无效。请在下方重新验证您不是机器人。”的提示了,同一个地址多次注册账号等问题也可能会导致被Steam判定为机器人注册,没有万能的解决方法。而且这个错误估计不久就会被修复吧。 32 | -------------------------------------------------------------------------------- /_posts/2024-11-04-NitroPatcher.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2024-11-04 15:34 3 | head_image: a0dcbda7806913ed7a5298a44ccd3abd.webp 4 | head_image_height: 324.5 5 | head_image_width: 469 6 | info: 打个补丁。 7 | last_modified_at: 2025-05-11 23:36 8 | links: 9 | - - https://github.com/Xzonn/NitroPatcher 10 | - 项目地址 11 | tags: DS 作品发布 12 | title: NitroPatcher:NDS ROM 补丁工具 13 | --- 14 | [**NitroPatcher**](https://github.com/Xzonn/NitroPatcher)是一个基于[NitroHelper](https://github.com/Xzonn/NitroHelper)的NDS ROM补丁工具。 15 | 16 | 其实质是通过替换NDS ROM所包含的文件来实现汉化、修改等功能。本工具支持[Xdelta](https://en.wikipedia.org/wiki/Xdelta)补丁。 17 | 18 | 替代[《宝可梦》第四、第五世代汉化修正工具](https://github.com/Xzonn/PCTRTools)中的补丁应用工具。 19 | 20 | ## 应用补丁 21 | ### GUI(图形化界面) 22 | #### Windows版(WPF) 23 | 24 | 支持Windows平台。 25 | 26 | 需要[.NET Framework 4.7](https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/net47)或更高版本的运行时(Runtime)。Windows 10/11应该已经预装了.NET Framework 4.7。Windows 7可能需要安装 [KB976932](https://www.catalog.update.microsoft.com/Search.aspx?q=KB976932)、[KB4503548](https://www.catalog.update.microsoft.com/Search.aspx?q=KB4503548)更新。 27 | 28 | 根据图形界面的提示操作即可,或者参照[视频教程](https://www.bilibili.com/video/BV1oH1xYXEdb/t=69)。 29 | 30 | #### Windows/Android版(MAUI) 31 | 32 | [{% include image.html src="https://get.microsoft.com/images/zh-cn%20dark.svg" width="232" height="68" %}](https://apps.microsoft.com/detail/9NPLXRZ04F04?mode=direct) 33 | {: .plainlinks } 34 | 35 | 支持Windows/Android平台。 36 | 37 | Windows平台需从[Microsoft Store](https://www.microsoft.com/store/apps/9NPLXRZ04F04)下载安装,需要Windows 10 17763.0或更高版本。 38 | 39 | Android平台理论上最低支持Android 5.0(API 21),但仅在Android 12.0(API 31)上进行了测试。 40 | 41 | 根据图形界面的提示操作即可。 42 | 43 | ### CLI(命令行界面) 44 | 45 | 支持Windows、Linux、macOS平台。 46 | 47 | 需要[.NET 6.0 运行时](https://dotnet.microsoft.com/zh-cn/download/dotnet/6.0)(Runtime)。 48 | 49 | 用法: 50 | 51 | ``` 52 | NitroPatcherCli 原始ROM 补丁包 输出ROM 53 | ``` 54 | 55 | ## 创建补丁 56 | ### 基本用法 57 | 58 | 使用[ndstool](https://github.com/devkitPro/ndstool)分别提取原始ROM和修改后的ROM的文件系统,例如: 59 | 60 | ``` 61 | ndstool -x example.nds -9 "arm9.bin" -7 "arm7.bin" -y9 "overarm9.bin" -y7 "overarm7.bin" -d "data" -y "overlay" -t "banner.bin" -h "header.bin" 62 | ``` 63 | 64 | 然后筛选出具有差异的文件,将所有文件打包为`.zip`压缩包(需注意arm9.bin等文件需要在根目录下)。 65 | 66 | ### 额外功能 67 | #### 添加MD5校验码 68 | 69 | 可在补丁包的根目录下创建名为`md5.txt`的文件,在文件中包含原始ROM的MD5校验码。在应用补丁时,补丁工具会自动计算原始ROM和修改后的ROM的MD5校验码,并与`md5.txt`中的校验码进行比对。 70 | 71 | 如果有原始ROM有多个版本(例如,对未汉化的ROM和已汉化的ROM使用同一个补丁),可以在`md5.txt`中添加多个校验码,每行一个。以“#”为首的行及空行会被忽略。 72 | 73 | [这里提供了一个示例](https://github.com/Xzonn/PokemonChineseTranslationRevise/blob/9f0632f22c3982bd2ce541c6c902dee54bd0db1a/original_files/DP/D/md5.txt)。 74 | 75 | #### 使用Xdelta补丁 76 | 77 | 可以在补丁包的根目录下创建名为`xdelta`的文件夹,然后计算原始ROM和修改后的ROM之间的差异,并将差异文件保存到`xdelta`文件夹中。例如,若对`data/some/sub/folder/pack.pak`这个文件计算了Xdelta补丁,则补丁位置应为`xdelta/data/some/sub/folder/pack.pak`。 78 | 79 | 此功能对于ROM中包含较大文件(例如开发商自定义的打包格式)的情况非常有用。 80 | 81 | [这里提供了一个批量计算脚本](https://github.com/Qi-Busiyi-Hanhuazu/EO3ChsLocalization/blob/c7643f75b9a8c39954a6170fb3846a98c3914b81/scripts/create_xdelta.py)。 82 | -------------------------------------------------------------------------------- /_posts/2021-10-14-Try-to-Extract-Messages-from-Games.md: -------------------------------------------------------------------------------- 1 | --- 2 | class: auto-numbering 3 | date: 2021-10-14 23:07 4 | info: 以Nintendo Switch游戏为例。 5 | last_modified_at: 2021-10-17 12:47 6 | tags: Switch 技术指南 7 | title: 尝试从游戏中提取文本 8 | --- 9 | 我在GitHub上有一个[项目](https://github.com/Xzonn/NintendoOfficialChineseGames/),专门用于记录任天堂官方中文化游戏的文本。这个项目对于喜欢确认译名的人来说应该比较有帮助,如果帮到了您,您可以选择给它一个Star。 10 | 11 | 这篇笔记主要就是来讲一讲这个项目里面的文本是怎么来的。注意:本文不涉及盗版游戏的获取方式。 12 | 13 | ## 文本在游戏中的存储 14 | 在提取文本之前,首先要定位文本的位置;而要定位文本的位置,首先得获得游戏文件。很尴尬的一件事就是:对于主机游戏来说,由于主机的封闭性,一般只有破解过的主机才能够提取游戏ROM。如果没有破解的主机,那么就只能够通过盗版网站获取ROM了。由于这并不是本文的重点,我不打算深入讨论这个问题,但是有一件很讽刺的事就是,由于“偷跑”的存在以及互联网的传播,盗版游戏反而容易比正版游戏提前获得。而对于电脑游戏、手机游戏来说,游戏文件的获取一般比较简单。 15 | 16 | 在获取游戏文件后,有时还需对文件进行“拆包”。这里的拆包大多是因为游戏厂商出于压缩容量、减少小文件数量等考量而将多个文件打包成一个,为了获取其中的单独文件而需要进行的步骤。对于主机游戏来说,游戏文件一般被称作ROM,其中包含了可执行文件(exefs)、数据文件(romfs)等多种文件,而游戏文本一般存储于数据文件中。对于常见的打包格式来说,由于对其感兴趣的人较多,因此可以使用的工具也比较多。例如,对于Nintendo Switch游戏的ROM文件,可以使用[Ryujinx](https://ryujinx.org/)提取其中的romfs;对于任天堂自家的常用打包格式,可以使用[Switch-Toolbox](https://github.com/KillzXGaming/Switch-Toolbox/)进行拆包;而对于跨平台的游戏引擎[Unity](https://unity.com/),则有专门的工具[AssetStudio](https://github.com/Perfare/AssetStudio/)用于分析数据文件。 17 | 18 | 接下来需要定位文本的位置并提取文本。一般来说,包含文本的文件多以“Message”“Text”“Localization”等词语命名,或者按语言代码“ja”“en”等词语分类。其保存路径因游戏而异,有时也需要一些突如其来的想法才能找到文本。如果没找到的话,可能是拆包不彻底,也可能是厂商用了特殊的命名方式(比如使用了母语+缩写)。虽然也可能是保存在了可执行文件中,但这样一般不方便维护,而且不利于本地化翻译,对于国际厂商来说一般不会这么做。 19 | 20 | ## 从文件中提取文本 21 | 定位了文本所在的文件之后,剩下的就是将文本提取出来了。如果厂商使用的是常见格式(如`.txt`、`.csv`、`.xml`、`.json`)等,则可以直接使用文本编辑器打开,或是自己编写简单的脚本批量读取、转换。但是,基于存储大小、读取速度、定位方式等多种因素考虑,游戏中的文本一般不会保存为常见的格式,而是保存为厂商特有的二进制文件。例如,近年来任天堂自家的游戏多以`.msbt`格式存储文本,对于这一格式的研究也已经比较深入,除了前文的Switch-Toolbox之外,还有一个在Nintendo 3DS时代常用的工具[Kuriimu](https://github.com/IcySon55/Kuriimu/)也能读取`.msbt`格式的文件。此外,这两个工具也能读取一些其他的常用文本文件格式,可以参考两者的GitHub项目主页查看。如果这两个软件都无法打开文本文件,还可以尝试Google一下文件格式 + Extract或类似字样,有时可以找到前人已经写过的工具。 22 | 23 | 当然,并不是所有的文件格式都有前人分析。对于搜索无果的情况,可以尝试先用十六进制编辑器打开(如[HxD](https://mh-nexus.de/en/hxd/)),然后读取疑似的字节串,查看其UTF-16或UTF-8解码的结果。对于国际厂商来说,文本编码多为这两种编码,但也有例外,如厂商可能使用Shift-JIS编码日语,或GB18030编码简体中文;如果是这种情况的话,可能真的需要一些灵感了。如果字节串可以读出有效信息,表明文本文件应该是没有加密的,可以编写脚本读取。 24 | 25 | 在提取出文本之后,有时还要处理文本中存在的控制符。如果控制符本身就是可见字符(如使用了类似HTML标记的`<>`),一般无需处理;而对于控制符本身是不可见字符的情况,就会变得有些复杂。`.msbt`格式的控制符就是属于后一种情况,但Kuriimu等工具对于控制符的处理效果不佳,建议自行分析控制符的使用方式。 26 | 27 | ## 笔记:一些不常见的文本文件格式 28 | ### `BTXT`文件:不一样的`.txt`文件 29 | 在《密特罗德 生存恐惧》(发售日:2021-10-08)中,文本文件使用了`.txt`格式,但这些文件无法用文本编辑器直接打开。用HxD查看之后发现Magic Header是`BTXT`(`42 54 58 54`),文字也基本可读,就是简单的ID + 字符串格式。 30 | 31 | 参考代码:[GitHub Gist](https://gist.github.com/Xzonn/aa4ffdfc89ea416108e8348f2506ad99)。 32 | 33 | ### `.wmbt`文件:`.msbt`文件的后继者? 34 | 在《分享同乐!瓦力欧制造》(发售日:2021-09-10)中,文本文件使用了`.wmbt`的格式。这种格式的结构与`.msbt`几乎相同,仅仅是部分字节有了变化。原有的工具无法直接使用,但经过简单修改后仍可提取文本。 35 | 36 | 参考代码:[GitHub Gist](https://gist.github.com/Xzonn/f779dcb213fa8c366779f8b22c94f0c4)。 37 | 38 | ### `.etb`文件:使用GBK进行编码 39 | 在《搭档任务 秘密搜查组》(亚洲版本,发售日:2021-08-20)中,文本文件使用了`.etb`格式。这种格式的文本编码比较特殊,不是常用的UTF-16或UTF-8,而是随不同语言而变化,也即中文文本用了GBK(顺带一提,繁体中文文本编码也是GBK,而不是BIG-5),韩文文本用了EUR-KR。我推测日文文本可能用了Shift-JIS,但我没有实际测试。 40 | 41 | 参考代码:[GitHub Gist](https://gist.github.com/Xzonn/bc9454ec711d4c547776825c5eaea476)。 -------------------------------------------------------------------------------- /_posts/2018-06-05-About.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2018-06-05 12:00 3 | head_image: /assets/images/icon_32x32.svg 4 | head_image_height: 720 5 | head_image_shown: false 6 | head_image_width: 720 7 | info: 关于Xzonn的小站的说明。 8 | last_modified_at: 2025-05-11 01:14 9 | tags: 网站日志 10 | title: 关于本站 11 | --- 12 | 如果您有任何问题、意见或建议,请 **[在此页面](https://github.com/Xzonn/Xzonn.github.io/issues)** 与我联系,或在页面下方留言。 13 | 14 | 如果您想寻找全部页面,请 **[在此页面](/pages.html)** 查看。 15 | 16 | ## 概述 17 | 18 | 本站是由Xzonn创建的个人网站,主要内容是本人的学习资料、个人笔记等,源文件为html和markdown格式,由[jekyll](https://jekyllrb.com/)生成,部署于[GitHub Pages](https://pages.github.com/)。[源代码](https://github.com/Xzonn/Xzonn.github.io/)发布于[GitHub](https://github.com)。目前本站样式版本为5.0版本。 19 | 20 | 本站使用了JsDeliver作为CDN,分发css、js等静态文件。 21 | 22 | 目前本站为每次推送到GitHub时自动构建。当前版本构建于{{ "now" | date: "%F %T %Z" }},构建环境为{{ jekyll.environment }}。 23 | 24 | ## 许可 25 | 26 | 除非另有说明,本站所有文章均采用“[知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议](http://creativecommons.org/licenses/by-nc-sa/4.0/)”进行许可,遵循“个人非商用”原则。 27 | 28 | 本站源代码采用[GPL 3.0](https://github.com/Xzonn/xzonn.github.io/blob/master/LICENSE)进行许可。 29 | 30 | ## 致谢 31 | 32 | - 页面部署于[GitHub Pages](https://pages.github.com/)。 33 | - 页面生成使用[jekyll](https://jekyllrb.com/),语法参考了[jekyllCN](https://jekyllcn.com/)的教程。 34 | - 页面布局基于[Bootstrap v3](https://getbootstrap.com/docs/3.4/),根据个人习惯进行自定义,使用[less.js](http://lesscss.org/)编译。 35 | - 页面处理使用[jQuery](https://jquery.com/)。 36 | - 公式渲染使用[MathJax](https://www.mathjax.org/),并使用了[mhchem for MathJax](https://github.com/mhchem/MathJax-mhchem)插件渲染化学公式。 37 | - 中英文混排使用[Han](https://hanzi.pro/)。 38 | - 评论系统使用[giscus](https://giscus.app/)。 39 | - 分析系统使用[百度统计](https://tongji.baidu.com/)。 40 | - 搜索功能使用[Algolia](https://www.algolia.com/)。 41 | 42 | ## 更新日志 43 | - 2018-06-05: 44 | - 开始项目。 45 | - 2018-06-28: 46 | - 页面格式更新,升级至2.0版本。 47 | - 2019-01-05: 48 | - 页面格式更新。 49 | - 增加评论功能。 50 | - 2019-07-21: 51 | - 调整CSS,使中文标点可以以中文字体渲染。 52 | - 2019-07-24: 53 | - 添加“标签一览”页面。2020-02-16补注:由于页面格式更新,本页面已与“文章列表”页面合并。 54 | - 2019-09-24: 55 | - 添加独立的说明页面。 56 | - 将导航链接放至页脚。 57 | - 小幅修改页面格式。 58 | - 2019-12-28: 59 | - 修改CSS字体定义。 60 | - 2020-02-16: 61 | - 页面格式更新,升级至3.0版本。([3.0版本更新日志](posts/Update-3-0.html)) 62 | - 2020-03-02: 63 | - 完成备案并将网站服务器迁移至阿里云。 64 | - 2020-03-07: 65 | - 公开“学习资料库搜索”及“服务器渲染PDF”功能。([新功能上线:学习资料库搜索及服务器渲染PDF](/posts/Update-Study-Search-and-Pdf.html)) 66 | - 添加网站自动构建功能。 67 | - 2020-08-31: 68 | - 服务器到期,将网站迁移回GitHub Pages。 69 | - 2021-01-11: 70 | - 修改配色。 71 | - 改进PDF渲染方式,修复Han.js在MathJax内添加空格导致PDF输出错误的问题。 72 | - 2021-05-23: 73 | - 拆分学习资料和其他内容。 74 | - 使用[LazyLoad](https://github.com/verlok/vanilla-lazyload)延迟加载图片。 75 | - 页面格式更新,升级至3.1版本。 76 | - 2021-05-24: 77 | - 改用`decoding="async" loading="lazy"`参数替换LazyLoad。 78 | - 2023-06-15: 79 | - 拆分[“学习资料”](/study/)。 80 | - 2023-10-12: 81 | - 移除原有的[来必力](https://livere.com/)评论系统,改用基于[GitHub Disscussions](https://github.com/Xzonn/xzonn.github.io/discussions)的[giscus](https://giscus.app/)。 82 | - 2023-12-28: 83 | - 升级到Bootstrap 5.x版本。 84 | - 添加[搜索](/search.html)功能。 85 | - 2024-02-11: 86 | - 初步支持中英双语界面。 87 | - 2025-05-10: 88 | - 添加对深色模式的适配。 89 | -------------------------------------------------------------------------------- /_posts/2019-11-01-Tenki-no-ko.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2019-11-01 12:00 3 | head_image: https://img1.doubanio.com/view/photo/m/public/p2570059839.webp 4 | head_image_height: 755 5 | head_image_width: 540 6 | last_modified_at: 2020-01-03 23:02 7 | tags: 杂记 8 | title: 《天气之子》杂记 9 | --- 10 | 提前一天读完了小说,今天去看了电影。个人评分:小说7/10,电影8/10。我对新海诚也不算太了解,他之前的作品我只看过《秒速5厘米》和《你的名字。》,这里就随口说几句观后感。可能有剧透。 11 | 12 | 高中生森岛帆高离家出走来到遭遇百年不遇大雨的东京,走投无路时得到了打工少女天野阳菜赠送的汉堡。随后热心的大叔须贺圭介和他的侄女夏美收留了他并让他留下打工,在打工期间他帆高与阳菜再次相遇,在一幢废弃大楼中帆高得知阳菜有使天气小范围放晴的能力,两人和阳菜的弟弟凪一起开办人工影响天气业务。当他们名声变大时,因警察登门拜访使得三人不得不更换去处,在逃走期间走投无路来到酒店歇脚。在酒店,帆高得知阳菜改变天气会使身体变得透明,且只有献出自己的生命才能使暴雨停止。帆高不希望阳菜消失,而阳菜则选择了离开。第二天,天气放晴,阳菜却消失了。帆高摆脱了警察追捕前往废弃大楼寻找阳菜,最终他穿过楼顶的鸟居带回了阳菜,天气又变为了雨天。三年间,东京大部分被水淹没。三年后,帆高来到东京上大学,两人再次重逢。 13 | 14 | 从结局来看,帆高与阳菜重逢,大团圆结局。从过程来看,两人的关系充满了曲折:阳菜一直隐瞒自己改变天气身体就会变得透明的事实,而在得知之后帆高想阻止阳菜继续改变天气,但阳菜为了拯救暴雨下的东京而选择离开。在发现阳菜消失后,帆高逃脱警察的追捕,甚至开枪警告救命恩人须贺大叔,最终他的坚持打动了须贺,在他和凪的帮助下穿越鸟居带回了阳菜。或许这种对对方的执着才是影片的动人之处。 15 | 16 | 须贺圭介大叔其实是一个很典型的“老实人”。他是一位老好人:在船上搭手救了帆高,又在帆高走投无路时收留了他,为他提供了工作。而他同时也是一位好父亲:为了女儿而努力工作,为了让女儿可以在阳光下玩耍而拜托阳菜改变天气。当然,他也有普通人软弱的一面:因为警察调查帆高而不得不将他赶走,但又给了他“离职金”,回到家后又因为自己的做法而喝的酩酊大醉;他还赞同牺牲一个人换取晴天的做法。当他得知帆高逃跑时,他来到废弃大楼劝说帆高迷途知返,还在警察赶到时帮帆高说好话,又在被帆高打动时不惜冲撞警察为帆高换取时间,自己却因妨碍公务被带走。可以说,须贺圭介普通得不能再普通,但他又是许许多多的普通人中最典型的一位。正是这些普通人使得我们的生活有了色彩。 17 | 18 | 小说和电影的故事情节大体相同,电影的视觉效果更强,而小说则对一些背景进行了补充。例如,关于须贺圭介与夏美的关系,电影中仅仅是提到了两人是叔侄关系,而小说中则描写了夏美的内心活动。如果有可能,建议小说和电影都看一下。 19 | 20 | 有几个想吐槽的地方: 21 | 22 | 1. 帆高为何如此容易就拿到了一把枪,而且枪扔到废弃大楼竟然没有警察来调查回收,当帆高又一次回到大楼时竟然还在那里。另外,帆高多次从警察手中逃脱,令我不禁感叹日本警察是否有存在的意义。 23 | 2. 帆高从电车轨道上走的时候,许多工作人员都警告他,然并卵,尽然没有一个人上前拽住他不让他走,仿佛所有工作人员都定住了一样。 24 | 3. 凪小小的年纪已经有两任女友了,而且两任女友还能相安无事的同屏出现,怪不得帆高要叫他“前辈”。 25 | 26 | 然后是我个人发现的一些小彩蛋: 27 | 28 | 1. 电影中出现了《你的名字。》中的主人公:立花泷(立花富美老奶奶的孙子,向帆高提议送阳菜礼物)、宫水三叶(帆高买礼物的商店店员)。另外敕使河原克彦、名取早耶香、宫水四叶等人也在配音表中出现,但我没有在正片中找到他们。2019/11/04补充:根据[官微](https://weibo.com/u/6885069945)的[说明](https://weibo.com/6885069945/IeGBvfdbx),敕使河原克彦和名取早耶香出现在阳菜第一次在跳蚤市场放晴后的摩天轮上,宫水四叶是天气彻底放晴后的一位享受阳光的学生。 29 | 2. 凪的两任女朋友分别叫“佐仓绫音”和“花泽香菜”。佐仓绫音的配音员是佐仓绫音,花泽香菜的配音员是花泽香菜。 30 | 3. 配音表中最后出现的是须贺圭介的配音——小栗旬。所以须贺圭介才是主角?我瞎说的。配音表最后的人可能是特邀前来配音的人。 31 | 4. 电影中出现的很多商标都是现实存在的企业,例如McDonalds、Haier等。此外有家公司名为“TOHO”,我怀疑是指本片的日本发行商东宝,但字幕给出的翻译是“东邦”,而后者确实也真实存在。 32 | 5. 电影中三人唱卡拉OK的两首歌曲也是现实的歌曲,分别是《恋爱幸运曲奇》日语:恋するフォーチュンクッキー,原唱:AKB48。和《恋》日语:,原唱:星野源。。 33 | 34 | 另外是我个人认为的翻译不恰当的地方: 35 | 36 | 1. 小说中对于阳菜的称呼是“人柱”,这似乎是汉字直译,查了日语词典后发现这个词的意思就是“牺牲者”人柱:①被活埋在水下(土中)的人。②献身的人,牺牲者。。而电影对这个词的翻译则是“献身者”。因此我觉得小说中应该将此词意译。 37 | 2. 小说中对于凪女友名字的介绍中,提到了两人登记的姓名是“佐仓加奈”和“花泽绫音”,而两人登记姓名时互换了姓和名小说第173页。,因此两人的原名应分别为“佐仓绫音”和“花泽加奈”。考虑到两人在电影中的配音员分别是佐仓绫音和花泽香菜,而“加奈”和“香菜”同音,均为“カナ”,片尾演职员表中的表记也是假名“カナ”,因此我认为应将名字译为“香菜”。 38 | 3. 电影中出现宫水三叶时,字幕对名牌的翻译似乎为“宫本茂”,不知是不是我看错了。2019/11/04补充:没看错,这已经变成一个梗了。 39 | 4. 电影中凪提议三人一起泡澡时,帆高和阳菜的回应似乎是“自分で入れ”,字幕给出的翻译是“我自己洗”,而小说给出的翻译则是“你自己泡(澡)”小说第150页。。从语法上来看应该是命令形,因此我认为小说的翻译更准确。 40 | 41 | 最后,祝大家阅读/观影愉快。 -------------------------------------------------------------------------------- /_posts/2023-03-15-A-Purchase-in-Surugaya.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2023-03-15 10:46 3 | head_height: 480 4 | head_image: 150d6a5e0b5a60e3a6eb26e082b8ceb8.jpg 5 | head_width: 720 6 | info: 计划赶不上变化。 7 | last_modified_at: 2023-03-15 15:25 8 | tags: Switch 杂记 9 | title: 骏河屋海淘记录 10 | --- 11 |
      12 |
      太长不看版:
      13 |
      14 | 1. 为防止被反薅,建议支付前让卡上的余额只留比优惠价格高出10% 左右。 15 | 2. 建议抢优惠前先自己走一遍购买流程,确认实际支付是在什么时候,在抢优惠时可以直接等到10点在最后一步确认支付。 16 | 3. 如果被税了又不想交代理清关的手续费,建议去银行办张实体卡,绑定之后可以直接缴税。 17 | {: style="margin-bottom: 0;" } 18 |
      19 | 20 | ## 起因 21 | 这几天PayPal和银联做活动,[满300人民币减15%,最高可减150人民币](https://www.paypal.com/c2/webapps/mpp/campaigns/nna/202302upicampaign)。许多人都推荐买任亏券,但是我不喜欢第一方游戏买下载版。为了薅羊毛,我想到了海淘。正好我最近又想买《夏日重现》的游戏——[《夏日重现 Another Horizon》](https://summertimerendering.mages.co.jp/game/),而日亚不能用PayPal,于是我选择了[骏河屋](https://www.suruga-ya.com/)。虽说骏河屋是二手(中古),但是品相看着还不错,而且二手比全新还便宜一些,对我来说是个不错的选择。另外,正好我有个朋友想买《超级马力欧 奥德赛》,他也不介意二手,于是我就一起买了。 22 | 23 | 先算下价格,二手《夏日重现》价格10500日元,《奥德赛》价格4400日元,手续费500日元,运费原价1160日元,而骏河屋每满10000日元可减免500日元运费,最终总价为16060日元,算上PayPal的15% 优惠,最终价格为13651日元,约合人民币700元。折合到每个游戏上,《夏日重现》493人民币,《奥德赛》207人民币,都比国内二手平台便宜不少。 24 | 25 | {% include figure.html src="edd808108cac7e9d372d30dbceedea25.jpg" alt="最终支付的订单" width="640" height="350.4" %} 26 | 27 | ## 支付 28 | 理想很美好,现实很骨感。首先,PayPal的优惠是有限额的,每天早上10点开抢,但实际上差不多5分钟就抢没了。而这个优惠又是下单之后才知道抢没抢到,如果一不小心就会按原价成交,直接被反薅。最终的解决方法是,直接把大部分余额转到另一张卡上,只留比折扣价高出10% 左右的余额(我留了800元人民币),这样没抢到优惠时就直接支付失败,不会被反薅,可以留到第二天支付。 29 | 30 | 此外,实际支付的时候也有坑。在骏河屋确认订单后会跳到PayPal的界面选择支付方式,这时候需要注意选择汇率,PayPal给出的汇率非常不划算,需要选择按JPY(日元)支付。而且,在PayPal确认后并没有支付成功,而是跳转回骏河屋的网页,需要再次确认才会扣款。 31 | 32 | {% include figure.html src="9e55b756170d5f17395f4de9a40d51af.jpg" alt="PalPal给出的汇率很不划算,按图上的汇率来算100日元需要5.394人民币,而当天银行给出的购汇汇率是5.135,高出了约5%" width="579" height="254" %} 33 | 34 | 因为选项过于复杂,我第一天的尝试耗时太长而没抢到优惠,好在余额不足没有支付成功。因此到了第二天我直接在9:59之前完成了前面的所有步骤,等到10:00一到直接在最后的页面确认支付,终于支付成功了。 35 | 36 | {% include figure.html src="8beda5dd309b800c1219881963eccfa3.jpg" alt="支付成功后,银联提醒我发生了预授权交易,直到发货后才正式扣款" width="360" height="800" %} 37 | 38 | ## 运输 39 | 骏河屋的运输方式有两种,一种是EMS,一种是DHL。我选择了EMS,官网上说最快2-3天,但实际上从下单到发货用了一星期,从发货到最终收货又花了一星期。 40 | 41 | 本以为能顺顺利利地收货,没想到中国邮政提醒我需要缴99.31人民币的税。这里又是个坑,中国邮政提供的代理报关需要交10人民币的手续费,本着能省就省的思想,这手续费我肯定是不想出的。 42 | 43 | {% include figure.html src="8c4c5581ad211e559d06512f74d44c5b.jpg" alt="中国邮政提醒我缴税" width="360" height="800" %} 44 | 45 | 而在海关自己的程序上缴税必须要绑定银行卡,并且限定了兴业银行或招商银行。这两家银行的银行卡我都没有,我在招商银行APP上创建的虚拟银行卡虽然能够绑定,但无法成功支付。打电话问了客服,他们一问三不知。于是我打算去线下直接缴税,结果到了海关大厅已经下午四点半了,到了下班时间。为了不拖到第二天,我最终还是去银行办了张实体卡,绑定之后终于缴税成功。 46 | 47 | {% include figure.html src="7ce55f6b26e8b29bcf26ff4ec6d14d5d.jpg" alt="虚拟银行卡可以绑定(签署协议),但是无法成功支付,客服也无法解决" width="360" height="800" %} 48 | 49 | ## 收货 50 | 缴完税之后顺利放行,又隔了一天,我最终收到了包裹。虽然两个游戏都是二手的,但是品相看起来还不错,《夏日重现》的所有东西都在,《奥德赛》里面没有广告纸,不过问题不大。最后算了一下,加上税费总共花了798.88人民币,也还算可以了。 51 | 52 | {% include figure.html src="8c08f7fb186d8347c32a78ddc235998d.jpg" alt="《夏日重现 Another Horizon》初回限定版外包装" width="540" height="360" %} 53 | 54 | {% include figure.html src="5b7d77888cfe5db8a356683517f417c7.jpg" alt="说是“初回限定版”,其实也就多了个官方攻略书和游戏原声带" width="540" height="360" %} -------------------------------------------------------------------------------- /_posts/2020-07-31-How-to-Download-Subtitle-for-Online-Class.md: -------------------------------------------------------------------------------- 1 | --- 2 | class: auto-numbering 3 | date: 2020-07-31 16:38 4 | info: 把字幕整理起来,就得到了老师上课的文字实录。 5 | last_modified_at: 2020-07-31 18:31 6 | tags: 技术指南 7 | title: 如何下载网课的字幕 8 | --- 9 | 11 | 12 | ## 前言 13 | 14 | 上个学期,由于一场公共卫生事件,许多课程不得不开展线上教学,这也使得“网课”成为了一大话题。有些课程是实时教学,这些课暂时不讨论;而另一些课程则采用了录播的形式,教学内容提前录制好并上传,学生只需要在线学习或者下载学习即可。相比于面对面教学来说,这种录播的形式一般都有三个特点:能够回放,方便复习;能够快进,方便复习;能够调节播放速度,方便复习。 15 | 16 | 首先先介绍一下网课如何调节播放速度。在浏览器按F12打开控制台,切换到“Console”,输入如下代码并回车运行: 17 | 18 | ```javascript 19 | tmp = document.getElementsByTagName("video"); 20 | for (let i = 0; i < tmp.length; i++) { 21 | tmp[i].playbackRate = 16; 22 | } 23 | ``` 24 | 25 | 简单解释一下发生了什么。第1行获取页面内所有`
    • ' | replace: '', '
      • ' | replace: '', '
      ' | replace: '
    • ', '' }}{{ _splited_part[1] | replace: DOUBLE_LINE_BREAK, LINE_BREAK | replace: LINE_BREAK, LINE_BREAK_INDENT }}{% endif %}{% endfor %} 10 | {% if page.references or page.links or page.logs %}{% capture infobox %} 11 |
      {%if page.references %} 12 |
      13 |
      {% t content-references %}
      14 | 17 |
      {% endif %}{%if page.links %} 18 | {% endif %}{%if page.logs %} 24 |
      25 |
      {% t content-history %}
      26 |
        {% for log in page.logs %} 27 |
      • {{ log }}
      • {% endfor %} 28 |
      29 |
      {% endif %} 30 |
      {% endcapture %}{{ infobox | replace: ' 32 |
      {% t content-comment-info %}
      33 | 34 | {% endunless %} 35 | {% unless page.no_sidenav %} 36 |
      37 | {% include toc.html html=content sanitize=true h_max=4 class="xz-sidenav-list nav flex-column" item_class="nav-item" anchor_class="nav-link" submenu_class="nav flex-column" %} 38 |
      {% endunless %} 39 | 40 | 41 | -------------------------------------------------------------------------------- /assets/css/_highlight.scss: -------------------------------------------------------------------------------- 1 | /* 2 | * Copied from https://raw.githubusercontent.com/richleland/pygments-css/master/default.css 3 | * Created by richleland 4 | */ 5 | 6 | .highlight { 7 | .c { color: #408080; font-style: italic } /* Comment */ 8 | .err { border: 1px solid #FF0000 } /* Error */ 9 | .k { color: #008000; font-weight: bold } /* Keyword */ 10 | .o { color: #666666 } /* Operator */ 11 | .ch { color: #408080; font-style: italic } /* Comment.Hashbang */ 12 | .cm { color: #408080; font-style: italic } /* Comment.Multiline */ 13 | .cp { color: #BC7A00 } /* Comment.Preproc */ 14 | .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */ 15 | .c1 { color: #408080; font-style: italic } /* Comment.Single */ 16 | .cs { color: #408080; font-style: italic } /* Comment.Special */ 17 | .gd { color: #A00000 } /* Generic.Deleted */ 18 | .ge { font-style: italic } /* Generic.Emph */ 19 | .gr { color: #FF0000 } /* Generic.Error */ 20 | .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 21 | .gi { color: #00A000 } /* Generic.Inserted */ 22 | .go { color: #888888 } /* Generic.Output */ 23 | .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ 24 | .gs { font-weight: bold } /* Generic.Strong */ 25 | .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 26 | .gt { color: #0044DD } /* Generic.Traceback */ 27 | .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ 28 | .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ 29 | .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ 30 | .kp { color: #008000 } /* Keyword.Pseudo */ 31 | .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ 32 | .kt { color: #B00040 } /* Keyword.Type */ 33 | .m { color: #666666 } /* Literal.Number */ 34 | .s { color: #BA2121 } /* Literal.String */ 35 | .na { color: #7D9029 } /* Name.Attribute */ 36 | .nb { color: #008000 } /* Name.Builtin */ 37 | .nc { color: #0000FF; font-weight: bold } /* Name.Class */ 38 | .no { color: #880000 } /* Name.Constant */ 39 | .nd { color: #AA22FF } /* Name.Decorator */ 40 | .ni { color: #999999; font-weight: bold } /* Name.Entity */ 41 | .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ 42 | .nf { color: #0000FF } /* Name.Function */ 43 | .nl { color: #A0A000 } /* Name.Label */ 44 | .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ 45 | .nt { color: #008000; font-weight: bold } /* Name.Tag */ 46 | .nv { color: #19177C } /* Name.Variable */ 47 | .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ 48 | .w { color: #bbbbbb } /* Text.Whitespace */ 49 | .mb { color: #666666 } /* Literal.Number.Bin */ 50 | .mf { color: #666666 } /* Literal.Number.Float */ 51 | .mh { color: #666666 } /* Literal.Number.Hex */ 52 | .mi { color: #666666 } /* Literal.Number.Integer */ 53 | .mo { color: #666666 } /* Literal.Number.Oct */ 54 | .sa { color: #BA2121 } /* Literal.String.Affix */ 55 | .sb { color: #BA2121 } /* Literal.String.Backtick */ 56 | .sc { color: #BA2121 } /* Literal.String.Char */ 57 | .dl { color: #BA2121 } /* Literal.String.Delimiter */ 58 | .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ 59 | .s2 { color: #BA2121 } /* Literal.String.Double */ 60 | .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ 61 | .sh { color: #BA2121 } /* Literal.String.Heredoc */ 62 | .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ 63 | .sx { color: #008000 } /* Literal.String.Other */ 64 | .sr { color: #BB6688 } /* Literal.String.Regex */ 65 | .s1 { color: #BA2121 } /* Literal.String.Single */ 66 | .ss { color: #19177C } /* Literal.String.Symbol */ 67 | .bp { color: #008000 } /* Name.Builtin.Pseudo */ 68 | .fm { color: #0000FF } /* Name.Function.Magic */ 69 | .vc { color: #19177C } /* Name.Variable.Class */ 70 | .vg { color: #19177C } /* Name.Variable.Global */ 71 | .vi { color: #19177C } /* Name.Variable.Instance */ 72 | .vm { color: #19177C } /* Name.Variable.Magic */ 73 | .il { color: #666666 } /* Literal.Number.Integer.Long */ 74 | } -------------------------------------------------------------------------------- /_posts/2019-11-29-Save-Your-Unsaved-PPT-File.md: -------------------------------------------------------------------------------- 1 | --- 2 | class: auto-numbering 3 | date: 2019-11-29 12:00 4 | head_image: https://mmbiz.qpic.cn/mmbiz_png/Qh7FH95PRnsGibm3j1h8hlnibx94eAfibTVFXjYq5ECtrAV4C3UjtFuU9oS2Nic4pIZibyHVkicJy2C0Cx9iaS86p6iaJw/0 5 | head_image_height: 1466 6 | head_image_width: 1920 7 | info: 最好的拯救方法还是 Ctrl + S。 8 | last_modified_at: 2020-02-09 15:25 9 | tags: 技术指南 10 | title: 拯救未保存的 PPT 11 | wechat_link: https://mp.weixin.qq.com/s/DuEaIZgflV2b5yK5g0kfJA 12 | --- 13 | ## 起因 14 | 下午 5 点,一个电话把我从睡梦中吵醒。我定睛一看,是小弟打来的。 15 | 16 | “大哥,我昨天晚上做完 PPT 之后电脑没电了,PPT 也没保存,自动保存的文件我也打不开,这可咋整啊 1551……” 17 | 18 | 话说着,他给我发了两张截图。 19 | 20 | {% include figure.html src="53f4dd4e5c7173b8bb1b3092a6038328.png" alt="PowePoint 发现内容有问题" width="640" height="150.96" %} 21 | 22 | {% include figure.html src="932c4e1b92f96c7e7bbfef60dc4f8425.png" alt="很抱歉,PowerPoint 无法读取" width="640" height="284.88" %} 23 | 24 | 光看图看不出毛病,我便问他:“要不你把这个文件发我我试试?” 25 | 26 | 没想到,他回答道:“大哥,这俩文件我找不着哇!” 27 | 28 | 我一愣。一看路径,“C:\Users\10591\AppData\Roaming\Microsoft\PowerPoint\pptF8D1.tmp”。不怪他找不到。那就我亲自上手吧。我说:“你把 QQ 打开,我给你远程桌面。” 29 | 30 | 他一口答应下来,打开了 QQ。然而,我却连接不上他。我让他发个截图给我,然后打眼一看:这不是应用商店版的 QQ 么? 31 | 32 | {% include figure.html src="dc7e5e30a4c7f2a224e7c51aa12c61cb.png" alt="神奇的 QQ 界面" width="640" height="505.82" %} 33 | 34 | 我也不想再费口舌,便说:“要不你过来找我吧,一句两句话说不清楚。对了,我刚吃完饭,有点口渴……” 35 | 36 | 他似乎听懂了我想说啥,一口答应道:“好嘞哥,我这就过去,给您点上奶茶!” 37 | 38 | ## 找到文件 39 | 拿到他的电脑之后,我干的第一件事就是找这个文件,因为我最担心的就是这个文件是个空文件。当然,要进入上面那个路径“C:\Users\10591\AppData\Roaming\Microsoft\PowerPoint\pptF8D1.tmp”可能需要费点功夫。 40 | 41 | 一方面,“C:\Users\”这个文件夹显示的中文名是“用户”而不是“Users”,一眼看去可能找不到。另一方面,“AppData”是个隐藏文件夹,需要在设置里选中“隐藏的项目”这一复选框。 42 | 43 | 另外,其实还有一个方法,就是在地址栏中输入“%APPDATA%”然后回车,就会跳到“C:\Users\\*<当前用户名>*\AppData\Roaming”这个文件夹。 44 | 45 | {% include figure.html src="db816a5bcc79f47720b3e1ba75a3a0f3.png" alt="寻找 AppData" width="640" height="300" %} 46 | 47 | 很快,我找到了这个文件。查看文件大小,13.2 MB,还算正常,应该是保存了的。至于这个文件如何打开,我还是费了一番功夫。 48 | 49 | ## 改扩展名 50 | 第一个想法就是直接改后缀名。我很容易就想到把“.tmp”改成“.pptx”,然后打开。然而,现实总是充满惊喜。 51 | 52 | {% include figure.html src="73728a9408b63862406a6f05ce5f769d.png" alt="文件扩展名已更改" width="606" height="132" %} 53 | 54 | “.pptx”不行,那就改成“.ppt”。这次虽然好像是打开了,但是卡在了修复上。 55 | 56 | {% include figure.html src="c19454fa6ca116716870a76c2098b32c.gif" alt="改了扩展名还是打不开的文件" width="400" height="225" %} 57 | 58 | 于是,我决定另辟蹊径。 59 | 60 | ## 开肠破肚 61 | 虽然 PowerPoint 不认自家孩子,但不代表别的软件不认。在 Office 2007 版本后,默认文件格式的后缀名都加了个“x”。不要小看这个“x”,这些文件是以 ZIP 格式压缩的,因此将其扩展名改为“.zip”后,就可以用一半的解压软件打开。同理,对解压出来的文件修改后再压缩回 ZIP 格式并改后缀名,也可以用 Office 再次打开。一般我会用这种方法从 Office 文档中提取图片,或是批量修改内容。但这次,我要做的是找到错误并修正。 62 | 63 | 将这个文件后缀名改为“.zip”,然后尝试解压缩,果然得到了许多文件。这说明文件格式没有损坏,至少我们还能从里面抢救出图片来。图片存放的位置是“\ppt\media\”文件夹。只有图片可能不太够,如果需要幻灯片的文字内容,就要去“\ppt\slides\”文件夹找找。 64 | 65 | {% include figure.html src="7597120be2a238743134cd56647c649b.png" alt="解压缩 pptx 文件" width="640" height="300" %} 66 | 67 | 当然,我还是希望能尽量把这个文件恢复到原来的样子。虽然理论上来说我可以查阅文档来了解它的内部结构,但是似乎时间不是很充足了。我决定司马当活马医,再拆一个 PPT,然后把这个 PPT 的所有幻灯片移过去。 68 | 69 | 我从小弟那里要来了他做这个 PPT 使用的模板,将其后缀名也改为了“.zip”并解压缩。然后,我把错误文件中拆出来的“\ppt\”文件夹下的“media”“notesSlides”“slides”三个文件夹的内容移动到了模板文件中拆出来的对应文件位置,然后重新打包,改后缀名为“.pptx”,打开。振奋人心的事情发生了:它复活了,好像从来没有离开过一样。 70 | 71 | {% include figure.html src="ccd6448c884d387bb952af24f6448fb6.png" alt="焕然一新的 PPT" width="640" height="300.18" %} 72 | 73 | 当然,仔细一看还是有点问题的。距小弟说,这个 PPT 原本有 30 多页,现在只有 19 页了。我返回去看了一下模板,发现模板的页数正是 19 页。这好办,我把模板后面添加了十几张空白页,保存之后又操作了一遍。这次,这个 PPT 才是真正焕发了新生。 74 | 75 | ## 后记 76 | 经过我一通复杂操作,这个“打不开的 PPT”算是找回来了。我正觉得口渴,突然想起来“买奶茶”的承诺,便问小弟:“哎呀,大哥好像有点渴了……” 77 | 78 | 小弟笑着说:“好嘞,给您点奶茶……”突然,他的笑容僵住了,脸上的表情变得复杂了起来。我刚想问他咋回事,就见他说道:“哎呀,我急急忙忙出来,手机忘在宿舍了……” 79 | 80 | 我叹了口气,准备自己去接水。正当我的手伸向水杯时,我眼角的余光看到了他在偷笑。于是,我咳了一声,说:“好吧,那你今晚给我打赏就行。” 81 | 82 | 我并没有看到他之后的表情,但我觉得,他的笑容大概是消失了。 83 | 84 | ## 总结 85 | 1. “C:\Users\\*<当前用户名>*\AppData\”文件夹是隐藏文件夹,需要选中“隐藏的项目”这一复选框才能找到。 86 | 2. 应用商店版 QQ 似乎没有远程桌面功能,如有需要,请下载 Windows 版 QQ。 87 | 3. Office 2007 及以后的版本保存的文档可以直接把后缀名改为“.zip”解压缩,对于 PowerPoint,图片位于“\ppt\media\”,幻灯片位于“\ppt\slides\”。 88 | 4. 对于打不开的 PPT,可以尝试把这个 PPT 和它用的模板一起解压缩,然后把前者“\ppt\”文件夹下的“media”“notesSlides”“slides”三个文件夹的内容移动到后者对应位置,然后压缩并改后缀名为“.pptx”再次打开。 89 | 5. 这次能把 PPT 的内容找到或许只是巧合,要想不丢失文件,最好的方法还是:经常保存。按个“Ctrl + S”的功夫,花不了多少时间。 90 | 6. 点不了奶茶不要紧,点下面的打赏也行。 -------------------------------------------------------------------------------- /assets/css/_variables_override.scss: -------------------------------------------------------------------------------- 1 | $prefix: bs- !default; 2 | $white: #fff !default; 3 | $black: #000 !default; 4 | 5 | $xz-colors: ( 6 | "cold": #de8321, 7 | "warm": #217cde, 8 | ); 9 | $xz-colors-variants-light: ( 10 | "slightly-light": 10%, 11 | "light": 25%, 12 | "lighter": 40%, 13 | "lightest": 46%, 14 | ); 15 | $xz-colors-variants-dark: ( 16 | "slightly-dark": 10%, 17 | "dark": 25%, 18 | "darker": 40%, 19 | "darkest": 46%, 20 | ); 21 | 22 | $white-bg: var(--#{$prefix}body-bg); 23 | 24 | $color-cold: var(--#{$prefix}color-cold); 25 | $color-warm: var(--#{$prefix}color-warm); 26 | 27 | $color-cold-slightly-light: var(--#{$prefix}color-cold-slightly-light); 28 | $color-cold-light: var(--#{$prefix}color-cold-light); 29 | $color-cold-lighter: var(--#{$prefix}color-cold-lighter); 30 | $color-cold-lightest: var(--#{$prefix}color-cold-lightest); 31 | $color-cold-slightly-dark: var(--#{$prefix}color-cold-slightly-dark); 32 | $color-cold-dark: var(--#{$prefix}color-cold-dark); 33 | $color-cold-darker: var(--#{$prefix}color-cold-darker); 34 | $color-cold-darkest: var(--#{$prefix}color-cold-darkest); 35 | 36 | $color-warm-light: var(--#{$prefix}color-warm-light); 37 | $color-warm-lighter: var(--#{$prefix}color-warm-lighter); 38 | $color-warm-lightest: var(--#{$prefix}color-warm-lightest); 39 | $color-warm-dark: var(--#{$prefix}color-warm-dark); 40 | $color-warm-darker: var(--#{$prefix}color-warm-darker); 41 | $color-warm-darkest: var(--#{$prefix}color-warm-darkest); 42 | 43 | $white-bg-rgb: var(--#{$prefix}white-bg-rgb); 44 | $color-warm-lightest-rgb: var(--#{$prefix}color-warm-lightest-rgb); 45 | 46 | $primary: darken(map-get($xz-colors, cold), 12%); 47 | 48 | /* 链接 */ 49 | $link-decoration: none; 50 | 51 | /* 字体 */ 52 | $font-family-sans-serif-latin: "Open Sans", "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans"; 53 | $font-family-sans-serif-chinese: "Source Han Sans CN", "Source Han Sans SC", "Source Han Sans", "Noto Sans CJK SC", "Hiragino Sans GB", "PingFang SC", "Microsoft YaHei"; 54 | $font-family-sans-serif: append(join($font-family-sans-serif-latin, $font-family-sans-serif-chinese), sans-serif); 55 | 56 | $font-family-serif-latin: STIX-Web, "Noto Serif", "Times New Roman"; 57 | $font-family-serif-chinese: "Source Han Serif CN", "Source Han Serif SC", "Source Han Serif", Simsun, serif; 58 | $font-family-serif: append(join($font-family-serif-latin, $font-family-serif-chinese), sans-serif); 59 | 60 | $font-family-monospace-latin: "Source Code Pro", Consolas, "Liberation Mono", "Courier New"; 61 | $font-family-monospace: append(join($font-family-monospace-latin, $font-family-sans-serif-chinese), monospace); 62 | 63 | /* 字号 */ 64 | $font-size-root: 15px; 65 | $font-size-base: 1rem; 66 | 67 | $line-height-base: 1.732050807568877; 68 | 69 | $h1-font-size: $font-size-base * 2; 70 | $h2-font-size: $font-size-base * 1.8; 71 | $h3-font-size: $font-size-base * 1.6; 72 | $h4-font-size: $font-size-base * 1.2; 73 | $h5-font-size: $font-size-base; 74 | $h6-font-size: $font-size-base; 75 | 76 | $headings-font-weight: 600; 77 | $headings-line-height: inherit; 78 | 79 | /* 表格 */ 80 | 81 | /* 导航条 */ 82 | $navbar-light-color: $color-cold-dark; 83 | $navbar-light-bg: $color-cold-lightest; 84 | $navbar-light-border: $color-cold; 85 | 86 | $navbar-light-link-color: $color-cold; 87 | $navbar-light-link-hover-color: $color-cold-dark; 88 | $navbar-light-link-active-color: $color-cold-slightly-dark; 89 | $navbar-light-link-disabled-color: $color-cold-lighter; 90 | 91 | /* 导航 */ 92 | $nav-link-hover-bg: $color-cold-light; 93 | 94 | /* 代码 */ 95 | $kbd-bg: $color-warm-dark; 96 | $kbd-color: $color-warm-light; 97 | 98 | $pre-bg: $color-warm-light; 99 | $pre-color: $color-warm-dark; 100 | $pre-border-color: $color-warm-dark; 101 | 102 | /* 类型 */ 103 | $blockquote-font-size: $font-size-base; 104 | $blockquote-border-color: $color-warm-dark; 105 | 106 | /* Modal */ 107 | $modal-sm: 100%; 108 | $modal-md: 900px; 109 | $modal-lg: 900px; 110 | $modal-xl: 900px; 111 | $modal-content-border-width: 0; 112 | 113 | /* 图标 */ 114 | $bootstrap-icons-font-dir: "https://cdn.jsdelivr.net/npm/bootstrap-icons@1/font/fonts"; 115 | -------------------------------------------------------------------------------- /_posts/2023-03-29-Paranormasight-Translation.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2023-03-29 13:40 3 | head_image: 8641ff9bee2e445e78ec3ce82614590e.jpg 4 | info: 简单记录一下汉化的实现方式,让后人少走点弯路。 5 | last_modified_at: 2023-10-12 17:07 6 | links: 7 | - - https://www.jp.square-enix.com/paranormasight/ 8 | - 游戏官网 9 | - - https://github.com/Xzonn/ParanormasightChsLocalization 10 | - 汉化相关代码 11 | tags: Switch Windows 汉化笔记 12 | title: 《灵异视界 FILE23 本所七大不可思议》汉化笔记 13 | --- 14 |
      15 | **[发布链接](https://xzonn.top/ParanormasightChsLocalization/)** 16 |
      17 | 18 | 本来我没打算买这个游戏,不过我有一个朋友说对这个游戏感兴趣,我就顺便研究了一下。 19 | 20 | {% include video.html bvid="BV1Tc411V7tp" title="《灵异视界 FILE23 本所七大不可思议》文本翻译汉化效果预览及技术实现介绍" %} 21 | 22 | ## 文件格式 23 | 24 | {% include figure.html src="4909c64ee26b53388617f6ebb7514946.jpg" alt="游戏的文件结构,来自
      SteamDB" %} 25 | 26 | 拿到游戏文件后一看结构,“PARANORMASIGHT_Data”“StreamingAssets”几个文件夹直接蹦了出来,一看就知道是Unity做的游戏。直接拿[AssetStudio](https://github.com/Perfare/AssetStudio)读取一下,从`PARANORMASIGHT_Data/resources.assets`、`PARANORMASIGHT_Data/sharedassets0.assets`里找到了[TextMesh Pro](https://docs.unity3d.com/cn/2020.3/Manual/com.unity.textmeshpro.html)的字体文件。这个插件我也不是第一次接触了,[之前]({% link _posts/2022-09-20-AI-The-Somnium-Files-Chs-Patch.md %})我就写过用这个插件修改字体的文章。实际上就是用这个插件拿中文字体重新生成一个字体,然后替换掉原字体的相关信息,再打包回去就行了。 27 | 28 | 但是这两个文件显然没有包含全部游戏内容,继续寻找,发现在`PARANORMASIGHT_Data/StreamingAssets/`文件夹下有很多诸如`a001`、`a002`文件名的文件。拖到AssetStudio里没法直接打开它,拿HxD一看,发现了`UnityFS`的文件头。推测是在Unity的文件格式外面又套了一层不知道什么格式,因此直接尝试简单粗暴的办法,去掉`UnityFS`文件头前面的字节序列,然后把它当成Unity的打包文件修改,修改之后再把字节序列加回去。尝试了一下,这样操作完之后游戏仍然可以读取这个文件,因此勉强能用。 29 | 30 | {% include figure.html src="49c8851795f179a1b859c3ab60be6043.jpg" alt="用HxD查看文件结构" %} 31 | 32 | 批量去除`UnityFS`前的字节序列后,得到了35个文件。为了汉化,我需要关注的是字体和文本。在简单查找并确认后,我发现字体文件位于`a021`、`a035`、`a038`中,而文本位于`a024`、`a036`中。字体同样实用的TextMesh Pro,按照前面所说的方式修改即可。 33 | 34 | ## 文本导出 35 | {% include figure.html src="9668391353c219731044ed9128f4871a.jpg" alt="a036" %} 36 | 37 | 首先关注的是`a036`文件中的文本。这个文件中包含了`Hazy_Localization_JP`和`Hazy_Script_JP`等文本文件,从名字上来看应该就是游戏的文本了。解析起来也不困难,是类似于csv的格式,每行用逗号分隔了文本id和文本内容。虽然看上去像csv,但实际上不能用csv的解析器解析,因为部分文本里面有引号,还有部分文本里有逗号,所以真的只是“类似于csv”而非“就是csv”。 38 | 39 | 导出,修改,导入——这是最简单的流程。但是导入之后发现了新的问题,修改英文文本可以直接显示出来,但是修改日文文本是没有效果的。 40 | 41 | {% include figure.html src="fa147d2657cd658575d9572954710423.jpg" alt="a024" %} 42 | 43 | 再检查一下`a024`文件,这个文件包含的文本是游戏的运行脚本,里面包含了文本id和显示方式。考虑到这是个日本游戏,可以猜测这个游戏的日文版实际上是直接从脚本里读取文本的,而不是从`a036`文件中读取的。因此,如果要基于日文制作汉化的话,需要修改这些运行脚本。并且,游戏脚本中有一些基于游戏语言的判断,在日文和英文条件下文本的显示位置和内容都有细微的差异,但却共用了同一个id。离谱的是,我自己的编写程序从这些脚本中导出的文本实际上与`a036`文件中导出的文本不一致,推测是开发过程中修改了运行脚本但却没有再次导出日文文本(因为实际用不上)。于是我自己实现了文本的导出,并根据新导出的文本制作汉化。 44 | 45 | ## 快速机翻 46 | 47 | 导出文本之后,还要对文本进行翻译。粗略算了一下,需要翻译的文本大概有40万个字符(VS Code数据),全靠人工翻译不太现实,就需要用到机翻了。对于中文↔日文翻译来说,Google翻译、必应翻译和DeepL的效果都很差,因为他们都会先把文本翻译成英文,经过两次转手的翻译结果简直没法看。在经过了对比之后,我决定选择[百度翻译](https://fanyi.baidu.com/)和[有道翻译](https://fanyi.youdao.com/),然后对比两种翻译,选取“比较好的”。 48 | 49 | 关于两种翻译的使用方式,[百度翻译有官方的API](https://fanyi-api.baidu.com/),个人开发者注册并进行实名认证后可以享受“高级版”服务,每月免费使用量为100万字符。而[有道翻译的官方API](https://ai.youdao.com/product-fanyi-text.s)没有每月的免费额度,只是初次注册时送10元的试用额度。当然,能免费用的话还是免费用比较好,所以我还是更喜欢百度翻译一些。不过有道翻译的质量也不差,因此还是需要想办法把它也用上。 50 | 51 | 经过了一些测试,我最终采用了这样的工作流程: 52 | 53 | 1. 将全部文本提取出来,然后将一些片假名专有名词替换为对应的汉字,例如`ヒハク`→`飛白`。 54 | 2. 将替换专有名词后的文本按标点符号分割为句子。标点分割的正则表达式:`re.compile(r"^[^。!?…\!\?\\]*[。!?…\!\?]+[」』”’〜)]?")`。 55 | 3. 将所有句子去重后,按照字典序排序,然后按照每1000行句子为一组,分别写入到多个文件中。 56 | 4. 对分割后的文件进行百度翻译或有道翻译,先用日翻中获得中文,再用中翻日获得日文。 57 | 5. 使用Python自带的`difflib.SequenceMatcher`函数,对原文和两次翻译后获得的日文进行对比,认为相似度较高的翻译算是“比较好的”。将两种翻译及其相似度保存到数据库中。 58 | 6. 将“比较好的”翻译结果按照原文拼接出译文,然后保存成新文件,再进行人工校对。 59 | 7. 校对过程中,如果发现了新的专有名词,就将其加入到专有名词字典中,然后重新进行步骤1;只是无需再将数据库中已翻译过且未修改的句子再次翻译,节省成本。 60 | 61 | 关于人工校对的方式,我采用了[Weblate](https://weblate.org/),这是一个开源的翻译平台,可以用来管理翻译项目。由于Weblate对导入和导出的文件格式有一定要求,为了充分利用Weblate的功能,我加了一道转换过程,将游戏文本转换成了Weblate可识别的csv文件,并对Weblate的代码进行了少许定制。然后,我在GitHub上创建了一个[翻译项目](https://github.com/Xzonn/ParanormasightChsLocalization),并使用了多个分支,其中`master`分支是构建补丁所用的文件,`weblate`分支是喂给Weblate的文件。之后,在Weblate上创建一个项目,并将`weblate`分支的文件导入进去,就可以开始翻译了。翻译完成后,Weblate会自动将译文推送到GitHub的`weblate`分支,通过GitHub Actions的自动部署更新`master`分支,然后自动构建补丁并发布。 62 | 63 | {% include figure.html src="8641ff9bee2e445e78ec3ce82614590e.jpg" alt="导入翻译后的效果" %} -------------------------------------------------------------------------------- /_posts/2020-02-02-How-to-Get-e-Textbooks.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2020-02-02 11:33 3 | head_image: https://mmbiz.qpic.cn/mmbiz_jpg/Qh7FH95PRnuTaCZzkk8vk5TGhAhzR9nUy1iaPNXmBRjjPKuApwQBCcMSibnOEQJpCib1LmEc3N1nLficbnNdBqALlQ/0 4 | head_image_height: 544 5 | head_image_width: 1276 6 | info: Xzonn的技能小讲座第5讲。 7 | last_modified_at: 2020-02-15 14:24 8 | tags: 技术指南 9 | title: 如何获取电子教材? 10 | wechat_link: https://mp.weixin.qq.com/s/QMMHTNPba5_N4OyBoE0d-A 11 | --- 12 | ## 1 13 | 14 | 2020年的寒假似乎有些漫长,为了让寒假变得充实,许多同学下定决心在家自学,然而没有教材成为了一大难题。好在,在2020年的今天,无纸化学习并非不可能。 15 | 16 | 前天(2020/01/31)北京大学学生发展支持(SDS)推出了6篇推送,其中一篇介绍了电子书的获取方法,例如阅读软件、网络资源、国家图书馆等,详见《[云成长,待春归|叮咚~你收到了一份假期学习资源清单](https://mp.weixin.qq.com/s/_QpfF_0DeHr4otqM6_pqBw)》(顺带一提,这篇推送还介绍了其他学习资源,可以好好阅读一下)。然而,教材类图书毕竟受众较少,很多阅读软件不会提供;一些教材可能在互联网上有非正版扫描pdf资源,但也不很全面。这时就需要求助北大图书馆了。 17 | 18 | 或许很少有人知道,北大自建了一个数据库,名为“[北京大学电子教参服务平台](http://162.105.138.126/Usp/)”(该平台仅可校内访问,如在校外访问请使用虚拟专用网络),这个平台甚至连个域名都没有,只有一串IP地址。但不管怎么说,里面收录的教材还是很齐全的,截至目前(2020/02/01)共有18,309条检索结果(不同课程推荐的同一书目会被记作多条检索结果),包括了全校32个开课院系(如果我没数错的话)开设的课程,环院共有125条检索结果。 19 | 20 | {% include figure.html src="3d8b86dc663773cca42ecf87eaf61bb9.png" alt="北京大学电子教参服务平台" width="640" height="360" %} 21 | 22 | 该平台的使用方法很简单,右上角输入课程或教材的名称搜索,或通过左侧索引目录查找。这里的书目一部分是来自图书馆藏书的扫描版(一些书的封面上甚至可以看到条形码),还有一部分来自北大购买的其他数据库(如“阿帕比数字资源平台”“读秀知识库(超星)”等),均提供在线阅读和“借阅”服务。其中来自其他数据库的图书可能会有目录,扫描版图书基本没有目录。 23 | 24 | {% include figure.html src="92759f4170306cdcc603adf0ed38f728.png" alt="在线阅读服务" width="640" height="360" %} 25 | 26 | 尽管有“借阅”服务,但该服务需要下载特殊软件,且一定时间后还需要重新借阅,似乎有些不太方便。于是我又萌生了通过技术手段把它下载到本地的想法。 27 | 28 | ## 2 29 | 30 | [上篇文章](/posts/How-to-Download-Chinese-Standard.html)我曾经说过:既然是在线阅读,那就一定能获取源文件。 31 | 32 | > “Xzonn规则”第一条:只要能用Chrome看的东西都能扒出来源文件和源代码。 33 | 34 | 由于不同种类的图书在线阅读的网页不同,因此需要通过不同方式分析。 35 | 36 | 首先是扫描版的图书和阿帕比数字资源平台的图书,两者使用的是同一系统。调出开发者工具重载页面一看,源文件实际是图片,其URL虽然很长,但同一图书不同页面的URL只改变了页码部分。 37 | 38 | {% include figure.html src="1556cab854054179d1b48fa77d2f43a3.png" alt="用开发者工具查看扫描版图书在线阅读页面" width="640" height="260.58" %} 39 | 40 | 类似如下: 41 | 42 | ``` 43 | http://162.105.138.126/OnLineReader/command/imagepage.ashx?objID=...&pageid=1&ServiceType=... 44 | ``` 45 | 46 | (有省略)可以看出,`pageid=1`即代表了页码。有了这个规律,接下来就是批量下载了,我直接使用了python的requests库实现批量下载: 47 | 48 | ```python 49 | import re 50 | import requests 51 | 52 | BASE_URL = '...'; 53 | PATTERN = re.compile(r'(?<=&pageid=)\d+(?=&)'); 54 | 55 | i = 1; 56 | while True: 57 | r = requests.get(PATTERN.sub(str(i), BASE_URL)); 58 | if r.ok and len(r.content) > 0: 59 | with open("%03d.png" % i, "wb") as f: 60 | f.write(r.content); 61 | print(i); 62 | i += 1; 63 | else: 64 | break; 65 | ``` 66 | 67 | 这里使用了正则表达式,之后我可能会单独写篇文章探讨一下,这里不是重点不再赘述。注意此处使用了`len(r.content) > 0`与否来判断是否超出页码范围,超出范围的部分返回长度为0。 68 | 69 | 而读秀知识库(超星)平台与上述类似,区别有两处:第一,图片链接多了一步302重定向,因此需要查找原始网址;第二,该平台超出页码范围会返回有错误说明的图片,因此需要修改终点判定方式。此处不再给出代码,读者可自行尝试。 70 | 71 | 下载下来的一堆图片可以用Adobe Acrobat的“合并文件”功能存为一个pdf文件,然后用“增强扫描”→“识别文本”功能将图片转为可选中的文本,详见[上篇文章](/posts/How-to-Download-Chinese-Standard.html)。另外,可以用“组织页面”→“更多”→“页面标签”功能修改页码,留待之后再说。 72 | 73 | {% include figure.html src="e35fb4644d871f9caa9f00ba4e3d32bc.png" alt="合并为一个pdf文件" width="640" height="273.02" %} 74 | 75 | ## 3 76 | 77 | 多说几句。北大其实不仅提供了电子教参,还提供了其他中西文电子书资源。在北大图书馆网站的首页就可以看到: 78 | 79 | {% include figure.html src="df0283cbaebf8becc9ecf9ab3f4654b5.png" alt="北大图书馆电子期刊/图书导航" width="640" height="360" %} 80 | 81 | 然而根据我个人的体验,这个检索系统的搜索结果页面似乎很难载入,至少我试了几次还没载入过。因此,我个人建议点击上图“新手指南”中的“中外文电子图书资源简介”,这里盘点了提供中外文电子图书的数据库名称,然后可以直接从各个数据库内检索。 82 | 83 | {% include figure.html src="e2127bc8f1509e13f8c426b2603735b3.png" alt="中外文电子图书资源简介" width="640" height="904.92" %} 84 | 85 | 例如在“‘读在燕园’”互联网数字图书馆检索“化学”: 86 | 87 | {% include figure.html src="c706d5aead1273b16527b24fa852e34b.png" alt="在“‘读在燕园’”互联网数字图书馆检索“化学”" width="640" height="360" %} 88 | 89 | ## 4 90 | 91 | 再多说几句。说实话,北大提供的学习资源不少,但我基本没有了解使用过。我得知教参服务平台的契机是我复习的时候想要查阅教材而没有在网络上找到资源,于是去了图书馆想要借阅纸本,发现纸本封面上写着“有电子版”,询问了工作人员才得知。如果有机会的话,我倒是希望仔细了解一下北大购买了哪些有趣的数据库。 92 | 93 | 这个寒假我打算多写几篇乱七八糟的文章,自我学习,也帮助大家学习。 94 | 95 | ## 5 96 | 97 | 总结一下我今天写了啥: 98 | 99 | 1. 假期学习资源请参考SDS的推送:《[云成长,待春归|叮咚~你收到了一份假期学习资源清单](https://mp.weixin.qq.com/s/_QpfF_0DeHr4otqM6_pqBw)》。 100 | 2. 北京大学电子教参服务平台提供了许多课程的教材电子资源,可以在线阅读或借阅。 101 | 3. 北大还提供了其他丰富的中外文电子图书资源,等待大家探索。 -------------------------------------------------------------------------------- /_posts/2023-11-06-Jellyfin-Plugin-Douban.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2023-11-06 22:05 3 | head_image: e7fc8fe18df5ee4f638996a6df6e67ae.webp 4 | info: 自力更生。 5 | last_modified_at: 2024-12-09 22:36 6 | links: 7 | - - https://github.com/Xzonn/JellyfinPluginDouban 8 | - JellyfinPluginDouban 9 | - - https://kk.sb/2023/use-jellyfin-to-organize-anime-library.htm 10 | - 使用 Jellyfin 搭建二次元媒体库 11 | references: 12 | - - https://github.com/caryyu/jellyfin-plugin-opendouban 13 | - jellyfin-plugin-opendouban 14 | - - https://github.com/kookxiang/jellyfin-plugin-bangumi 15 | - jellyfin-plugin-bangumi 16 | tags: 作品发布 17 | title: Jellyfin 豆瓣元数据插件 18 | --- 19 | [电脑组装了半年了]({% link _posts/2023-05-28-DIY-My-Computer.md %}),硬盘里也存了不少番剧、日剧和电影,所以我打算整理一下,搭个媒体库。原本是想用Emby,但是这玩意稍微搞点啥操作都要会员,搞不懂了,又不用你家服务器还要开会员?后来发现Emby原来是开源的,后来闭源了,而[Jellyfin](https://jellyfin.org/)就是从Emby最后一个开源版本演化过来的。开源软件,好!闭源软件,不好! 20 | 21 | 不过Jellyfin只是个媒体库平台,视频还是需要自己提供,并且需要对视频按照文件夹分类。分好类之后还需要想办法收集元数据,这样才能在Jellyfin里看到漂亮的封面和简介。Jellyfin官方提供了一个[TMDB](https://www.themoviedb.org/)网站的元数据插件,但因为众所周知的原因不太好用。也有人开发了用于豆瓣的元数据插件[jellyfin-plugin-opendouban](https://github.com/caryyu/jellyfin-plugin-opendouban),我试了一下还不错,不过因为要起一个Docker,稍微有些麻烦。于是我参考了这个插件以及bgm.tv的元数据插件[jellyfin-plugin-bangumi](https://github.com/kookxiang/jellyfin-plugin-bangumi),自己写了一个[豆瓣元数据](https://github.com/Xzonn/JellyfinPluginDouban)插件出来。 22 | 23 | ## 功能和特性 24 | 相较于[jellyfin-plugin-opendouban](https://github.com/caryyu/jellyfin-plugin-opendouban),本插件增加了一些功能和特性以增强体验: 25 | 26 | - 无需额外运行Docker容器,对Windows用户更友好。 27 | - 搜索时根据“电影”或“电视剧”分类进行排序,避免关联到不恰当的条目。例如,当前(2023年11月6日)直接[搜索《名侦探柯南》](https://www.douban.com/search?cat=1002&q=%E5%90%8D%E4%BE%A6%E6%8E%A2%E6%9F%AF%E5%8D%97)得到的第一条结果是电影《名侦探柯南 黑铁的鱼影》而不是动画《名侦探柯南》,这可能是考虑到了最新作电影更有人气而将搜索顺位提前,但是对于收集元数据来说很不方便。而进行排序后,如果指定视频类型为“节目”,则会将分类为“电视剧”的条目排在前面,就可以得到正确的结果。 28 | - 对元数据中标题的处理更加准确。当影视的译名中存在空格时,原插件无法准确识别原名和译名的分割,而本插件通过其他标签辅助判断,能够推断出准确的原名和译名。 29 | - 使用内置Api和[AnitomySharp](https://github.com/chu-shen/AnitomySharp)根据文件名判断视频标题,搜索结果更加准确。 30 | - 增加了对单集剧集的元数据的支持。但据我个人的使用经验,豆瓣的单集剧集的条目内容良莠不齐,有些集数的介绍甚至是对剧情的吐槽,所以请自行选择是否开启。 31 | - 支持访问速率控制,并且内置了缓存机制,避免频繁访问豆瓣服务器导致被封禁。 32 | 33 | {% include figure.html src="7fd1e025c4f1502aff165f0ca0373310.jpg" alt="获取元数据后的效果" %} 34 | 35 | ## 安装方式 36 |
      37 | **注意**:Jellyfin 10.9.x版本和10.10.x版本的插件互相不兼容。对于Jellyfin 10.9.11版本,请使用本插件的2.x版本;对于Jellyfin 10.10.0及以上版本,请使用本插件的3.x版本。 38 |
      39 | 40 | ### 插件库 41 | - 打开控制台,选择`插件`→`存储库`→`添加`。 42 | - 在`存储库 URL`处填入:[`https://xzonn.top/JellyfinPluginDouban/manifest.json`](https://xzonn.top/JellyfinPluginDouban/manifest.json)。 43 | - 在插件目录中找到Douban插件,选择安装。 44 | - 重启Jellyfin。 45 | 46 | ### 手动安装 47 | - 下载插件压缩包,将dll文件解压至 `/Plugins/Douban`。 48 | - 重启Jellyfin。 49 | 50 | ## 已知问题 51 | ### 关于速率限制 52 | 由于豆瓣目前已经没有公开的api,所有请求均基于直接获取相关网页,过快的访问速率可能会被视为恶意爬取软件而被封禁。为了尽可能避免被封禁,请尝试调整设置选项: 53 | 54 | 1. 增加每两次请求之间的时间间隔。默认设置为2秒。 55 | 2. 填入Cookie。请使用浏览器打开[豆瓣电影](https://movie.douban.com/)并登录,然后按F12打开控制台,选择`Network`,刷新页面,选择`movie.douban.com`,在右侧的`Headers`中找到`Cookie`,复制其内容并填入设置选项中。 56 | 57 | 此外,在不带Referer获取豆瓣的图片时会被限速至10KB/s左右,这可能会导致获取元数据时超时,部分剧集无法正常显示。可在本插件的设置中取消“在影视页面获取演职员照片”的勾选,这可以防止Jellyfin在获取影视元数据时大量获取演职员的图片导致超时。 58 | 59 | 速率限制可以通过搭建反代来回避,插件自带了一个反向代理,可在设置选项中修改“豆瓣图片服务器”使用。例如,如果服务器地址为`http://localhost:8096/`,则本插件的反代地址为`http://localhost:8096/Plugins/Douban/Image?url=`(注意最后有一个等号 `=`)。 60 | 61 | 也可以自行搭建反代,以下是一个简单的nginx本地搭建反代的配置文件示范: 62 | 63 | ``` nginx 64 | server { 65 | listen 80; 66 | listen [::]:80; 67 | charset utf8; 68 | server_name doubanio.localhost; 69 | location / { 70 | proxy_pass https://img2.doubanio.com; 71 | proxy_set_header Host img2.doubanio.com; 72 | proxy_set_header Referer https://movie.douban.com/; 73 | } 74 | } 75 | ``` 76 | 77 | ### 部分影视无数据 78 | 豆瓣限制了部分影视仅在登录状态下可见([例](https://movie.douban.com/subject/26752722/)),这可能导致部分影视无法获取到元数据。如果遇到这种情况,请登录并填入Cookie(参见[上一步](#关于速率限制)),或者手动填写豆瓣ID。 79 | 80 | ### 季的内容为空 81 | 由于Jellyfin自身的缺陷,如果将视频文件直接存放在一级子目录下(例如`/(根目录)/剧名/[XXSub] Bangumi Name - 01.mp4`),Jellyfin会自动生成一个季,导致插件的解析出现错误。3.3.1版本已尝试修复了此问题,但仍可能存在问题。建议将视频文件存放在季的子目录下(例如`/(根目录)/剧名/第1季/[XXSub] Bangumi Name - 01.mp4`,[参考资料](https://www.himiku.com/archives/deploy-a-more-comfortable-animation-library-with-jellyfin-and-bangumi.html))。 82 | 83 | ## 更新日志 84 | [见此](https://github.com/Xzonn/JellyfinPluginDouban/blob/master/ChangeLog.md)。 85 | 86 | ## 写在最后 87 | 感谢两个插件的作者对本插件的启发。 -------------------------------------------------------------------------------- /_posts/2021-11-15-Download-Pdf-File-from-Cnki.md: -------------------------------------------------------------------------------- 1 | --- 2 | class: auto-numbering 3 | date: 2021-11-15 16:14 4 | head_image: 5ce33e735d637decf48b2cb2c2637f54.png 5 | info: 让浏览器访问硕博论文时自动跳转到中国知网“海外版”。 6 | last_modified_at: 2023-06-16 22:59 7 | logs: 8 | - 2022-03-26:修复正则表达式匹配不全的问题。 9 | tags: 技术指南 10 | title: 关于我在中国知网下载硕博论文pdf格式文件这件事 11 | wechat_link: https://mp.weixin.qq.com/s/w8KTRrs5akWCQ8nCWnreIg 12 | --- 13 | 14 | 15 | **2023-06-02更新**:目前知网“海外版”屏蔽了中国大陆的IP访问,并且中国大陆的高校无法使用机构登录。但是目前中国大陆版本的知网已经开始提供PDF下载链接。 16 | 17 | ## 前言 18 | 众所周知,中国知网(CNKI)为了推广自家的“caj”格式,故意不提供硕博论文的pdf格式下载。点开硕博论文的介绍页,里面提供的只有“caj”格式的“整本下载”,而没有pdf格式。至于这个“caj”格式,除了知网自家的阅读器之外根本打不开,给学术研究造成了极大不便。此前曾有人编写了[下载pdf的脚本](https://greasyfork.org/scripts/18842),可以在硕博论文的介绍页提供“pdf下载”的按钮,但在知网网站更新后已失效,而作者的[个人网站](http://blog.yuelong.info/post/cnki-pdf-js.html)也已无法打开。 19 | 20 | 在简单搜索后,我发现了一个新思路:虽然[中国知网](https://www.cnki.net/)在官网上提供的是“caj”格式,但是中国知网还有个[“海外版”](https://chn.oversea.cnki.net/),在这个“海外版”中不仅没有了烦人的广告,连论文下载都变得听话了很多,虽然仍然有阴魂不散的“caj”格式,但至少提供了一个下载pdf格式的链接,而北京大学图书馆也拥有“海外版”的下载权限。不过以我个人的体验来看,“海外版”在中国大陆的访问速度并不算快,因此我想到可以使用“海内版”查文献、“海外版”下载硕博论文。 21 | 22 | **注意:能够下载pdf文件的前提是拥有下载权限,这篇文章不是在教怎么白嫖文献。** 23 | 24 | {% include figure.html src="aeece7ff01d2c143688ed818bd47ee47.png" width="960" height="540" alt="中国知网" %} 25 | 26 | {% include figure.html src="5ce33e735d637decf48b2cb2c2637f54.png" width="960" height="540" alt="中国知网“海外版”" %} 27 | 28 | {% include figure.html src="a73c659c14539733d7aaf8011d3ab68a.png" width="801" height="88" alt="中国知网的下载按钮" %} 29 | 30 | {% include figure.html src="febe086cb1ad4d24c844151bce3a2c28.png" width="917" height="88" alt="中国知网“海外版”的下载按钮" %} 31 | 32 | ## 手动修改URL 33 | 简单探索一下可以发现,对于同一篇硕博论文,中国知网的链接与“海外版”的链接格式是相同的,仅仅是域名不同。例如,对于某篇论文,其在中国知网上的链接是: 34 | 35 | ``` 36 | https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CDFD&dbname=CDFD1214&filename=1014124155.nh&uniplatform=NZKPT&v=NJHJizxoAuPQFhVvCSqHauxz8fdIJxmKbAjmhVNHHzRp6W8VeQT6ysHFH2BYxedD 37 | ``` 38 | 39 | 而其在海外版的链接是: 40 | 41 | ``` 42 | https://chn.oversea.cnki.net/kcms/detail/detail.aspx?dbcode=CDFD&dbname=CDFD1214&filename=1014124155.nh&uniplatform=NZKPT&v=NJHJizxoAuPQFhVvCSqHauxz8fdIJxmKbAjmhVNHHzRp6W8VeQT6ysHFH2BYxedD 43 | ``` 44 | 45 | 也就是将开头的`https://kns.cnki.net/`替换为了`https://chn.oversea.cnki.net/`。虽然方法很简单,但在大量查阅论文时手动修改还是比较麻烦的,因此需要探索一下自动跳转的方式。 46 | 47 | ## 使用“Header Editor”实现自动跳转 48 | [Header Editor](https://he.firefoxcn.net/)是一个浏览器扩展,可以修改请求头、响应头或进行重定向。此处我们可以制定一个简单的重定向规则,将硕博论文的详情页直接重定向到“海外版”中国知网。扩展的安装方式请参考官网给出的链接。 49 | 50 | 在扩展中增加一条规则,命名为“中国知网海外版”,规则类型为“重定向请求”,匹配类型为“正则表达式”,匹配规则为: 51 | 52 | ``` 53 | ^https?://kns\.cnki\.net/(.*=(?:CMFD|CDFD)&.*)$ 54 | ``` 55 | 56 | 执行类型为“常规”,重定向至: 57 | 58 | ``` 59 | https://chn.oversea.cnki.net/$1 60 | ``` 61 | 62 | 随后保存。如果一切正常,那么现在访问中国知网的硕博论文详情页已经可以自动跳转到海外版的网站了。 63 | 64 | {% include figure.html src="b9aa4241c15b96b04716d9d7df5d14c4.png" width="960" height="540" alt="Header Editor的设置" %} 65 | 66 | 如果添加有问题,可以尝试扩展的“导出和导入”选项卡中的“下载规则”,输入: 67 | 68 | ``` 69 | https://pastebin.com/raw/MxVbMrZa 70 | ``` 71 | 72 | 然后按照提示保存即可。 73 | 74 | ## 使用用户脚本替换搜索页链接 75 | 在浏览器中有些扩展可以提供用户脚本以便实现附加功能。[Tampermonkey](https://www.tampermonkey.net/)是一个常见的加载用户脚本的扩展,因此只需要编写一个脚本就可以替换搜索页的链接。扩展的安装方式请参考官网给出的链接。 76 | 77 | 脚本的思路比较简单,即在访问知网的搜索页面并点击链接时,自动识别该链接是否是硕博论文,如果是则修改链接地址到“海外版”。核心代码如下: 78 | 79 | ```javascript 80 | let changeLink = function (e) { 81 | let target = e.target; 82 | while (target.tagName.toLowerCase() != "a") { 83 | if (target.tagName.toLowerCase() == "body") { 84 | return; 85 | } 86 | target = target.parentNode; 87 | } 88 | if (target.href && target.href.match(/^https?:\/\/kns\.cnki\.net\/(.*=(?:CMFD|CDFD)(?:&.*)?)$/)) { 89 | target.href = target.href.replace(/^https?:\/\/kns\.cnki\.net\/(.*=(?:CMFD|CDFD)(?:&.*)?)$/, "https://chn.oversea.cnki.net/$1"); 90 | } 91 | }; 92 | document.body.addEventListener("mousedown", changeLink); 93 | document.body.addEventListener("click", changeLink); 94 | ``` 95 | 96 | 我已经发布在了[Greasy Fork](https://greasyfork.org/zh-CN),网址:。 97 | 98 | ## 后记 99 | “海外版”的存在,让下载pdf格式的硕博论文成为了可能。希望互联网上能够少一些私有格式,多一些通用标准,让“网上冲浪”减少一些阻碍。 100 | 101 | **再次提醒:能够下载pdf文件的前提是拥有下载权限,这篇文章不是在教怎么白嫖文献。** 102 | 103 | -------------------------------------------------------------------------------- /_posts/2019-11-26-Managing-Chinese-Literature-with-EndNote.md: -------------------------------------------------------------------------------- 1 | --- 2 | class: auto-numbering 3 | date: 2019-11-26 12:00 4 | head_image: https://mmbiz.qpic.cn/mmbiz_jpg/Qh7FH95PRnuXsKbo6P2vzJ5gyibs6g4lF7VEU4vMicFmaTeul8xt9NyUG5AibhKCscKV5lK4OfJkTOaBhK9VWyQgQ/0 5 | head_image_height: 853 6 | head_image_width: 1280 7 | info: EndNote 其实也是可以管理中文文献的。 8 | last_modified_at: 2022-05-23 15:13 9 | tags: 技术指南 10 | title: 用 EndNote 管理中文文献 11 | wechat_link: https://mp.weixin.qq.com/s/gTwaB7uqqNfTbg0UgsL4zw 12 | --- 13 | ## 前言 14 | 一个月前(2019 年 10 月 20 日)环院学生会邀请了 2019 级博士生陈龙师兄介绍了 EndNote 软件的食用指南,想必各位都有不少收获。如果想回顾这场讲座的内容,请移步哔哩哔哩: 15 | 16 | {% include video.html aid="71909726" page="1" %} 17 | 18 | 作为本科生,我个人平时写课程论文时的参考文献还是以中文文献为主的。奈何 EndNote 对中文文献管理的支持并不算太好,想要用 EndNote 管理中文文献可能还需要花费一点功夫。最近趁着 18 本的小朋友在写《环境科学》文字报告、19 本的小朋友在准备《环境问题》课堂展示,我也分享一些个人使用 EndNote 管理中文文献的经验,希望对大家有所帮助。 19 | 20 | ## 为啥要用 EndNote 21 | 第一,**EndNote 可以管理文献**。如果把文献实体化为一本本书,那么知网等数据库就像是北京大学图书馆,里面的藏书非常丰富。但我们在写论文、作报告的时候并不会把数据库里所有的文献都阅读一遍(就像我们不会把北大图书馆的书都搬出来一样,当然,如果能周读文献 3000 页当我没说),而是会选取对报告内容有用的文献进行阅读(就像我们从图书馆中借书后放在自己的书架上一样)。此时,EndNote 就像书架一样,可以用来分类管理我们选取的文献。 22 | 23 | 第二,**EndNote 可以管理文献插入文章中的格式**。对于本科生来说,大部分课程论文、报告等对于参考文献的引用格式要求都是 GB/T 7714-2015《信息与文献 参考文献著录规则》。尽管许多数据库(如知网)和搜索引擎(如百度学术)都直接提供了符合 GB/T 7714-2015 标准的引用格式,但它们提供的格式还是有略微不同(例如百度学术会在逗号后面加空格,而知网不会),对于追求格式规范的朋友来说还是不够完美。另外,在正文中插入参考文献时需要用对文献进行标号([1]、[2]、[3]等),如果用手动标号的方法,一旦之后对文本顺序进行调整,后果不堪设想。(我知道 Word 可以插入尾注,也能插入引文,但是效果都不咋好) 24 | 25 | 虽然我只能想到这两条理由,但是我觉得足够了。原因说得再多都是废话,下面才是真正有用的东西。 26 | 27 | ## EndNote 的安装 28 | **注:以下操作均基于 64 位 Windows 10 操作系统,本人使用的 EndNote 版本为 EndNote X9.2。其他操作系统或软件版本操作方法应该类似。** 29 | 30 | “北京大学正版软件共享平台”(http://software.pku.edu.cn/)上已经提供了正版 EndNote 的下载,也提供了安装说明。在下载压缩包后需将 .msi 文件和 License.dat 文件放在同一个文件夹中(后者是许可证文件,用于正版软件激活),随后打开 .msi 文件,按照说明安装即可。**注意:程序默认安装位置是“C:\Program Files (x86)\EndNote X9”,如果此处修改了安装位置,请先记下来以便后续操作。** 31 | 32 | 安装完毕后,打开软件。初次使用时需要创建一个“Library”,这便相当于前文所说的“书架”,之后导入的所有数据都会存放在 Library 中。此时在 Library 所在的文件夹中还会出现一个名为“\*.Data”(\* 代表文件名)的文件夹,里面存放了数据文件,不可删除。 33 | 34 | ## 将文献导入 EndNote 35 | ### 1. 从数据库或搜索引擎导入 36 | 许多数据库或搜索引擎都提供了可用于导入 EndNote 的文件。以知网为例,搜索页面的每个条目前都有复选框,当选中复选框后单击右侧“已选文献”,页面右下角会出现“已选文献”文本框。点击“导出/参考文献”后,再从左边的列表中找到“EndNote”,点击“导出”,即可得到一个 .txt 文件。百度学术等网站的导出方式类似。 37 | 38 | 然后,从文件资源管理器中,右键单击从网站上导出的数据文件,从“打开方式”中选择“EndNote X9...”即可导入此文件。 39 | 40 | 或者,也可从 EndNote 软件菜单栏中选择File → Import → File,在“Import File”中选择对应的文件,在“Import Option”中选择“EndNote Import”即可。 41 | 42 | 此种方法导入的文献并不会附带文献原文 pdf,需要手动添加。方法是选中单篇文献,点击右侧预览框上方的“曲别针”图标,然后选择对应的 pdf。 43 | 44 | ### 2. 从 pdf 导入 45 | 这个方法其实是我现学现卖的。一般从外文数据库下载的 pdf 文件都会保留 DOI(Digital Object Identifier,数字对象标识符)信息,此时将 pdf 导入 EndNote 后,软件会从数据库查找文献的信息并存入 Library 中。导入方法与上文类似。 46 | 47 | 此种方法导入的文献会自动附带导入的 pdf 文件,但是对于大部分中文期刊来说并不适用。 48 | 49 | ### 3. 手动输入 50 | 一般来说,如果需要对网页进行引用,则需要手动输入。此处也以网络文献为例讲解手动输入的方法: 51 | 52 | 从 EndNote 软件菜单栏中选择References → New Reference,然后从出现的表单中进行填写。首先在第一行“Reference Type”中选择“Web Page”,然后依次填写以下项: 53 | 54 | - Author:作者。 55 | - Title:标题。 56 | - Access Date:获取日期,YYYY-MM-DD 格式(如:2019-11-25)。 57 | - Last Update Date:最后更新日期,YYYY-MM-DD 格式,可留空。 58 | - Type of Medium:文献类型,参考 GB/T 7714-2015。常用:电子公告 EB(一般我不知道该用什么就用它);报纸 N;数据库 DB。 59 | - URL:网址。 60 | 61 | 其他项可填可不填,GB/T 7714-2015 中未对其他项进行要求。输入完毕后,保存关闭即可。 62 | 63 | ## 在 Word 中使用 EndNote 64 | ### 1. 插入参考文献引用 65 | 安装 EndNote 后,Word 的菜单栏会出现一个名为“EndNote X9”的选项卡。从此选项卡中可以直接插入参考文献引用。如果已在 EndNote 软件中选中要插入的文献,可直接选择Insert Citation → Insert Selected Citation(s)。否则,则选择Insert Citation → Insert Citation,从打开的对话框中搜索所需的文献。 66 | 67 | 插入引用后,软件会自动在文档最后插入所有被引用的参考文献。从选项卡上方的“Style”下拉菜单可以选择参考文献列表的格式,需要注意的是 GB/T 7714-2015 格式并不在默认的格式中,需要手动添加(见下文)。 68 | 69 | 如果在正文中修改了文献引用顺序,或对引用有所增添,可选择“Update Citations and Bibliography”,软件会自动更新标号。 70 | 71 | ### 2. 修改参考文献列表的格式 72 | 由于 EndNote 默认格式中没有 GB/T 7714-2015 格式,而官网给出的格式也有一些问题,所以建议大家直接下载本人修改过的版本: 73 | 74 | 75 | 76 | 还记得前文所述的安装位置吗?将“Chinese Std GBT7714 (numeric) Copy.ens”文件复制到安装位置文件夹下的“Styles”文件夹下(如果是默认安装路径,则应为“C:\Program Files (x86)\EndNote X9\Styles”),然后即可从上文所述的样式列表中找到这一格式。(如果下拉菜单中无此格式,则需选择“Select Another Style”,然后从对话框中搜索) 77 | 78 | 需要注意的是,该格式默认在作者超过 3 位时对第 4 位及以后的作者名用“等”代替,而引用英文文献时应换为“et al”。这可以在 EndNote 菜单栏中的 Edit → Output Styles → Edit "Chinese Std GBT7714 (numeric) Copy" → Bibliography → Author Lists 中修改,但不支持中英文同时存在的情况。如有这种需求,建议在正文定稿后复制全部参考文献列表,然后手动修改。 79 | 80 | ## 后记 81 | 本文写得有些仓促,内容可能也不算太完善,希望大家多多交流,共同进步。 82 | 83 | ## 参考文献 84 | 1. {: #ref-chen-long }陈龙. Endnote 使用经验分享 [Z/OL]. (2019-10-20) [2019-11-25]. . 85 | {: .endnoteRefList .square} -------------------------------------------------------------------------------- /_posts/2019-03-02-Pokemon-Tweaking.md: -------------------------------------------------------------------------------- 1 | --- 2 | class: auto-numbering 3 | date: 2019-03-02 12:00 4 | head_image: 48f542abdecfe0d46966b557d0b6f6b0.png 5 | head_image_height: 384 6 | head_image_width: 256 7 | infobox: incomplete pokemon pokemonGlitch 8 | last_modified_at: 2020-01-03 23:02 9 | tags: DS 任天堂 宝可梦 10 | title: 《精灵宝可梦》地图图块漏洞 11 | --- 12 | {% include figure.html src="48f542abdecfe0d46966b557d0b6f6b0.png" alt="漏洞触发后的效果" width="256" height="384" %} 13 | 14 | ## 概述 15 | **地图图块漏洞**是存在于第四世代《精灵宝可梦》系列游戏中的游戏漏洞。此漏洞在英文玩家中也被称为“Tweaking”。该漏洞通过快速切换地图图块,使游戏产生载入错误,并可以使玩家进入原本无法进入的区域,走出地图并进入“谜之空间”。此漏洞最早由 GameSpot 论坛的用户 Holepunch 发现,但原贴如今已经不存在。 16 | 17 | ## 漏洞原理 18 | 在全部第四世代游戏中,所有的地图都以 32 × 32 格大小的区块存储。游戏同时可以读取 4 个区块,即玩家所在的区块以及相邻的 3 个区块。在区块中间具有不可见的“载入线”,当玩家通过这条线时,下一个区块将会被读取。当玩家以最高速骑着自行车通过载入线时,游戏载入区块的速度慢于玩家通过的速度,这样会触发“竞争冒险”机制,可能会使游戏冻结、出现不可见的墙、出现黑色区域、出现白色区域、Z 轴改变、载入其他区块等。 19 | 20 | 消除载入错误的方法包括正常通过新的载入线,或是打开任意菜单后返回等。此时区块将被重新读取。 21 | 22 | 此外,通过跑步、冲浪等也可以触发此漏洞。 23 | 24 | ## 触发方式 25 | {% include figure.html src="cd4b3a2ec058fec68bde3e5d168ef2f9.png" alt="图例" width="200" height="200" %} 26 | 27 | 以右图为例,蓝色的线代表载入线(即图块的中线),数字代表玩家所在的区域。在下述方式中,所有图案均可以翻转或旋转。 28 | 29 | ### 同方向替换 30 | “3124343”(高速自行车):以发现者 Zorch 命名,也是最初发现的可靠的触发方式。此方式使玩家右侧的区块以黑色区域载入到玩家左侧。它被之后发现的“Shortzorch”法替代。 31 | 32 | “42121”(高速自行车):被称为“Shortzorch”,同上。 33 | 34 | “31213”(高速自行车,白金/心金/魂银):使玩家右侧的区块以可见的形式载入到玩家左侧。在钻石/珍珠中,由于自行车速度不同,此方法会使游戏冻结。 35 | 36 | “42131”(低速自行车、跑步、冲浪,白金/心金/魂银):低速自行车使玩家右侧的区块变为黑色、可行走的区域并有一部分或没有 NPC,跑步使玩家右侧的区块变为不可行走但可见的区域并有一部分或没有 NPC,冲浪使玩家右侧的区块变为可行走、可见的区域并有一部分或没有 NPC。还可以用跑步以“1242131”的方式触发相同的效果。 37 | 38 | “421312D21”(高速自行车):使玩家下方的区块以可见的形式载入到玩家上方。“D”表示“2”右侧的一格。 39 | 40 | ### 对角线替换 41 | “12421”(低速自行车):使玩家左上方的区块以可见的形式载入到玩家右上方。 42 | 43 | “1242131”或“13431”(低速自行车):使玩家左下方的区块以可见的形式载入到玩家右下方。当以“1242131”方式时还会使玩家上方的区块不可行走。 44 | 45 | ## 拓展 46 | ### 捷径 47 | 这一漏洞可以使一些可行走的区块被载入到原来不可行走的区块的位置,因此可以产生一些捷径,例如在《心金/魂银》中在27号道路的岩壁上加在可行走区块,使无需秘传学习器07便跳过都城瀑布等。在一些被 NPC 阻挡的建筑的图块,玩家可以通过改变 Z 轴通过 NPC 正常占据的图块。这可以使玩家在《钻石/珍珠/白金》中于拿到第一个徽章前即进入祝庆电视台获得神秘礼物,或者在《心金/魂银》中于呆呆兽之井剧情前即打败桧皮道馆(但玩家仍需要完成次剧情并打败兰斯,之后才能在桐树林触发大葱鸭的剧情)。 48 | 49 | 这类捷径在全部第四世代游戏中均可用。 50 | 51 | ### 谜之空间漏洞 52 | 谜之空间漏洞仅在《珍珠/钻石》中有效。玩家需要将含有可通过区域的区块载入到原本含有建筑的区块上,并移动到建筑物入口的上方一格。随后重新载入区域并向下进入建筑,此时玩家将进入到正常地图的下方,与四天王房间冲浪漏洞类似。通过这种方法可以进入新月岛或花之乐园捕捉达克莱伊/谢米。 53 | 54 | 在前往新月岛或花之乐园时,玩家需要在谜之空间保存游戏,这可能会使玩家被困在错误的地图中无法出来。最坏的情况是,游戏在读取存档时立即重启,玩家必须创建新的存档。一种方法是在保存存档前查看菜单中的其它选项后返回,如果游戏冻结,则可以保护存档不受损失。 55 | 56 | 在捕捉达克莱伊/谢米的方法被发现后,许多玩家开始尝试前往初始之间捕捉阿尔宙斯。但直到 2017 年,朋友公园返回漏洞被发现后,捕捉阿尔宙斯才成为了现实。 57 | 58 | 由于溢出,移动 65536 步以上会使游戏不再载入黑色的区域,而是会载入正常的区域,这被称作是“假神奥”或“假城都/关都”。 59 | 60 | 在《白金/心金/魂银》中,谜之空间中有许多看不见的墙,这会使玩家陷在谜之空间中,因此这一漏洞在这三部游戏中难以实现,除非使用特殊手段。 61 | 62 | #### 捕捉阿尔宙斯 63 | 利用“朋友公园返回漏洞”可以捕捉阿尔宙斯。[[4](#ref-4)]步骤如下(原文如此,详细说明请参考原贴): 64 | 65 | ``` 66 | ======= 67 | Step 1 68 | ======= 69 | 1 S 70 | 17 W 71 | 14 N 72 | 2015 W 73 | 512 S 74 | Save & Reset 75 | 76 | ======= 77 | Step 2 78 | ======= 79 | 32 E 80 | 384 S 81 | 32 W 82 | 1792 S 83 | 128 W 84 | 32 S 85 | 192 W 86 | 64 S 87 | 160 W 88 | 89 | ======= 90 | Step 3 91 | ======= 92 | 96 S 93 | 96 E 94 | 32 S 95 | 63 E 96 | 1 N 97 | 63 E (or 64 E if you've already been to Pal Park before) 98 | 191 N 99 | 1 N (注1) 100 | 101 | ======= 102 | Step 4 103 | ======= 104 | 192 E 105 | 66 S 106 | 1 N 107 | 108 | ======= 109 | Step 5 110 | ======= 111 | 192 W 112 | 64 N 113 | 64 W 114 | 32 N 115 | 128 W 116 | 64 N 117 | 64 W 118 | 96 N 119 | 226 E 120 | Start -> RETIRE 121 | 122 | ======= 123 | Step 6 124 | ======= 125 | 34 S 126 | 33 W 127 | 128 S 128 | 160 W 129 | 160 S 130 | 160 E 131 | 31 S 132 | 1 S 133 | 64 E 134 | 166 N 135 | 1 N 136 | Start -> RETIRE 137 | 138 | ------ 139 | 注1:根据本人测试,如果玩家已经进入过朋友公园,此处不需要向上 1 格。 140 | ``` 141 | 142 | ## 参考视频 143 | {% include video.html aid="44978212" page="1" %} 144 | 145 | {% include video.html aid="44978212" page="2" %} 146 | 147 | {% include video.html aid="47147308" page="1" %} 148 | 149 | ## 参考资料 150 | 1. Bulbapedia. Tweaking[OL]. (2018-05-04) [2019-03-02]. . 151 | 2. Johnstone. POKEMON GLITCHES: The Tweaking Glitch (Part 1) - Darkrai and Shaymin[V/OL]. (2018-01-20) [2019-03-02]. . 152 | 3. Ganix. Void Glitch - How to Catch Arceus in Pokemon D/P[V/OL]. (2017-01-22) [2019-03-23]. . 153 | 4. Cryo. Obtaining Arceus via the Void Glitch[EB/OL]. (2017-01-10) [2019-03-23]. . 154 | {: .list-endnote .square } -------------------------------------------------------------------------------- /assets/js/search.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | /* global $ */ 3 | const lang_default = "zh-cn"; 4 | const i18n = { 5 | "zh-cn": { 6 | "search-input-placeholder": "请输入关键词", 7 | "search-no-results": "无结果", 8 | "posts-link": "/posts/" 9 | }, 10 | "en": { 11 | "search-input-placeholder": "Please enter keywords", 12 | "search-no-results": "No results", 13 | "posts-link": "/posts/en/" 14 | }, 15 | }; 16 | 17 | window.addEventListener("load", () => { 18 | const lang = document.body.lang || document.querySelector("html").lang || lang_default; 19 | const t = function (key, _lang = lang) { 20 | return (i18n[_lang] || i18n[lang_default])[key] || i18n[lang_default][key] || key; 21 | } 22 | 23 | let search = instantsearch({ 24 | indexName: "xzonn_top", 25 | searchClient: algoliasearch("ZVIOW9GL6U", "335c8667308137ed2d846141b842d730"), 26 | }); 27 | 28 | let hitTemplate = (hit) => { 29 | let url = hit.external_url || hit.url, 30 | anchor = hit.anchor || "", 31 | title = hit._highlightResult.title.value, 32 | heading = ((hit._highlightResult.headings || []).slice(-1)[0] || {}).value || "", 33 | tags = (hit._highlightResult.tags || []).map((x) => x.value), 34 | content = (hit._highlightResult.content || []).value, 35 | hit_lang = hit.lang || lang_default, 36 | posts_link = t("posts-link", hit_lang); 37 | 38 | let defineList = $("
      ").addClass("xz-search-list-item"), 39 | _title = $("
      ") 40 | .addClass("xz-search-list-title") 41 | .append( 42 | $("") 43 | .attr({ 44 | "href": `${url}${anchor ? "#" : ""}${anchor}`, 45 | }) 46 | .html(title) 47 | ) 48 | .appendTo(defineList), 49 | _heading = heading ? $("").addClass("xz-search-list-heading").html(heading).appendTo(_title) : null, 50 | _tags = tags.length 51 | ? $("
      ") 52 | .addClass("xz-search-list-tags") 53 | .append($("
        ").append(tags.map((x) => $("
      • ").html(`#${x}`)))) 54 | .appendTo(defineList) 55 | : null, 56 | _content = $("
        ").addClass("xz-search-list-content").html(content).appendTo(defineList); 57 | 58 | Han(defineList[0]).render(); 59 | return defineList[0].outerHTML; 60 | }; 61 | 62 | search.addWidget( 63 | instantsearch.widgets.searchBox({ 64 | container: ".xz-search-searchbar", 65 | placeholder: t("search-input-placeholder"), 66 | cssClasses: { 67 | "form": "input-group", 68 | "input": "form-control", 69 | "submit": "btn btn-primary", 70 | "reset": "btn btn-primary", 71 | }, 72 | searchAsYouType: false, 73 | }) 74 | ); 75 | search.addWidget( 76 | instantsearch.widgets.hits({ 77 | container: ".xz-search-hits", 78 | templates: { 79 | item: hitTemplate, 80 | empty: t("search-no-results"), 81 | }, 82 | }) 83 | ); 84 | search.addWidget( 85 | instantsearch.widgets.pagination({ 86 | container: ".xz-search-pagination", 87 | cssClasses: { 88 | root: "d-flex justify-content-center", 89 | list: "pagination", 90 | item: "page-item", 91 | link: "page-link", 92 | previousPageItem: "d-none", 93 | nextPageItem: "d-none", 94 | selectedItem: "active", 95 | disabledItem: "disabled", 96 | }, 97 | }) 98 | ); 99 | search.addWidget( 100 | instantsearch.widgets.configure({ 101 | hitsPerPage: 10, 102 | filters: `lang:${lang}`, 103 | }) 104 | ); 105 | search.addWidget( 106 | instantsearch.widgets.poweredBy({ 107 | container: ".xz-search-poweredby", 108 | }) 109 | ); 110 | search.start(); 111 | 112 | let submitTimeout; 113 | $(".xz-search-searchbar") 114 | .on("keyup", (e) => { 115 | if (!$(e.target).is(".ais-SearchBox-input")) { 116 | return; 117 | } 118 | if (submitTimeout) { 119 | clearTimeout(submitTimeout); 120 | } 121 | submitTimeout = setTimeout(() => { 122 | $(".ais-SearchBox-submit").trigger("click"); 123 | $(".ais-SearchBox-input")[0].focus(); 124 | }, 500); 125 | }) 126 | .on("keydown", (e) => { 127 | if (!$(e.target).is(".ais-SearchBox-input")) { 128 | return; 129 | } 130 | if (submitTimeout) { 131 | clearTimeout(submitTimeout); 132 | } 133 | }); 134 | 135 | let observer = new MutationObserver(window.windowScroll); 136 | let observerConfig = { attributes: true, childList: true, subtree: true }; 137 | observer.observe(document.querySelector(".xz-search-hits"), observerConfig); 138 | }); 139 | -------------------------------------------------------------------------------- /_posts/2020-02-16-Update-3-0.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2020-02-16 13:48 3 | head_image: 6ca98d296e70f7a4a34070876597a575.png 4 | head_image_height: 720 5 | head_image_width: 1080 6 | info: Xzonn 的小站升级为 3.0 版本。 7 | last_modified_at: 2020-02-17 23:13 8 | math: true 9 | tags: 网站日志 10 | title: 3.0 版本更新日志 11 | wechat_link: https://mp.weixin.qq.com/s/egR_kNRfxBEcGcOxmAwDPA 12 | --- 13 | ## 前言 14 | 15 | 阿里云最近推出了“[学生‘在家实践’计划](https://developer.aliyun.com/adc/student/)”,在校大学生可以免费领取半年的阿里云服务器一台。官方说明如下: 16 | 17 | > 因新冠肺炎疫情,学校延期开学。在家时间不浪费,提高技能好机会。阿里云弹性计算联合开发者社区,推出高校“在家实践”计划,全国高校学生,每人可免费领取一台云服务器ECS算力资源,在线实践课程等资源。 18 | 19 | 趁着这个机会,我领取了一台云服务器,2核CPU、4 G内存、1 Mbps带宽、40 GB系统盘,原价918人民币,看上去还可以——除了带宽似乎有点小,不过既然是免费领取的,也就不讲究了。有了这台云服务器,我打算把自己部署在GitHub Pages上的小站转移到云服务器上,毕竟阿里云服务器在国内,访问速度应该要比GitHub Pages快一些。趁着这个机会,我也把小站更新了一下页面设计。 20 | 21 | ## 基于[Bootstrap](https://getbootstrap.com/docs/3.4/)的新布局 22 | 23 | 3.0版本最大的更新就是弃用原有的布局,改为基于Bootstrap v3的新布局,并根据原有布局的代码修改参数。之前我曾经稍微尝试过用Bootstrap,但是没有系统地学习过,而且Bootstrap的代码在当时不是很适合我的品位,因此在[某次更新](https://github.com/Xzonn/xzonn.github.io/commit/1b39cde87e7dd00313db0cc81f8f7a3303e8d271#diff-2c19d9859b055d0302043d0fa2833e3f)后我就删除了Bootstrap的引用。而这次再次使用Bootstrap布局是想把界面改得简约一些。 24 | 25 | {% include figure.html src="0b2c9694cd5dfc276134ec6f36f3635d.png" alt="本站2.0版本" width="640" height="360" %} 26 | 27 | 相比2.x版本,这一版本在布局方面有如下改进: 28 | 29 | 1. 删除背景图片,将正文的背景色改为主背景色,正文背景改为白色。 30 | 2. 将左侧导航栏改为顶部导航栏并固定,原有头像删除,改为像素图标。 31 | 3. 标题、信息从正文提至页面最顶部,增强视觉效果。 32 | 4. 二维码大小改为由标题区块大小决定。 33 | 5. 对正文进行滚动监听,达到目录动态显示的效果。 34 | 6. 将原有样式名的驼峰式写法改为与Bootstrap统一的横线式写法,删除Bootstrap已有实现的样式。 35 | 7. 将Bootstrap样式表命名为“base.css”,便于其他项目调用;本站使用的样式增加“xz-”前缀,样式表为“main.css”,仅本站调用。 36 | 8. 合并“文章列表”和“标签列表”,重写样式,更新原有的脚本代码。 37 | 9. 首页“文章一览”最近才更新过,此次仅修改了页码部分的样式。 38 | 10. 暂时删去信息框。 39 | 11. 删去打赏二维码链接。 40 | 12. 页脚删去CC BY-NC-SA 4.0的图标(请注意本站仍按照CC BY-NC-SA 4.0许可,只是删去了图标),重新排版。 41 | 13. 修改滚动条样式。 42 | 14. 其他未提到的琐碎修改。 43 | 44 | ## 向Bootstrap中加入自定义内容 45 | 46 | 目前Bootstrap的版本已经更新到4.x,但我仍在使用3.x版本,其原因在于3.x版本的自定义方式比较简单,既可以手动编译,也可以从网站定制;且中文教程丰富-。而4.x版本的编译方法我鼓捣了很久也没搞出来,最后只好作罢。 47 | 48 | 本次更新时使用的版本为Bootstrap 3.4.1,与原版相比我自定义了如下内容: 49 | 50 | 1. 字体。原版字体仅有英文字体,此处我添加了中文字体。同时为了更正引号`“”`引起字体回退的问题,利用Han的标点标注功能,将中文标点设为仅有中文字体。 51 | 2. 颜色。原版给出了一些颜色方案,但为了和本站的2.x版本匹配,我修改了颜色,采用蓝红两色对比的颜色方案,基色分别为#00b7ff / HSL(197, 100%, 50%)#ff4800 / HSL (17, 100%, 50%),两种颜色恰好是对比色,并借助函数调整明度。 52 | 3. 字号。原版标题字号偏大,我按照个人习惯调小了字号,新字号介于原版字号和本站2.x版本字号之间。 53 | 4. 行距。原版行距偏小,为1.43(即20/14),我改为了1.732(即$$\sqrt 3$$)。 54 | 5. 添加了本站2.x版本的部分样式。 55 | 56 | 自定义内容使用[less.js](http://lesscss.org/)编译。 57 | 58 | ## Bootstrap提供的JavaScript插件 59 | 60 | Bootstrap提供了一些插件,本站使用了如下内容: 61 | 62 | 1. 滚动监听(scrollspy.js),用于动态显示目录。由于顶部导航条的存在,锚点定位存在一些问题。我参考了其他网站的做法,在每个标题内加入了一个空白的``标签用于修改锚点定位。 63 | 2. 弹出框(popover.js),用于显示注释。 64 | 3. 提示框(alert.js),目前仅用于MathJax渲染提示,后续可能会增加新的用途。 65 | 4. 固定(affix.js),用于将目录显示在固定位置。 66 | 67 | ## 改用[jsDelivr](https://www.jsdelivr.com/)作为CDN源 68 | 69 | 本站原本采用了Cloudflare提供的[cdnjs.com](https://cdnjs.com/)网站作为CDN源,但我发现cdnjs.com的访问速度较慢,因此改用jsDelivr作为CDN源。本站使用的Bootstrap脚本、jQuery脚本、MathJax脚本均用jsDelivr源,而Han.js未在该网站找到,因此改用本地源。 70 | 71 | 另外,为了进一步提升速度,MathJax仅在需要渲染公式的页面引入。 72 | 73 | ## 其他使用的外部资源 74 | 75 | 以下资源均自2.x版本中即开始使用。 76 | 77 | 1. [jQuery](https://jquery.com/),用于修改页面元素等。 78 | 2. [jquery.qrcode.js](https://jeromeetienne.github.io/jquery-qrcode/),jQuery插件,用于生成二维码。 79 | 3. [js-cookie](https://github.com/js-cookie/js-cookie/),用于处理cookies。 80 | 4. [MathJax](https://www.mathjax.org/),用于渲染数学公式。 81 | 5. [mhchem for MathJax](https://mhchem.github.io/MathJax-mhchem/),MathJax的插件,用于渲染化学公式。 82 | 6. [Han](https://hanzi.pro/),用于添加中英文之间的空格。 83 | 7. [来必力](https://livere.com/),评论系统。 84 | 8. [友盟+](https://web.umeng.com/),分析系统。 85 | 86 | ## 其他重要变化 87 | 88 | 3.0版本将所有文章的链接由原来的`/:title/`形式修改为了`/posts/:title.html`形式,这是由于原有形式会在发布时在根目录下生成较多文件夹,不利于管理。为降低影响,我使用脚本更新了内部链接,并自定义了404页面,对原始链接的访问将调用404页面,然后根据脚本转向新的链接页面。但是,本站采用的来必力评论系统基于页面链接显示,因此本站更新前的所有评论均无法显示。 89 | 90 | 另外,源代码中添加了更多的meta元素和link元素,用于页面描述和图标,可查看源代码访问。 91 | 92 | ## 更新计划 93 | 94 | 目前我已经申请了[xzonn.top](http://xzonn.top)域名,正在进行备案,备案完成后我计划自己写评论系统,以替换国内访问速度较慢的来必力;并添加搜索系统。 95 | 96 | ## 参考资料 97 | 98 | 1. {: #ref-lovelydong }lovelydong. 定制你的bootstrap [EB/OL]. (2017-10-24) [2020-02-16]. . 99 | 2. {: #ref-wang-sai }王赛. Bootstrap 中文文档 [EB/OL]. (2020-01-16) [2020-02-16]. . 100 | 3. {: #ref-cai-niao-jiao-cheng }菜鸟教程. Bootstrap 教程 [EB/OL]. [2020-02-16]. . 101 | 4. {: #ref-the-core-less-team }The core Less team. Less.js [EB/OL]. (2019-09-20) [2020-02-16]. . 102 | {: .list-endnote .square } -------------------------------------------------------------------------------- /_posts/2024-01-01-Migrate-LiverRe-comments-to-Giscus.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2024-01-01 16:50 3 | head_image: 92545f08f0838ddaee40f3d13dd5799f.webp 4 | head_image_height: 1280 5 | head_image_shown: false 6 | head_image_width: 1920 7 | info: 自力更生。 8 | last_modified_at: 2024-01-01 17:38 9 | tags: 技术指南 网站日志 10 | title: 将来必力(LiveRe)的评论迁移到giscus并优化排序 11 | --- 12 | ## 前言 13 | 新的一年,我的小站也焕然一新。除了每年例行的更换配色外,今年终于将Bootstrap 3升级到了Bootstrap 5,利用Jekyll自带的sass相关插件生成css。其实我早就想升级了,几个新的小项目都直接用了Bootstrap 5,但是博客因为历史遗留太多,一直没有动力去改。这次终于下定决心,一口气把主站也升级了。另外,还利用Algolia增加了[搜索](/search.html)功能,这个功能也是我很早就想添加的,只不过之前GitHub Pages不能直接通过GitHub Action上传,而GitHub Pages默认配置不支持其他插件,所以一直没有添加。现在能通过GitHub Actions生成后,就不局限于GitHub Pages默认的插件了,可以用Ruby编写插件,扩展性大大增加,我甚至给我的[游戏记录](/games/)添加了修改页面主题色的功能。 14 | 15 | 除了上面这些之外,还有一件事我一直没解决,也就是博客的评论系统。众所周知,我的博客是基于Jekyll生成的静态网站,所以没法像基于WordPress的博客一样自带评论系统,需要借助第三方评论系统。我之前一直用的是[来必力(LiveRe)](https://livere.com/),这个评论系统之前很好用,支持很多第三方登录,而且还有自带的管理后台,可以直接在后台管理评论。但是不知道从什么时候起,来必力的邮件通知就失效了,即使有人发了新评论也不会给我发邮件,导致我经常没法及时回复。为了解决时效性的问题,我决定把评论系统迁移到基于GitHub的应用,因为网站本身就是GitHub生成的,在GitHub上讨论也很正常。基于GitHub的评论系统也有很多,比如[utterances](https://utteranc.es/)、[Gitalk](https://gitalk.github.io/)等,但是比较来比较去我还是选择了[giscus](https://giscus.app/),主要原因在于它利用的是GitHub Disscussions而不是Issues,不会在Repo的“Issues”那里显示出数字(强迫症友好),并且支持简体中文界面。下面就来介绍一下如何将来必力的评论迁移到giscus。 16 | 17 | ## 导出 18 | 来必力不支持评论导出,这稍微有些麻烦。不过打开浏览器开发者工具后访问管理后台,可以直接找到相关接口的请求,所以拿Python模拟一下即可: 19 | 20 | ``` python 21 | import datetime 22 | import json 23 | import math 24 | import requests 25 | 26 | # Replace this line with your cookies 27 | COOKIES = """JSESSIONID=...""" 28 | 29 | session = requests.Session() 30 | for cookie in COOKIES.split(";"): 31 | key, value = cookie.split("=", 1) 32 | session.cookies.set(key, value) 33 | 34 | results = [] 35 | 36 | page = 1 37 | count = 10 38 | 39 | while math.ceil(count / 10) >= page: 40 | response = session.post("https://livere.com/insight/managereply/period", { 41 | "startDate": "2017-01-01", 42 | "endDate": datetime.date.today(), 43 | "sort": "regdate", 44 | "order": "desc", 45 | "pageNum": page, 46 | }) 47 | response_json = response.json() 48 | results += response_json["resultData"] 49 | count = response_json["count"] 50 | page += 1 51 | 52 | with open("result.json", "w", -1, "utf8", newline="\n") as writer: 53 | json.dump(results, writer, ensure_ascii=False, indent=2) 54 | ``` 55 | 56 | 这个脚本会将所有评论导出到`result.json`文件中。还没完,GitHub Disscussions基于Markdown,所以手动把原始评论转成Markdown文件并保存: 57 | 58 | ``` python 59 | from datetime import datetime, timedelta, timezone 60 | import json 61 | import os 62 | import re 63 | import urllib.parse 64 | 65 | with open("result.json", "r", -1, "utf8") as reader: 66 | results: list[dict] = json.load(reader)[::-1] 67 | 68 | url_data: dict[str, dict[str, list[str]]] = {} 69 | 70 | for result in results: 71 | url = result["site"] 72 | content: str = result["content"] 73 | reply_seq = result["reply_seq"] 74 | parent_seq = result["parent_seq"] 75 | author: str = result["name"].strip() 76 | date: datetime = datetime.strptime(result["regdate"].strip(), "%Y-%m-%d-%I:%M:%S %p").replace(tzinfo=timezone(timedelta(hours=9))).astimezone(timezone(timedelta(hours=8))) 77 | images = [] 78 | i = 1 79 | while f"image{i}" in result: 80 | images.append(result[f"image{i}"]) 81 | i += 1 82 | 83 | content = re.sub(r"\n\n\n+", "\n\n", content).replace("\n", " \n").replace(" \n \n", "\n\n") 84 | 85 | path = urllib.parse.unquote(url.split("/", 3)[-1].split("?")[0].split("#")[0], encoding="utf8") 86 | 87 | if path.endswith("/"): 88 | path += "index.html" 89 | assert path.endswith(".html") 90 | path = path.removesuffix(".html") 91 | if path not in url_data: 92 | url_data[path] = {} 93 | if parent_seq not in url_data[path]: 94 | url_data[path][parent_seq] = [] 95 | 96 | output_str = [f"*****{author} {"评论于" if reply_seq == parent_seq else "回复于"} {datetime.strftime(date, "%Y-%m-%d %H:%M:%S")} (UTC+8)*****\n\n{content}"] 97 | for image in images: 98 | output_str.append(f"\n\n![{image}]({image})") 99 | url_data[path][parent_seq].append("".join(output_str)) 100 | 101 | for path, comments in url_data.items(): 102 | os.makedirs(os.path.join("output", path), exist_ok=True) 103 | for id, content in sorted(comments.items(), key=lambda x: int(x[0])): 104 | with open(os.path.join("output", path, f"{id}.md"), "w", -1, "utf8") as writer: 105 | writer.write(f"> 评论导出自来必力\n\n") 106 | writer.write("\n\n".join(content)) 107 | ``` 108 | 109 | 这个脚本会将所有评论按照原始URL和评论ID保存到`output`文件夹中。这样就完成了来必力评论的导出。 110 | 111 | ## 导入 112 | 导入其实也可以做到全自动化,但是因为我懒得写这部分脚本了,就直接手动复制粘贴。 113 | 114 | 当然,导入之前先要把giscus集成到网站上。在giscus的[官方网站](https://giscus.app/)中有详细的配置流程,不再赘述。 115 | 116 | ## 优化排序 117 | giscus默认的排序是按照评论创建时间正序排序的,这样就会导致新的评论会被放在最后,而不是放在最前。这对于我的博客来说并不方便,因为很多旧评论是已经解决的问题或者已经不成立的情况,放在最前面没有什么意义。虽然giscus提供了倒序排序的功能,但是经过我的尝试,在评论分页的情况下仍然是先加载旧评论。理论上来说这个问题最好的解决方法应该是写成分页的形式,但是这样的话改动起来很麻烦,相当于要重写一部分UI。在我研究了源代码之后,决定用个偷懒但是日后维护起来可能很麻烦的办法:把api中加载“较新”和“较旧”的方法调换一下。这样就可以实现默认加载最新评论,而不是最旧评论了。具体实现方法可以参考[此次提交](https://github.com/Xzonn/giscus/commit/127f3157148286c585a036ab2204c53b65186d93)。 118 | 119 | 修改了源代码之后还得想办法部署,[官方文档](https://github.com/giscus/giscus/blob/main/SELF-HOSTING.md)里也给出了部署的步骤,我也同样用了[Vercel](https://vercel.com/),看起来还不错,而且可以自定义域名。 -------------------------------------------------------------------------------- /_posts/2020-10-30-Automatic-Numbering-in-Microsoft-Word.md: -------------------------------------------------------------------------------- 1 | --- 2 | class: auto-numbering 3 | date: 2020-10-30 21:14 4 | info: Word中提供了许多自动化工具,尽管初次上手可能有些麻烦,但熟练掌握之后必将对之后的使用提供便利。 5 | last_modified_at: 2021-05-23 17:34 6 | logs: 7 | - 2021-05-23:增加章节编号为中文时的处理方法。 8 | tags: 技术指南 9 | title: 浅谈 Microsoft Word 中的自动编号 10 | --- 11 | ## 前言 12 | 13 | 最近大四的同学似乎都勤奋了起来,不用问,大家都是在写本研的结题报告。我本想十一假期就大刀阔斧的搞完,无奈事务繁忙,拖到现在才刚刚初步完成。 14 | 15 | 本研报告要求用Microsoft Word写,并且给了一个2006年流传至今的论文模板。虽然我不是很喜欢用Word写学术论文(当然我最后也没用Word写),但是毕竟用Word的人还是大多数,我也只能学着如何让Word用得稍微顺手一点。在我最近与身边同学沟通之后,我发现大部分人都没有注意过如何让Word的使用变得更加便捷,其中之一就在于:自动编号。本文将简述Word中4种最常见的编号:页码、参考文献编号、标题项编号、图表编号,并在此基础上穿插一些我自己常用的技巧,希望对各位有所帮助。至于我本人最常用的Markdown + CSS + Princexml,由于需要一定的技术含量,我可能会单独写一篇技术指南,此处不再赘述。 16 | 17 | 本文所用的Word版本为Microsoft Office专业增强版2016版本1808,“参考文献编号”一章所用的Endnote版本为EndNote X9.2 (Bld 13018),在对应软件的其他不同版本中操作可能略有不同,但大同小异。 18 | 19 | ## 页码 20 | 21 | {% include figure.html src="6114723baa7a83ca37d767e3141a8edd.png" alt="插入页码" width="640" height="361.74" %} 22 | 23 | 页码的编号应该是最简单的,在页面上方的菜单中找到“插入”→“页码”,然后选择合适的格式即可,一般情况下应该插入在页面底端处()。其实质是在页脚处生成了一个“域”,可以理解为Word中的一个简单的自定义编程输出。 24 | 25 | 这里先简单聊一聊页眉和页脚。默认情况下,Word的页眉和页脚会在每页的顶端和底端出现,但也可以根据实际需要选择“首页不同”(一般首页不需要页眉)或“奇偶页不同”(一般是在双面印刷时有需要)。而插入的页眉页脚在对应的每页都是相同的,但有些时候可能会需要同一文档中页眉和页脚不同,这时可以插入“分节符”,或者使用前文所述的“域”。 26 | 27 | {% include figure.html src="5e2e119ec0075e08fb3a736dbc4b6cf5.gif" alt="插入分节符" width="640" height="360" %} 28 | 29 | 插入分节符():先在文档最开始的部分插入页眉和页脚,并选择“首页不同”,删除首页的页眉。然后在每章结束时,通过菜单栏→“布局”→“分隔符”→“分节符”(可以根据需求选择是否分页)。在新一节的页眉,先在菜单栏(→“页眉和页脚工具”)→“设计”→“导航”中取消选中“链接到前一条页面”,然后取消选中“选项”→“首页不同”,再修改新一节的页眉。这样的优点是比较自由,缺点则是需要手动修改,在章节较多时比较麻烦。 30 | 31 | {% include figure.html src="591e965a77b1aa460c86fe587c72ecfa.gif" alt="使用域" width="640" height="360" %} 32 | 33 | 使用域():“首页不同”同“解法1”,然后在非首页页眉处选择菜单栏→“插入”→“文本”→“文档部件”→“域”,在出现的窗口左侧选择“StyleRef”,在中部选择本章标题所用的样式名称(一般为标题2),然后确定即可。这种方法在文档较长的时候可以自动更新当前章节的标题,也是我比较常用的方法。 34 | 35 | 上述方法中用到了自定义域,而Word中域的用法还有很多,读者可以自行探索。这里提到的“StyleRef”顾名思义就是引用了对应样式的内容,而样式在菜单栏→“开始”→“样式”中可以设定,默认的样式包括正文、标题、题注等。很多人可能没有注意过“样式”的使用方法,但我个人认为这是Word为数不多的称得上规范的地方。通过定义样式,Word可以区分出文字的用途,从而为不同用途的文字指定不同的格式。右键点击样式可以修改样式的默认格式,也可以在下拉菜单中创建、清除和应用样式。 36 | 37 | {% include figure.html src="fd2314ce5920aaccbda7d55cdcc5c517.png" alt="默认字体" width="640" height="361.74" %} 38 | 39 | 另外多提一句,正式文件一般要求正文字体为中文宋体、英文Times New Roman,标题字体为黑体(我习惯黑体搭配Arial使用),而默认字体也可以通过菜单栏→“设计”→“字体”来设置()。在样式中如果指定字体为“×× (中文正文)”,则修改默认字体后正文的字体也会修改,如果手动指定字体则不利于快速调整格式。我个人建议,多使用默认字体,不要手动修改字体,而且不建议在同一份文档中使用3种以上的字体(宋体、黑体、楷体/仿宋足矣),否则会显得混乱。 40 | 41 | ## 参考文献编号 42 | 43 | 关于Word中参考文献,我个人还是习惯用EndNote,因为EndNote可以直接实现参考文献编号的自动更新。我之前也写过一篇[用EndNote管理中文文献的文章](https://xzonn.top/posts/Managing-Chinese-Literature-with-EndNote.html),在这篇文章中我已经介绍了EndNote的安装、插入文献、修改文献列表格式等,此处不再赘述。 44 | 45 | {% include figure.html src="53a596156e46d5f97cd3fec5d2de4dc3.png" alt="EndNote检查更新" width="640" height="360" %} 46 | 47 | 仅多说一句,北京大学正版软件共享平台提供的EndNote X9似乎有一些问题,在导入文献时期刊名称无法被识别,在此建议大家安装后按照菜单栏→“Help”→“Check for Updates...”检查更新()。 48 | 49 | ## 标题项编号 50 | 51 | {% include figure.html src="4bdd8d0002f9402eca8a16592ab0a2a7.gif" alt="标题自动编号" width="640" height="360" %} 52 | 53 | 标题项也是可以自动编号的。为了实现自动编号,需要用到上文提到的“样式”。在菜单栏的“开始”→“段落”→“多级列表”(![多级列表\|none](e57dabb960b816bdb361bec48c54bdfe.png))→“定义新的多级列表”可以创建多级列表,点击弹出的对话框下方“更多”按钮可以出现更多选项,将各级列表链接到对应的样式,随后确定。在输入标题时选择对应的样式,则会自动出现编号()。 54 | 55 | {% include figure.html src="fdd294a0aaa2f775b2712be273709fbc.png" alt="中文标题编号" width="640" height="360" %} 56 | 57 | 除了数字的自动编号外,还可以实现中文自动编号,搭配样式调整可以获得更多效果。例如,要求二级标题自动显示“第某章”,三级标题自动显示“第某节”,四级标题显示数字。与前文类似,只不过编号样式需要调整为中文的“一, 二, 三 ...”()。如果子标题不需要显示副标题的编号,可以直接删除。如果子标题需要显示为数字,可以选中“正规形式编号”。 58 | 59 | ## 图表编号 60 | 61 | {% include figure.html src="f7d4da4ecf96ce589516c8fb0bb495a7.gif" alt="插入图表题注" width="640" height="360" %} 62 | 63 | 图表编号可能是需求量最大的一种编号,如果手动插入编号,一旦改变图片位置就要手动修改引用和编号顺序,比较麻烦。而使用自动编号可以摆脱手动修改的麻烦。插入图表编号的方法也比较简单,右键单击图片或表格,在菜单中选择“插入题注”,然后选择标签,输入内容,确认即可()。一般情况下,表注在上,图注在下。Word默认的题注并没有单独的“图”“表”两个字,需要手动添加。另外,Word提供了“自动插入题注”的选项,但我并未搞懂如何使用,如果各位知道如何使用还请不吝赐教。 64 | 65 | 如果需要在正文中引用题注,则需要找到菜单栏→“插入”→“交叉引用”,在弹出的对话框中选择引用类型为“图”,引用内容为“仅标签和编号”,插入即可。此外,交叉引用还可以插入其他编号项,例如文中如果需要提及“第X章”也可使用此方法插入;还可以插入其他引用内容,例如某项所在的页码,这些内容都会随着文档内容更新而更新。如果没有自动更新,可以使用Ctrl + A全选,然后按F9强制更新域。 66 | 67 | {% include figure.html src="6ec20ad79978eaf28f8af15ead9f25c5.png" alt="插入目录" width="640" height="361.74" %} 68 | 69 | 此外,通过自动编号插入的标题、图注、表注都可以生成对应的目录,均位于菜单栏的“引用”选项卡下。标题目录为“目录”→“目录”(),图注、标注目录为“题注”→“插入表目录”,设置方式类似,也可以手动修改对应的样式,此处不再详细说明。 70 | 71 | 补充:在写毕业论文的时候我发现,当章节标题使用了中文编号时,图表编号也会显示为中文,十分麻烦。网络上有一些解决方法,但有些需要用到域,而且需要定稿之后统一修改,比较麻烦。最后我发现了一个另类的方法:将“标题 1”设置为数字编号,然后设置字号、行距均为最小,颜色改为白色;再新建一个样式“中文标题 1”,设置为中文编号,用于显示。这样操作之后就可以同时满足显示中文数字、图表编号为阿拉伯数字了。 72 | 73 | ## 结语 74 | 75 | Word中提供了许多自动化工具,尽管初次上手可能有些麻烦,但熟练掌握之后必将对之后的使用提供便利。分享一个我自己使用的空白模板,供各位参考。链接:。 76 | 77 | 本文写得比较仓促,如各位读者有任何意见或建议,欢迎留言反馈。 -------------------------------------------------------------------------------- /_posts/2025-06-30-G-Fusion-Game-Fest-2025.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2025-06-30 21:59 3 | head_image: 03bfadd7543a067447e29f0371b14a0a.webp 4 | head_image_height: 1200 5 | head_image_width: 1600 6 | info: 超级忍技术职业培训学院毕业留念。 7 | last_modified_at: 2025-06-30 23:06 8 | no_sidenav: true 9 | tags: 杂记 10 | title: 核聚变2025流水账 11 | --- 12 | [Bilibili 动态](https://t.bilibili.com/1084255861041266708)发了一份,[微博](https://weibo.com/7199621409/PyXW96v6G)发了一份,[机核](https://www.gcores.com/talks/1110488)也发了一份,这里再发一份,写写因为字数限制或者其他因素放不下了的东西。 13 | 14 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/75537719cc77e60325b7c80a76b1d3c516114399.jpg" alt="世嘉《超级忍》展台" width="360" height="270" %} 15 | 16 | 第一次作为志愿者参加这种大型展会,第一天上午还有点放不开,到了后面就开始放飞自我了,甚至让同组的志愿者怀疑我是不是经验丰富的老手了。但我真不是,虽然在学校里也参加过志愿活动,但是接待这么多人的还真是第一次。(题外话:同组的志愿者知道我是PKU的学生之后还问我:你们学校是不是男娘很多啊?我:我不知道,对他们的圈子不太熟) 17 | 18 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/fc859f95471ad94bd2d110f2345775fb16114399.jpg" alt="在展台体验游戏的一家人" width="360" height="270" %} 19 | 20 | 周末两天主要的工作其实就是引导来场的玩家试玩游戏,每个人限时20分钟,最初的安排是一个人负责3-4台机器,后来发现引导工作不忙,只需要开始的时候介绍规则并且盖章、计时,结束的时候引导到出口并恢复机器状态,试玩过程基本不需要志愿者参与,于是到了后期大家的站位都越来越随意,我也放飞自我,抱着展板到其他展区排队的地方宣传了。 21 | 22 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/ee701f1e70860f0803e80fead132ef8316114399.jpg" alt="Marvelous《机甲战魔》宣传墙" width="360" height="270" %} 23 | 24 | 《超级忍》这个头箍的宣传效果挺不错的,场馆里随处可见带着我们区头箍的玩家和志愿者,每次我拿着一大堆头箍出去转一圈就全发完了,满载而出、空手而归,另一个志愿者都说想把我拉去他们公司做销售。他都不太相信我能发得这么快,其实只要队伍里有一个人拿出手机准备加愿望单,旁边的人也会被吸引着了解一下,形成链式反应。我算是理解为什么《过山车之星》里面周边会有人传人的现象了。甚至出现了队伍里太多人操作但我手上的头箍不够了,还得一路小跑回展位再拿点回来的情况。虽然我没具体数过巡回宣传发了多少头箍,但是估算一下,第一天发了2箱,第二天发了2箱半,粗略估计我外出宣传多发了两三百个吧。 25 | 26 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/06b04f741a601aba083be2696cc5d05d16114399.jpg" alt="九点刚过几分钟,《明末》的队伍就已经排了老长了" width="360" height="270" %} 27 | 28 | 但说实话,加入Steam愿望单这个操作略微有些麻烦,一方面很多人手机上没有Steam APP,另一方面因为众所周知的原因Steam的网络情况很差,于是[小黑盒](https://www.xiaoheihe.cn/home)就成了替代选择。还有些人小黑盒也没有,我顺带推荐了一下下载小黑盒(小黑盒打钱!)而且厂商做的展板上都没有这个游戏的名字,我周日意识到这个问题后贴了个官方的Logo贴纸,至少能让人知道这游戏叫啥了。至于展板上的二维码……说实话我觉得没啥用,Steam客户端和小黑盒客户端都扫不了游戏页面的二维码,拿微信扫码登录Steam的人毕竟是少数,还不如直接让他们搜索。 29 | 30 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/af9f801656f2af52f7937be1dc938f4a16114399.jpg" alt="《苏丹的游戏》展台" width="360" height="270" %} 31 | 32 | 说回到《超级忍》这个游戏,本来在周五下午踩点的时候是可以试玩的,但我还没打完第一章的最终BOSS就被叫走干别的事了,没能完整体验。周六周日也忙着接待来体验的玩家,没能有空自己玩,稍微有些小遗憾。本来想收摊的时候玩一下,结果厂商说要把游戏卸载掉,也没能玩上。实际上展台上的游戏能玩到很靠后的关卡,但是官方只允许普通玩家体验第一章的内容。虽说试玩时间限制是20分钟,但是如果有人在20分钟内打到了赤猿鬼这里,我们也会把计时器停掉让他继续打完,还是挺人性化的吧。 33 | 34 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/30467bc747fa2ae0eefc383e66158b4f16114399.jpg" alt="《黑神话》展台" width="360" height="270" %} 35 | 36 | 到第一章为止的操作不算太难,虽然我不太擅长动作游戏,但是熟悉了套路之后打个BOSS还是能过的。只不过中文版的默认配音是英语而不是日语,对于一个以“忍者”为主题的游戏来说多少有些奇怪。现场的宣传片配音也是英语,我个人是觉得日语配音的宣传片更地道。 37 | 38 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/652241bbe5b7c4553c94bbe9f29765ec16114399.jpg" alt="《超级忍》展区合影留念" width="360" height="270" %} 39 | 40 | 空闲的时候也跟世嘉的工作人员聊了聊,她们说世嘉现在确实很重视大陆这边的市场,从《人中之龙》系列有中配以及《超级忍》起了中文名等一系列举措都能看得出来。希望P4R发售之前也能有丰富的宣传活动吧。我还问了问她们世嘉招不招人,有没有什么硬性要求,她们说需要商务日语的水平。我只有个N1,分数还不算高,看来距离加入世嘉还有很长一段距离啊。 41 | 42 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/3029f28a8258f707102f0fde75c572db16114399.jpg" alt="全体志愿者大合影" width="480" height="270" %} 43 | 44 | 最后是一点小插曲,由于我脸盲,来展区的媒体和KOL我都认不出来是谁,后来才知道老袋也来超级忍展区了,没能跟他合上影。倒是排队的时候有人问能不能和我合影,一聊才知道竟然是在B站关注了我,没想到我也能有和粉丝合影的一天。 45 | 46 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/98d9557d3d9d866a8218abeca5f9180916114399.jpg" alt="粉丝合影" width="360" height="270" %} 47 | 48 | 总的来说这次志愿者活动还是挺有意思的,工作期间完全没感觉到累,也收集了很多有趣的小物料,虽然没能完整体验这个游戏,但也算是收获满满了。我的学生体验卡还有最后一年,希望还能有机会参与类似的活动吧。我之前一直羡慕日本动画里的校园“文化祭”,这次终于有机会亲身体验了一下向别人介绍、推广自己喜欢的东西。我的脑海里其实一直回想着《冰菓》里千反田爱瑠和福部里志尽力推广古典部社刊的情节,结果这两天就成真了。 49 | 50 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/1e22dabbf0ed8be97f9b1763166b560916114399.jpg" alt="物料1" width="360" height="270" %} 51 | 52 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/f82f2013a3edc69bbd9af2a6174b610316114399.jpg" alt="物料2" width="360" height="270" %} 53 | 54 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/06e522883f44fa1951e1e003f34140e116114399.jpg" alt="物料3" width="360" height="270" %} 55 | 56 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/a93926cf4baa9afbedfc135cb24a9efc16114399.jpg" alt="物料4" width="360" height="270" %} 57 | 58 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/1114b70d51f170c8be72546a4fa5f08c16114399.jpg" alt="物料5" width="360" height="270" %} 59 | 60 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/72b4cc1c738a0c32e375b390853c9a5216114399.jpg" alt="物料6" width="360" height="270" %} 61 | 62 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/ff6dd4969a48ad6ea87e574915d492ca16114399.jpg" alt="物料7" width="360" height="270" %} 63 | 64 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/db1d0872b92a4237d71de69772bad83b16114399.jpg" alt="物料8" width="360" height="270" %} 65 | 66 | 最后就是想到哪写到哪了: 67 | 68 | - 为啥这次的id是“西瓜鱼”而不是“Xzonn”呢?主要是我也不知道“Xzonn”该怎么念,就又编了个名字。“西瓜鱼”来自我某次吃石锅鱼的时候想吃西瓜所以取的。 69 | - 展区在石景山首钢国际会展中心,早上8点就要到,我得6点半就起床。谢谢核聚变和世嘉,激发了我上早八的回忆。 70 | - 展区里的手柄出了好几次BUG,导致我对这个手柄厂商的观感不太好。虽说它的自定义选项很多,但是连到游戏上偶尔会出问题,这就很尴尬了,尤其是在一些玩家试玩的时候出现手柄按键没反应的情况。 71 | - 在B站搜索“超级忍”的时候发现竟然有个500多粉丝的UP主也拿到了录屏资格,让我不禁怀疑世嘉选取KOL的标准是什么。早知道我也跟厂商要一下录播资格了,毕竟我B站账号有6000多粉丝呢。 72 | - 虽然展会里有Nintendo Switch 2展区,但是这并不是任天堂官方组织的(任天堂官方这么傲娇,才不会参加这种展会呢),而是机核自己组织的。这就导致这个展区只发了机核的徽章,没有官方物料(毕竟任天堂不给授权)。他们的志愿者倒是说我可以体验一下游戏,但提供的游戏只有《王国之泪》和《马车世界》,我都有了,没必要再那里玩了。 73 | - 我之前一直没买过吧唧,这次终于知道吧唧有啥用了——别在衣服上展示自己成分。我巡回发物料的时候看到了一个穿着“結束バンド”的老哥,他看到我身上的小孤独吧唧和我相视一笑。除此之外还有几个老哥穿了优衣库和旷野之息联名的T恤,看到胸前口袋上的呀哈哈克洛格,大家就懂了。 74 | -------------------------------------------------------------------------------- /_posts/2020-07-27-Run-Ubuntu-in-Windows-10.md: -------------------------------------------------------------------------------- 1 | --- 2 | class: auto-numbering 3 | date: 2020-07-27 15:31 4 | head_image: 3b6a83b652374b177287f0c0ae3908fe.png 5 | info: 即使是Windows操作系统也可以学习Ubuntu。 6 | last_modified_at: 2020-07-30 16:11 7 | tags: 技术指南 8 | title: 在安装了Windows 10的电脑上运行Ubuntu 9 | --- 10 | ## 前言 11 | 好久不见。 12 | 13 | 最近忙着在[萌娘百科](https://zh.moegirl.org.cn/User:Xzonn)、[神奇宝贝百科](https://wiki.52poke.com/wiki/User:Xzonn)写东西,顺便接着哔哩哔哩的BWIKI搭建了一个[美妙世界Wiki](https://wiki.biligame.com/twewy/%E9%A6%96%E9%A1%B5),欢迎大家来玩。因为MediaWiki写得太多,我甚至有些忘了Markdown语法,有啥问题都想来个模板。 14 | 15 | 当然,学习方面的资料我也有更新,这学期的两门通选课[普通生物学(C)](/posts/2020-03-27-General-Biology-C-Exams-Review.html)和[中国历史地理](/posts/2020-05-26-The-Historical-Geography-of-China-Review.html)的资料整理我也有在做,供各位参考。如果各位还有其他的学习资料,也欢迎提供给我。 16 | 17 | 这次来分享一下如何在Windows 10上运行Ubuntu。Ubuntu是类Unix系统的一种,其有较高的使用率,根据一份市场占有率报告,在2020年5月Ubuntu和其它Linux发行版的占有率分别为1.89%和0.97%(当然,占比前两名是Windows 10和Windows 7,分别为56.08%和25.59%)。而在Ubuntu下安装运行一些软件相对比Windows容易一些,只需要一个`apt-get install`命令就能基本搞定。 18 | 19 | 以下将以本站点的开发和部署作为案例稍微介绍一下我的使用经历,或许对大家有所帮助。 20 | 21 | ## 启用并安装WSL 22 | WSL,全称Windows Subsystem for Linux,翻译过来就是“适用于Linux的Windows子系统”。这是Windows官方对Linux的支持。最新版Windows 10(版本2004,内部版本19041)支持WSL 1和WSL 2,它们的区别请参考[官方文档](https://docs.microsoft.com/zh-cn/windows/wsl/compare-versions)。对于我来说,我需要WSL和Windows共享文件系统,因此WSL 1就够用了。 23 | 24 | 启用WSL的方法也可以参考[官方文档](https://docs.microsoft.com/zh-cn/windows/wsl/install-win10)。这里介绍一下简单方法: 25 | 26 | {% include figure.html src="0714aeafcefc10e9f8e5f4b4d56e700d.png" alt="启用或关闭 Windows 功能" width="415" height="418" %} 27 | 28 | {% include figure.html src="e442ec4dd3f0a3559b96d0e869640b80.png" alt="在商店查找并安装Ubuntu" width="640" height="497.30" %} 29 | 30 | 1. 在“控制面板\所有控制面板项\程序和功能”中,找到左侧的“启用或关闭 Windows 功能”,找到“适用于 Linux 的 Windows 子系统”,选中并确定。如果要求重启,则重启计算机。 31 | 2. 打开[Microsoft Store](https://aka.ms/wslstore),选择合适的Linux发行版并安装。 32 | 3. 首次启动新安装的Linux发行版时,将执行安装程序,此后便无需再次解压缩。然后需要[创建用户帐户和密码](https://docs.microsoft.com/zh-cn/windows/wsl/user-support),建议账户名全小写。注意Linux系统输入密码时不会显示任何内容,这并不是Bug。 33 | 34 | 随后进入终端界面,WSL安装完毕。常见问题的解答可以参考[官方文档](https://docs.microsoft.com/zh-cn/windows/wsl/faq)。 35 | 36 | ## WSL的运行与简单配置 37 | 运行WSL的方法有很多种,最简单的方法就是给安装好的发行版创建个快捷方式。 38 | 39 | 此外,也可以通过命令行,输入`Ubuntu`(或类似命令)直接进入对应的发行版本,或是通过输入`wsl`进入默认发行版本。详细内容可以参考[官方文档](https://docs.microsoft.com/zh-cn/windows/wsl/wsl-config)。 40 | 41 | 由于Ubuntu的许多命令需要root用户操作,因此我将默认用户设定为了root。设定方法为在命令行中运行`ubuntu config --default-user root`,再次运行Ubuntu即可。 42 | 43 | 首先建议修改一下apt的源。由于一些原因,在大陆访问国外源的速度比较感人。配置文件位于Ubuntu的`/etc/apt/sources.list`文件。可以使用Ubuntu自带的文本编辑器(如[Vim](https://www.vim.org/))编辑,但是这个编辑器对于没用过终端的人估计不太友好。也可以尝试用Windows自带的编辑器修改,但需要注意:**尽管Ubuntu的所有文件都存放在Windows的文件系统下,但直接使用Windows的相关程序修改Ubuntu的文件系统可能会出错误。**可以在Ubuntu中运行`explorer.exe .`(不要漏掉结尾的`.`),然后可以在资源管理器中管理文件。 44 | 45 | 修改`/etc/apt/sources.list`为以下内容(此处以Ubuntu 20为例,其他版本请参考[阿里云镜像的相关文档](https://developer.aliyun.com/mirror/ubuntu))。 46 | 47 | ``` 48 | deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse 49 | deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse 50 | 51 | deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse 52 | deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse 53 | 54 | deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse 55 | deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse 56 | 57 | deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse 58 | deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse 59 | 60 | deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse 61 | deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse 62 | ``` 63 | 64 | 完事之后,运行``apt update && apt upgrade``。更换阿里源后速度应该比较快。 65 | 66 | 现在可以尝试在Ubuntu里面运行命令了。 67 | 68 | 如果需要从WSL访问Windows的文件,则需要从`/mnt/`路径下访问,例如`/mnt/c/`就是Windows的`C:\`。 69 | 70 | ## 搭建LNMP服务器环境 71 | LNMP指的是Linux系统下的Nginx、MySQL、PHP三件套,是比较常见的服务器配置。由于我安装WSL的主要目的就是在本地调试我的个人网站,因此需要搭建一个服务器。最简单的操作就是运行`apt install nginx`,安装完毕后可以使用`service nginx start`启动服务。尝试转到,如果能看到默认的欢迎界面,说明安装成功。 72 | 73 | nginx的配置文件默认位于`/etc/nginx/nginx.conf`,与网站相关的默认配置为`/etc/nginx/sites-available/default`。网站默认的根目录位于`/var/www/html/`,可以直接在这个文件夹下修改,也可以通过修改配置文件改为其他文件夹。 74 | 75 | nginx默认启用的是静态文件,如果要运行php,则需要安装`apt install php`,在Ubuntu 20版本中会安装php7.4。在上文的配置文件中有一部分以`#`开头的注释与php相关,将其修改为:(注意,其中的`php7.4-fpm.sock`可能需要根据安装的php版本改变。) 76 | ``` 77 | location ~ \.php$ { 78 | include snippets/fastcgi-php.conf; 79 | fastcgi_pass unix:/var/run/php/php7.4-fpm.sock; 80 | } 81 | ``` 82 | 此外,在上方的`index`一项中加入`index.php`,如下所示: 83 | ``` 84 | index index.php index.html index.htm index.nginx-debian.html; 85 | ``` 86 | 87 | 安装完毕后可以使用`service php7.4-fpm start`启动服务。随后便可以使用php了。 88 | 89 | 需要注意的是,在WSL中使用php有时会出现加载不完全的情况,需要修改缓冲区。在php-fpm的配置文件`/etc/php/7.4/fpm/php.ini`中找到`output_buffering`,将其值改为`Off`,重启服务即可。 90 | 91 | MySQL是常见的数据库软件,常规来说只需要运行`apt-get install mysql-server mysql-client`即可安装,然而我在WSL下安装出现了问题,多次尝试均未解决,不知原因为何。如果各位有解决方法的话,欢迎告诉我。我退而求其次,在Windows上安装了MySQL。因为WSL和Windows的端口是互通的,因此可以通过3306端口通讯。 92 | 93 | ## 后记 94 | 以上便是我安装WSL的一点点小经验,供各位参考。今后或许会继续更新,如果文中有错误之处还请不吝赐教。 95 | 96 | ## 参考文献 97 | 1. {: #ref-li-jie-ling }黎杰领. 2020年5月OS市场占有率报告:Ubuntu和Linux分别占有1.89%和0.97% [EB/OL]. (2020-05-03) [2020-07-27]. . 98 | 2. {: #ref-rich }Rich. Do not change Linux files using Windows apps and tools [EB/OL]. (2016-11-17) [2020-07.27]. . 99 | {: .list-endnote .square } -------------------------------------------------------------------------------- /_includes/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {% feed_meta %}{% if page.i18n %}{% capture _i18n_url %}{% if page.lang == "zh-cn" %}{{ page.i18n_en | default: page.url | replace: "/posts/", "/posts/en/" }}{% else %}{{ page.i18n_zh | default: page.url | replace: "/posts/en/", "/posts/" }}{% endif %}{% endcapture %} 10 | {% endif %} 11 | 12 | 13 | 14 | 15 | 16 | 17 | {% if page.math %} 18 | 19 | 58 | {% endif %} 59 | 60 | 61 | {% assign css = page.base_css | split: " " %}{% for i in css %} 88 | {% endfor %}{% assign js = page.base_js | split: " " %}{% for i in js %} 89 | {% endfor %} 90 | 91 | {% assign css = page.css | split: " " %}{% for i in css %} 92 | {% endfor %}{% assign js = page.js | split: " " %}{% for i in js %} 93 | {% endfor %} 94 | {% if page.title %}{{ page.title }} - {% endif %}{%t site-name %}{% unless jekyll.environment == "development" %} 95 | 96 | {% endunless %} 97 | -------------------------------------------------------------------------------- /_plugins/i18n.rb: -------------------------------------------------------------------------------- 1 | =begin 2 | 3 | Jekyll Multiple Languages is an internationalization plugin for Jekyll. It 4 | compiles your Jekyll site for one or more languages with a similar approach as 5 | Rails does. The different sites will be stored in sub folders with the same name 6 | as the language it contains. 7 | 8 | Please visit https://github.com/screeninteraction/jekyll-multiple-languages-plugin 9 | for more details. 10 | 11 | =end 12 | 13 | module Jekyll 14 | ############################################################################## 15 | # class Site 16 | ############################################################################## 17 | class Site 18 | attr_accessor :parsed_translations # Hash that stores parsed translations read from YAML files. 19 | 20 | alias :process_org :process 21 | 22 | #====================================== 23 | # process 24 | # 25 | # Reads Jekyll and plugin configuration parameters set on _config.yml, sets 26 | # main parameters and processes the website for each language. 27 | #====================================== 28 | def process 29 | # Check if plugin settings are set, if not, set a default or quit. 30 | #------------------------------------------------------------------------- 31 | self.parsed_translations ||= {} 32 | 33 | # Variables 34 | #------------------------------------------------------------------------- 35 | languages = self.config['languages'] # List of languages set on _config.yml 36 | languages.each do |lang| 37 | self.parsed_translations[lang] = YAML.load_file("#{self.config['source']}/_i18n/#{lang}.yml") 38 | end 39 | 40 | self.config['default_lang'] = languages.first # Default language (first language of array set on _config.yml) 41 | self.config[ 'lang'] = languages.first # Current language being processed 42 | self.config['translations'] = self.parsed_translations # Hash that stores parsed translations read from YAML files. Exposes this hash to Liquid. 43 | 44 | # Build the website 45 | #------------------------------------------------------------------------- 46 | process_org 47 | end 48 | end 49 | 50 | class LocalizeTag < Liquid::Tag 51 | def initialize(tag_name, key, tokens) 52 | super 53 | @key = key.strip 54 | end 55 | 56 | def render(context) 57 | site = context.registers[:site] # Jekyll site object 58 | if site.parsed_translations.nil? 59 | return 60 | end 61 | lang = context.registers[:page]['lang'] 62 | translation_dict = site.parsed_translations[lang] 63 | 64 | if "#{context[@key]}" != "" # Check for page variable 65 | key = "#{context[@key]}" 66 | else 67 | key = @key 68 | end 69 | key = Liquid::Template.parse(key).render(context) # Parses and renders some Liquid syntax on arguments (allows expansions) 70 | 71 | if translation_dict.nil? 72 | puts "Missing language: #{lang}" 73 | lang = site.config['default_lang'] 74 | translation_dict = site.parsed_translations[lang] 75 | end 76 | 77 | translation = translation_dict.access(key) if key.is_a?(String) 78 | 79 | if translation.nil? or translation.empty? 80 | translation = site.parsed_translations[site.config['default_lang']].access(key) 81 | 82 | if site.config["verbose"] 83 | puts "Missing i18n key: #{lang}:#{key}" 84 | puts "Using translation '%s' from default language: %s" %[translation, site.config['default_lang']] 85 | end 86 | end 87 | 88 | TranslatedString.translate(key, lang, site) 89 | 90 | translation 91 | end 92 | end 93 | end 94 | 95 | unless Hash.method_defined? :access 96 | class Hash 97 | 98 | #====================================== 99 | # access 100 | #====================================== 101 | def access(path) 102 | ret = self 103 | 104 | path.split('.').each do |p| 105 | 106 | if p.to_i.to_s == p 107 | ret = ret[p.to_i] 108 | else 109 | ret = ret[p.to_s] || ret[p.to_sym] 110 | end 111 | 112 | break unless ret 113 | end 114 | 115 | ret 116 | end 117 | end 118 | end 119 | 120 | def translate_key(key, lang, site) 121 | translation = site.parsed_translations[lang].access(key) if key.is_a?(String) 122 | 123 | if translation.nil? or translation.empty? 124 | translation = site.parsed_translations[site.config['default_lang']].access(key) 125 | 126 | puts "Missing i18n key: #{lang}:#{key}" 127 | puts "Using translation '%s' from default language: %s" %[translation, site.config['default_lang']] 128 | end 129 | 130 | translation 131 | end 132 | 133 | class TranslatedString < String 134 | #====================================== 135 | # initialize 136 | #====================================== 137 | def initialize(*several_variants, key) 138 | super(*several_variants) 139 | @key = key 140 | end 141 | 142 | def key 143 | @key 144 | end 145 | 146 | #====================================== 147 | # translate 148 | #====================================== 149 | def self.translate(str, lang, site) 150 | if str.is_a?(TranslatedString) 151 | key = str.key 152 | else 153 | key = str 154 | end 155 | return TranslatedString.new(translate_key(key, lang, site), key = key) 156 | end 157 | end 158 | 159 | Liquid::Template.register_tag('t', Jekyll::LocalizeTag ) 160 | Liquid::Template.register_tag('translate', Jekyll::LocalizeTag ) -------------------------------------------------------------------------------- /_posts/2025-01-01-2024-ACGN-Reviews.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2025-01-01 00:00 3 | head_image: 8640806e4cc5b964944b732051ec17e9.webp 4 | head_image_height: 1080 5 | head_image_shown: false 6 | head_image_width: 1920 7 | info: 简单评价。 8 | last_modified_at: 2025-01-02 21:08 9 | tags: 杂记 10 | title: 2024年娱乐回顾 11 | --- 12 | 因为部分音乐需要会员,完整版歌单[在这里](https://music.163.com/#/playlist?id=13050625710)。 13 | 14 | 15 | 16 | ## 动画 17 | ### 辉夜大小姐想让我告白 18 | {% include figure.html src="8640806e4cc5b964944b732051ec17e9.webp" width="640" height="360" %} 19 | 20 | 年底把第一季到剧场版全都看了一遍,算是恋爱喜剧里水平最高的那一批了。虽然每集都是单元剧的拼凑,但是剧情和人物塑造都很到位,笑点也很多。主线剧情当然是白银会长和辉夜大小姐两人的情感,其中也穿插了辉夜对家族传统的反抗、石上从自暴自弃中走出来的成长、弥子对遵守规则的理解的改观等,每次当剧情变得沉重时却又会被一些搞笑的段子打破,让人看得很舒服。但是动画做到会长和辉夜在一起之后就没有继续了,原作漫画还有一半没有动画化,希望还能有动画续作。 21 | 22 | ### 败犬女主太多了! 23 | {% include figure.html src="e473bbfa7efa25cbd14226a538f56d33.webp" width="640" height="360" %} 24 | 25 | 同样算得上是恋爱喜剧里水平最高的那一批。不得不说以“败犬”为主题似乎有些沉重,而且一下子还来三个。三位败犬女主各有各的特色,老八性格活泼,柠檬是运动系女孩,小鞠内向胆小,三人成为败犬的经历也各有特色。高中生活的青春感,恋而不得的共情感,以及男主温水不时插入的吐槽,让人看得很舒服。虽然温水自述“没有朋友”,但是他不仅有个兄控妹妹,还有三位败犬女主好朋友,这tm不是现充吗? 26 | 27 | ### 小市民系列 28 | 提到这部动画就不得不把它和《冰菓》对比。同样是日常推理,同样的原作者,改编出来的动画却完全不同。画面不知道为什么用了电影宽屏的比例,而且剧情完全是平铺直叙,再加上偶尔不知道在干什么的运镜。豆瓣上有篇长评分析了如果这部动画是京阿尼制作的会怎样,我觉得非常有道理。《冰菓》在描述推理的时候总会配上略微有些夸张的配图说明,以及恰到好处的配乐。而这部动画的推理基本上就是在对话中完成的,没有任何辅助。说实话,如果不是因为原作者是同一个人,我可能根本不会看这部动画。 29 | 30 | ### 间谍过家家 31 | {% include figure.html src="f633a7040f7cb34d0b3bbcda3e6b758b.webp" width="640" height="360" %} 32 | 33 | 又是喜剧(我好喜欢喜剧),故事的核心在于三个人的互相伪装,但抛开伪装,即便是在做任务,三个人也展现出了家庭的温馨。阿尼亚的颜艺和她“虽然会读心但经常理解错误”的性格也带来了不少笑点。 34 | 35 | ### 名侦探柯南 百万美元的五棱星 36 | 去年的剧场版剧情太烂,导致我今年都约不到朋友一起看。结果今年的剧情也没好到哪去,为了宏大的场景而舍弃了真实感,为了票房故意把人气角色拉出来,完全是为了卖票而做电影。评价这么差我为啥还去?人傻钱多,为情怀买单罢了。 37 | 38 | ### 欢迎来到实力至上主义教室 第二季 39 | 拖了好久才看完,因为我看过一部分小说,感觉没有看第一季的时候这么惊艳了。小说本身剧情很多,但是篇幅所限要缩到几集里,所以进度难免有些快,看完一遍之后基本上啥都忘了。 40 | 41 | ### 哆啦A梦 大雄的地球交响乐 42 | 剧情我不是很能理解,但是考虑到是子供向的动画,我也不好过多挑剔。 43 | 44 | ## 真人影视 45 | ### 因果报应 46 | 本来我对印度电影没啥兴趣,而且印度人的脸看着都差不多,我也分不清楚。看了一半之后终于发现了时间线不对,但也没仔细想。但是跟我一起看的朋友很敏锐地发现了真相,我当时还觉得她脑洞有点大,没想到看到最后她说的都对。 47 | 48 | ### 灵媒侦探城塚翡翠 49 | {% include figure.html src="fb2a77341d14fc4f6853db64029a30a0.webp" width="640" height="360" %} 50 | 51 | 稍微有些慢热,还好只有5集,不然的话我可能看一半就弃了。一开始还以为女主确实是灵媒,丝毫没有怀疑过她的灵能力。我也没在意标题里“灵媒侦探”是什么意思,以为纯粹是靠灵媒能力来破案。看到一半的时候我还在想,靠灵能力算什么侦探剧啊。直到最后一集真相揭晓我才恍然大悟。而且前四集里女主的形象都有些阴沉,直到最后一集才发现是小恶魔类型的。 52 | 53 | ### 最后的里程 54 | 内地上映前评分有8.0,上映之后评分掉到了7.4。说实话这电影确实不行,可能是《非自然死亡》和《机动搜查队404》的联动给抬高了一点评分。剧情马马虎虎,快递工人过劳陷入昏迷,不去对付高管,反而去对付普通民众,脑子不太好使。想到《非自然死亡》里工厂厂长为了员工的健康而停工的剧情,比这电影高了不知道多少倍。引进版的翻译更是一塌糊涂,翻译和校对至少有一个不会日语的,印象最深的就是电影最后“这次不会爆炸哦”翻译成“请一定要收下”,而且片尾名单翻译了石原里美井浦新却不翻译绫野刚星野源是怎么回事? 55 | 56 | ### 重启人生 57 | {% include figure.html src="a5d2a4f92364c1fd5eaeb432347120bb.webp" width="640" height="360" %} 58 | 59 | 看似是日常轻喜剧,但是笨蛋节奏也埋了很多伏笔,有些伏笔我第一遍看的时候也注意到了但是没仔细想,直到最后揭晓真相的时候才大吃一惊。故事的主线是女主在意外去世之后多次重新开始自己的人生,每次人生既有相同的经历,也有因为选择不同而产生的变化。直到最后几集,剧情的最大反转才出现,但是因为恰到好处的铺垫,又不会让人感觉过于惊讶。 60 | 61 | ### 十角馆事件 62 | {% include figure.html src="3b7a5565dd3c38d12b01693fa6f3560c.webp" width="640" height="360" %} 63 | 64 | 绫辻行人的馆系列我高中的时候读过很多遍,依稀还记得一些情节,但是十角馆的核心诡计被我给忘了。刚好,这部电视剧非常还原原作,通过巧妙的叙述方式隐藏了真凶和作案手法。虽然演员都不是什么知名演员,但是呈现出来的效果很不错。 65 | 66 | ### 最爱 67 | 悬疑部分没多少,大致能猜出来发生了什么事情。剧情的核心就像标题所说,“最爱”,讲述的是人们为了维护自己最爱的人而做出的牺牲。 68 | 69 | ### 为了N 70 | 悬疑部分还是有一点的,但是中途就能猜出来有人在说谎。和《最爱》类似,每个人都在为了维护自己最爱的人而做出的牺牲。 71 | 72 | ### 从21世纪安全撤离 73 | 很颠的风格,很对得上我的脑电波。 74 | 75 | ### 抓娃娃 76 | 笑点很足,立意也还行。片外的人看是喜剧,但对于片内的孩子来说是悲剧。 77 | 78 | ### 年会不能停! 79 | 笑点很足,讽刺的对象是啥大家都清楚。不知道等我工作的时候会是啥样子呢。 80 | 81 | ### 玻璃之城 82 | 剧情上还是有点反转的,最后真凶出现的时候有些惊讶(当然也可能是因为我看的时候完全没动脑子)。 83 | 84 | ## 游戏 85 | ### 女神异闻录5 战略版 86 | 战棋游戏,系统参考了原作的设定,剧情则是完全原创,还增加了原创角色。虽然提供了试错的“反悔”操作,但实际用下来不太灵活。再加上祖传的二周目从零开始,完全不想玩第二遍。 87 | 88 | ### 女神异闻录3 Reload 89 | {% include figure.html src="5115cc276a7105ba256df29810c7c308.webp" width="640" height="360" %} 90 | 91 | 玩过P5R再来玩玩P3R,虽然发售之前听说过很多人吐槽“爬塔”,但是似乎除此之外的评价还不错,于是我就来试试看。剧情上略微有些沉重,虽然是高中生的日常,但是主角团的每个人都有不少秘密,再加上男主最后的下场,导致我不是很喜欢这个结局。除此之外,每天的日常就是发展发展人际关系、去店里吃吃喝喝打打游戏,偶尔去打个迷宫。我不太喜欢这种做任务还得看日子的系统,因为没办法按照自己的喜好推进剧情。饱受诟病的爬塔我倒是没觉得太差,每个月抽一天打个二十多层好像也还能接受。音乐很好听,《Full Moon Full Life》我单曲循环了很多遍。 92 | 93 | ### Another Code 回忆录 两种记忆/记忆之门 94 | 原作口碑很好,重制之后剧情和系统都改变了不少。谜题被重新设计了,而且难度大幅降低,确实很符合全年龄向的游戏。 95 | 96 | ### 夏日重现 Another Horizon 97 | 粉丝向作品,Galgame式的对话方式导致剧情表现水平甚至不如动画。添加的原创剧情补充了剧情的另一种走向,但是原创角色小弓场香织没什么存在感,基本上相当于凑数的。 98 | 99 | ### 谋杀谜案悖论 悠悠一夏十五载 100 | 玩法上既有推理游戏常见的问询线索、出示证物环节,也有独特的投票环节。这个推理系统可能到第三章的时候就有些乏味了,但是到了第四章,突然剧情出现了大反转,甚至直到第五章才会发现前几章埋下了许多伏笔,直到最后才回收,有些类似之前玩过的《AI:梦境档案》。玩完所有结局之后会有一种恍然大悟的感觉。 101 | 102 | ### 巴别塔圣歌 103 | 如同标题所说,游戏的核心类似于“巴别塔”的故事,通过人们的交流来将不同的语言文字一一对应。开始的时候谜题还比较简单,到了后期就有些费脑子了,而且除了破解语言文字之外还很考验操作。 104 | 105 | ### 纸片马力欧RPG 106 | 说实话马力欧的RPG系列都有些QTE要素,而且是每次战斗都要QTE,说实话搞得我比较反感。再加上没有传送功能经常需要长时间移动切换地图,而且2.5D的地图躲不开野怪,就算是低等级的野怪也需要一番操作才能打死,非常耗时。除了剧情稍微有些意思之外,其他系统都有些过时了。 107 | 108 | ### Famicom侦探俱乐部 笑脸男EMIO 109 | 关于这个游戏我在B站写了长评,可以去看看。核心就是一句话,期待落空了。总的来说,本作的画面和音乐确实非常出色,剧情也很感人,但是在操作和推理方面还有很大的提升空间。作为一部社会派推理小说来说尚可,但不要期待有太多的推理成分。当然,剧情里也有很多不尽人意的地方,涉及剧透就不展开说,可以去看长评。 110 | 111 | ### 人中之龙7外传 无名之龙 112 | {% include figure.html src="8c6d4e8752e17caf7adec81049938080.webp" width="640" height="360" %} 113 | 114 | 因为马上要退出XGP了,所以尝试了一下。主线流程不长(因为是外传),剧情也是原作的补充。虽然是我不擅长的动作游戏,但简单难度+辅助系统导致通关毫无难度,甚至最终BOSS也被我一遍过。小游戏非常丰富,甚至让我花牌打上了瘾。 115 | 116 | ### 人中之龙7 光与暗的去向 117 | 没错,我是先打完外传才打的本篇。本篇流程要稍微长一点,而且是我熟悉的回合制RPG。虽然没有难度选择,但主线通关并不难,然而最后的千禧塔我刚入门就被干翻了,直接卸载游戏。剧情上看似轻松活泼,实则暗流涌动,因为是黑道为主题,难免会出现打斗,甚至闹出人命。好在最后还算是喜剧。小游戏同样非常丰富,但是公司经营系统有些食之无味弃之可惜,没什么操作空间,耗时又长,为了全成就(虽然我最后也没全成就)还不得不做,算是一点小缺陷。 118 | 119 | ### 暗喻幻想:ReFantazio 120 | {% include figure.html src="a4166297aaf5680f142c7dcf6ec4afea.webp" width="640" height="360" %} 121 | 122 | 这游戏我预购了,但是发售之后却没能吸引我玩下去。系统方面吸收了女神异闻录系列的“好传统”——限时。主线和支线都不是想做就做,想一口气推完主线?不行,没到时间你必须在这卡着。而且前期MP回复非常艰难,又因为有时间限制,想自由回复MP就得多耗一天。除此之外开门、开宝箱、战斗结算和日期切换总有谜之长动画,看一次是享受,看多次是难受,想快速推迷宫推剧情的时候反复看是折磨。不过RPG系统还是有一定创新点的,加上低等级野怪可以不进战斗直接秒杀,这还是值得称赞的。 123 | 124 | ### PICO PARK 125 | 说实话我之前没怎么玩过联机游戏(因为找不到朋友),但是好在今年拉了实验室的几个人入坑,竟然能组起来多人联机游戏了。操作不复杂,但是很有节目效果。 126 | -------------------------------------------------------------------------------- /_posts/2023-02-24-Summer-Time-Rendering-Another-Horizon-Translation.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2023-02-24 21:43 3 | head_image: 218a17f49457714e7dcc6e5c563ccf94.webp 4 | info: 夏日重现。 5 | last_modified_at: 2024-04-15 00:45 6 | links: 7 | - - https://summertimerendering.mages.co.jp/game/ 8 | - 游戏官网 9 | - - https://github.com/Xzonn/STRAHChsLocalization 10 | - 汉化相关代码 11 | tags: Switch 汉化笔记 12 | title: 《夏日重现 Another Horizon》文本汉化笔记 13 | --- 14 |
        15 | **[汉化发布页](https://xzonn.top/STRAHChsLocalization/)** 16 |
        17 | 18 | 去年看完了《夏日重现》的动画,也很早就知道本作要有改编的Switch/PS4平台文字冒险游戏,但是不用想也知道一定是没有中文的。于是在游戏发售后,我开始琢磨怎么汉化。 19 | 20 |
        21 | **注意:本文介绍的内容仅用作技术交流,汉化方式为重定向补丁,请支持正版。** 22 |
        23 | 24 | ## 字体 25 | {% include figure.html src="d6ae46d8399a484aab8c60160b90b76d.webp" alt="romfs的文件结构" %} 26 | 27 | 拆开游戏一看,“Data”“StreamingAssets”几个文件夹直接蹦了出来,一看就知道是Unity做的游戏。字体文件可以很快从`Data/level1`和`Data/StreamingAssets/Switch/AssetBundles/data/fonts.unity3d`文件中找到,拿[AssetStudio](https://github.com/Perfare/AssetStudio)看了一下,没有用TextMesh Pro插件,而是直接把2个otf文件(分别是同一字体的两个字重)打包进去了。于是很容易就想到拿中文字体替换掉,但是AssetStudio只能导出不能导入,因此换用另一个工具[Asset Bundle Extractor](https://github.com/SeriousCache/UABE)(UABE)导入。 28 | 29 | 首先处理的是`fonts.unity3d`文件,没想到UABE打不开它,可能是太久没更新不支持最新的文件格式。于是我只好找出来之前搞火纹结合用的工具,先把`CAB-...`这个文件提取出来,再拿UABE打开,替换完之后再导入回去。这个工具只能处理bundle文件,被我扔到GitHub上[开源](https://github.com/Xzonn/BundleHelper)了。 30 | 31 | 在替换字体文件的时候,出了点小插曲。我发现替换字体后游戏会卡在初始界面,说明是打包后的文件有问题。在经过漫长的测试后,我发现这两个字体的总大小必须和原来两个字体的总大小完全一致,大了小了都不行。小一点的字体文件倒是可以在最后补0解决问题的,但比它大的字体文件就不好办了。因为游戏里有“澪”这个字,一些只有“简体”字库的字体不支持显示。最终我选了几千个常用字,找了个大字符集字体做了个子集化字体导入进去了。 32 | 33 | 这个问题直到之后我才解决——我发现用我自己的打包工具创建的新文件无法被AssetStudio读取,通过不断打断点才发现,打包替换包含文件的时候我忘了更新文件大小,导致文件大小不一致……最终我通过[加了一行代码](https://github.com/Xzonn/BundleHelper/blob/master/BundleHelper/BundleWriter.cs#L216)解决了问题。 34 | 35 | ## 文本 36 | 首先想到文本在Unity的文件里,但是计数后发现数量太少,支撑不起一个文字冒险游戏。于是继续寻找,找到了`Data/StreamingAssets/scrpt.cpk`这个文件。这个文件是[Criware](https://www.cri-mw.co.jp/)的打包格式,可以拿[CriPakTools](https://github.com/wmltogether/CriPakTools)解包和打包。但是实际测试下来打包之后的文件游戏无法读取,检查了代码之后猜测是补齐方式有问题,因此我[fork了一份](https://github.com/Xzonn/CriPakTools)修改了代码,总算是能用了。 37 | 38 | 解包后发现里面有很多文件,但是都是加密的,看起来不是很好处理。拿文本编辑器打开之后长这样: 39 | 40 | ``` text 41 | .bmEHM..[.RO→汉化发布页← 15 | 16 | ## 说明 17 | 『**ルイージマンション**』(参考译名:《**路易吉洋馆**》,英文名:***Luigi's Mansion***)是2001年于GameCube平台发售的游戏,并于2018年在3DS平台发售了重制版。其续作《**路易吉洋馆2**》(繁体:《**路易吉洋樓2**》,日文:『**ルイージマンション2**』)于2013年发售,港台版自带简繁中文支持。 18 | 19 | 由于重制版并未提供官方简体中文,因此开设汉化项目,旨在对本游戏提供爱好者的汉化工作。本项目基于日本发行版汉化。 20 | 21 | **声明:本人对游戏软件仅做研究用途,本人不提供软件本体,也从未对软件本体进行非法传播,更未对其用作商业用途。如因非法传播造成法律纠纷,概与本人无关。特此声明。** 22 | 23 | ## 图片 24 | 本游戏中需要汉化的图片仅有标题界面的“ルイージマンション”,而标题图片存储于`/Region_JP/Japanese/UITitle.gar`文件中。利用Kuriimu系列的Karameru软件可以打开该文件,但在不修改任何文件的情况下直接保存并在实机测试时会报错。对比一下两个文件可以看出,保存后的文件比原文件大小更大,因此推测是在保存过程中偏移量(Offset)出现了变化。由于导入图片时文件大小不变,偏移量也不变,因此我用Python写了一个简单粗暴的脚本,直接读取偏移量并修改相应数据。实机测试后发现没有报错,并且标题可以正常显示为修改后的图片。 25 | 26 | ``` python 27 | with open("UITitle.gar.bak", "rb") as f: 28 | ori = list(f.read()) 29 | 30 | with open("I_Logo_00.ctxb", "rb") as f: 31 | logo = f.read() 32 | 33 | ori[0x013800: 0x033880] = logo 34 | 35 | with open("UITitle.gar", "wb") as f: 36 | f.write(bytes(ori)) 37 | ``` 38 | 39 | 由于标题页面是有动画的,即“Luigi”的“i”和“Mansion”的“a”上的两只眼睛会动,为了保证“眼睛”的位置不变,需要保证英文的位置不变。而原标题的日文“ルイージマンション”覆盖了英文“Luigi Mansion”,修改起来比较困难,因此我提取了北美发行版中的英文标题,简单修改后与日版标题的英文对齐,并在两行字中间加入了“路易吉洋馆”的标题。 40 | 41 | ## 文本 42 | 本游戏中的所有文本存储于`/Region_JP/Japanese/main.gmsg`文件中,而Kuriimu对此文件的支持不佳。在网络上查找资料后发现该格式曾在同一开发商制作的《*塞尔达传说 梅祖拉的面具 3D*》(下称 **MM3D**)中使用。对比两游戏的文件二进制文件,发现MM3D中的版本数据是`01 00 00 00`,而本作版本数据是`03 00 00 00`,即两个文件的格式并不完全相同。但是,这对之后的工作仍有启发。 43 | 44 | 再次翻看`main.gmsg`的内容,发现从位置`0xe414`处开始,数据很有规律,如`PRESS`、`BUTTON`、`2001 - 2018 Nintendo`等,猜测这部分开始是文本内容,且为UTF-16-LE编码。随后向上搜索`14 E4 00 00`(偏移量,小端序),在位置`0x5bc4`处发现了这个数据,简单查看了一下周围的数据,内容大概为:`01 00 00 00 7F 00 00 00 14 E4 00 00 26 00 00 00`,猜测这是4个`int`数据,分别代表编号、*(未知)*、偏移量、文本长度。按照这个逻辑,我用Python脚本尝试对文本导出,得到了比较好的结果。随后我修改了几个文字后导入并在实机测试,发现可以显示。 45 | 46 | 其中一句文本如下: 47 | 48 | ``` plaintext 49 | Cスティックで\x7f\x16にゅうりょく\x00入力\x7f\x17した\x7f\x16ほうこう\x00方向\x7f\x17に\x7f\x01\x7f\x16まわ\x00回\x7f\x17ります。\x7f\x01\x7f\x16うえ\x00上\x7f\x17に\x7f\x16にゅうりょく\x00入力\x7f\x17すると\x7f\x16うえ\x00上\x7f\x17を\x7f\x16む\x00向\x7f\x17き\x7f\x01\x7f\x16した\x00下\x7f\x17に\x7f\x16にゅうりょく\x00入力\x7f\x17すると\x7f\x16した\x00下\x7f\x17を\x7f\x16む\x00向\x7f\x17きます。\x7f\x00 50 | ``` 51 | 52 | 经过对比后发现,`\x7f\x16`和`\x7f\x17`是用来标记汉字假名注音的,而`\x7f\x01`是换行符,`\x7f\x00`是结尾符。为了方便汉化,我将所有的假名注音删去,得到了初步处理后的文本。随后我在简单分词后尝试机翻,但导入并实机测试时出现了死机问题。经过排查后,发现控制符`\x7f\x02\x7f\x15\x03\x00`和`\x7f\x15\uffff\uffff`用来标记字体颜色,当两个控制符之间的字符数量增减后会出现问题。因此我想到了最简单的办法,即超出的字数从结尾删掉,不足的字数用全角空格补齐,果然未再出现死机。 53 | 54 | 2024-03-26更新:深入研究发现,实际上有些控制符是需要对齐到4字节(2字符)的,导致没有处理控制符时会死机。原本的处理方式是添加全角空格,并强制全角空格宽度为0,这会导致字体渲染存在挤压的问题。因此我确认了需要对齐的控制符,并在导入时对其进行了处理。实际上在1.0.0版本发布时就已经解决了这个问题,只是没有更新汉化笔记。 55 | 56 | ## 字库 57 | 本游戏中的字库存储于`/Region_JP/Fonts/main.gzf`和`/Region_JP/Fonts/location.gzf`。利用Kuriimu系列的Kukkii软件可以打开该文件,但图片显示出现错误。分析源代码后发现,该字库文件的图片应强制设为`LA44`格式,在此格式下可以正常导出字库内的图片。同时,利用Kukkii源代码中对GZF格式的支持,我得到了所有字符数据的存储位置,并用Python脚本提取。 58 | 59 | 然而,导入过程出现了问题:游戏并不会读取文件中存储的图片偏移量,而是默认读取`0x1780`处的图片数据。因此,这限制了字库能存储的字符数量,即496个。 60 | 61 | 2019-02-15更新:本人碰巧拆包了《*永恒绿洲*》(Ever Oasis),发现其字库也是`.gzf`格式,查了一下开发商,竟然也是GREZZO……这个游戏使用的字库容量比本作的字库容量更大,有1968个字符,因此字库问题大概可以解决了…… 62 | 63 | 2024-03-26更新: 64 | 65 | 再度研究了字库文件,实际上Kukkii中关于`.gzf`文件的支持是不完善的,而这个软件的继承者Kuriimu2也没有对`.gzf`文件提供支持,所以还是得自己研究。翻看[Kukkii中关于`.gzf`文件的代码](https://github.com/IcySon55/Kuriimu/blob/master/src/Cetera/Font/GZF.cs),其中对头文件格式的结构定义是这样的: 66 | 67 | ``` csharp 68 | public class Header 69 | { 70 | public Magic magic; 71 | public int version; 72 | public ushort imgInfoOffset; 73 | public ushort unk1; 74 | public int entryLength; 75 | 76 | public int imgCount; 77 | public int entryCount; 78 | public uint unk2; 79 | public uint unk3; 80 | 81 | public Format format; 82 | 83 | public byte pad1; 84 | public short unk4; 85 | public short unk5; 86 | public short unk6; 87 | 88 | public int unk7; 89 | } 90 | ``` 91 | 92 | 根据我对《路易吉洋馆》日版、美版、欧版、韩版的研究,我将部分变量重命名: 93 | 94 | ``` csharp 95 | public class Header 96 | { 97 | public Magic magic; 98 | public int version; 99 | public ushort imgInfoOffset; 100 | public ushort imgLength; 101 | public ushort entryLength; 102 | public ushort unk1; // Always 0 103 | 104 | public int imgCount; 105 | public int entryCount; 106 | public uint unk2; // Always 0xff0a 107 | public GZFImageFormat format; 108 | 109 | public uint fontSize; 110 | public ushort unk4; 111 | public ushort unk5; 112 | public ushort tileWidth; 113 | public ushort tileHeight; 114 | } 115 | 116 | public enum GZFImageFormat : ushort 117 | { 118 | L4 = 8, 119 | L8 = 6, 120 | } 121 | ``` 122 | 123 | 其中`GZFImageFormat.L4`表示每个像素占4 bit(半个字节),`GZFImageFormat.L8`表示每个像素占8 bit(一个字节)。根据这个结构,我可以提取出字库中的所有字符图片,并用Python脚本导出。完整的文件结构可以参考[更新后的脚本](https://github.com/Xzonn/LuigiMansion/blob/master/scripts/gzf.py)。我也测试了修改图片和包含字符的数量,发现可以正常显示,说明我之前的推测可能是错误的(或许是我当时的导入脚本没有修改某些变量?)。 124 | 125 | ## 汉化预览 126 | {% include figure.html src="9f9902a4bc809b069f20954f9b71a0e6.png" alt="标题界面" width="400" height="480" %} 127 | 128 | {% include figure.html src="03fa9bfb435915290a85a935650dbd04.png" alt="选择存档界面" width="400" height="480" %} 129 | 130 | {% include figure.html src="cbda96053ce9b31ae627b27992b5ff5b.png" alt="存档操作界面" width="400" height="480" %} 131 | 132 | {% include figure.html src="149a4d3e85f46f847d176841a4dafc77.png" alt="游戏界面" width="400" height="480" %} 133 | 134 | {% include video.html aid="45332875" page="1" %} 135 | 136 | ## 汉化进度 137 | - 2018-10-12: 138 | - 开始项目,尝试汉化北美发行版,但因问题太多而搁置。 139 | - 2018-11-11: 140 | - 尝试汉化日本发行版。 141 | - 2018-12-02: 142 | - 日版文本、字库问题得到一定程度解决,交由组长VLSMB后续分配任务。 143 | - 2018-12-05: 144 | - 发布[开坑说明/日文翻译招募贴](https://tieba.baidu.com/p/5969451467)。 145 | - 2019-01-08: 146 | - 标题图片问题解决。 147 | - 2019-02-15: 148 | - 字库问题基本解决。 149 | - 2019-03-04: 150 | - 发布机翻汉化预览视频。 151 | - 2019-03-16: 152 | - 发布汉化预览兼通关流程视频:开始游戏、探索区域1。 153 | - 2019-03-22: 154 | - 发布汉化预览兼通关流程视频:探索区域2。 155 | - 2019-03-24: 156 | - 发布汉化成果。 157 | 158 | ## 致谢 159 | * 感谢[IcySon55](https://github.com/IcySon55)的[Kuriimu](https://github.com/IcySon55/Kuriimu)项目及该项目的贡献者。 160 | * 感谢超巨星汉化组的组长VLSMB及本汉化组的所有成员。 161 | -------------------------------------------------------------------------------- /_posts/2021-12-28-2021-ACGN-Reviews.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2021-12-28 00:05 3 | head_image: 6c84e8b2e463152157d5755d716b39dc.jpg 4 | info: Xzonn的2021年娱乐回顾。 5 | last_modified_at: 2022-03-01 17:02 6 | logs: 7 | - 2022-03-01:修正错别字。 8 | tags: Switch 杂记 9 | title: 2021年娱乐回顾 10 | --- 11 | 年末将至,又到了一年一度的年度总结的时间。作为先头兵,我先把今年的游戏、动画、影视回顾一遍。 12 | 13 | ## 游戏 14 | ### 健身环大冒险 15 | 因为1月份发了奖学金,我就狠下心下单了《健身环大冒险》,然后幻想着自己能够通过健身环强身健体——本应是这样的。我没数过自己买来游戏之后玩过几次,零零散散加起来可能也不到两星期。要说原因的话,上半年没工位,也没买显示器,要想玩只能对着小小的Switch屏幕,实在是伸展不开。等下半年的时候我又已经对它没什么兴趣了,就放着吃灰了。希望2022年我能有几次把它打开的机会吧。 16 | 17 | {% include figure.html src="fdcc4c83180e1b61973014f3bba15d5d.jpg" alt="健身环大冒险" width="400" height="225" %} 18 | 19 | ### 莱莎的炼金工房2 ~失落传说与秘密妖精~ 20 | 又是我看画风买的游戏。系统相比前作有了大幅改变,炼金系统的品质计算不再被低品质素材拉低,品质提高更加简单。而且这类堆叠属性的游戏很合我胃口,甭管是啥堆到999就成了。探索方式有了更多选择,只不过新加入的迷宫系统基本没什么难度。战斗变得更加爽快,配合道具的使用简直无敌。 21 | 22 | {% include figure.html src="5b47acc2b3aaa14ed3b93399cd5fd06b.jpg" alt="莱莎的炼金工房2 ~失落传说与秘密妖精~" width="400" height="225" %} 23 | 24 | ### 超级马力欧 3D世界+狂怒世界 25 | 对我个人来说,3D马的体验要比2D马更好一些,主要体现在3D马的移动范围比较广,不像2D马判定范围那么严格。“3D世界”部分是传统的关卡型,需要收集星星和徽章,因为有些零碎我至今还没收集完,只是通关了主线。开学之后我也和朋友一起分享手柄玩过几关,体验也还不错,适合多人同乐。“狂怒世界”部分有点像是小的《奥德赛》,关卡设计还是挺有趣的,只不过狂怒酷霸王的出现有些频繁,有时候让人头疼。或许可以期待一下不知道什么时候才会公布的《奥德赛》续作。 26 | 27 | {% include figure.html src="9c453e98ab49930b7bedf9d119dd4826.jpg" alt="超级马力欧 3D世界+狂怒世界" width="400" height="225" %} 28 | 29 | ### 异度神剑2 30 | 因为我比较喜欢RPG,所以我早就想体验一下这作,但是一直没买。实际体验之后发现并没有我想象中的那么好。一方面,这作算是ARPG,需要考虑走位、出招时间等操作上的因素,再加上地狱般的新手引导,让我刚接触的时候完全不知道该怎么玩,只能求助攻略。另一方面,这作的地图设计也是恶梦,有时候在地图上绕了半天就是找不到任务点在哪。而且战斗属于即时对战,在找路的时候经常会触发对战,而对战又不能主动脱离,只能逃得远远的,再加上触发对战时不显示地图,让我每次跑路都心惊胆战。剧情或许是一大特色,不过我没有太多空暇时间通关了,目前处于弃坑状态。另外,找截图的时候我才想起来,这作竟然不支持长按截屏键录制视频,不知道是不是机能的原因。 31 | 32 | {% include figure.html src="2d737e223039956532624fe3b6d022d2.jpg" alt="异度神剑2" width="400" height="225" %} 33 | 34 | ### Famicom侦探俱乐部 35 | 我入手的第一个收藏版游戏。作为文字冒险游戏来说重制的质量很高了,全程语音,而且人物有各种反应。只不过系统设计受到原作时代所限,提示较少,很容易卡住不知道该干什么。总体来说还是值得体验的一款AVG。具体感想之前已经发过了([微博](https://weibo.com/7199621409/Koo25DULo)·[bilibili动态](https://t.bilibili.com/546439424825818222))。 36 | 37 | {% include figure.html src="f4296672a9ef6e5eaf4f24bf5ea1cc81.jpg" alt="Famicom侦探俱乐部" width="400" height="225" %} 38 | 39 | ### 双人成行 40 | 我心中的年度游戏。虽然因为各种原因,我已经和两个人玩过了游戏,但至今仍未通关。尽管没通关,这也不妨碍我认可它作为年度游戏。这部作品对双人合作拿捏得很好,不像《胡闹厨房2》那么紧张,而是让玩游戏的两个人有充分交流的机会。在关卡设计方面,这作也很有特色,将许多操作方式和游戏类型融合在了同一部作品中却又不显得突兀,即使之前没玩过动作冒险游戏的人也能快速上手。虽然剧情有些俗套,但是……管它呢,好玩就行。 41 | 42 | {% include figure.html src="a03579ffd23db5840083243c3596cfae.jpg" alt="双人成行" width="400" height="225" %} 43 | 44 | ### 绯红结系 45 | 看画风挺对我胃口,但是看评价似乎有些两极分化。玩下来之后总体体验还是不错的,动作很爽快,不同的超脑力有不同的效果,来回切换超脑力能打出漂亮的连击。剧情采用了双主角双视角的方式叙述,不过过场基本都是PPT,让表现力稍微打了些折扣。另外我先选了重线,因为玩之前看过采访所以也对这种叙述方式有了一点心理准备,玩的时候基本上看得懂剧情。总体来说还是值得一玩的。 46 | 47 | {% include figure.html src="c35be130bc914bf305efaf65b9c2bee9.jpg" alt="绯红结系" width="400" height="225" %} 48 | 49 | ### 塞尔达传说 御天之剑 HD 50 | 我通关的第一部《塞尔达传说》。体感操作让我又爱又恨,一方面来说体感确实新鲜,而且战斗的时候非常爽快,但另一方面来说,体感操纵很不准确,需要经常重置角度。抛开体感不谈,游戏内容还是很丰富的,游戏流程基本就是在不断探索新的区域、走迷宫、完成任务。我本来是不太喜欢动作类的游戏的,打最终BOSS的时候还有些顾虑,不过还好我顺利打过了。希望以后还有更多加入中文的《塞尔达传说》能登录Switch吧。 51 | 52 | {% include figure.html src="f9b0e8d18606878e6235ecb8478a5387.jpg" alt="塞尔达传说 御天之剑 HD" width="400" height="225" %} 53 | 54 | ### 新美妙世界 55 | 可能是我入手周边最多的游戏,也是我第一个同时买了实体版和下载版的游戏。之前打折的时候玩过前作《Final Remix》,感觉很对我胃口,于是新作发售之后我毫不犹豫就下单了。3D化的世界效果很不错,徽章的操作不再是划屏幕,收集要素非常丰富,人物设定也更加多元化。只不过没中文,玩起来比较吃力,有些剧情没太搞清楚在干什么。之前也已经发过感想了([微博](https://weibo.com/7199621409/KsfvqtvbP)·[bilibili动态](https://t.bilibili.com/555865082750720987))。 56 | 57 | {% include figure.html src="569e1e8ae6c79d988587585ac83e5128.jpg" alt="新美妙世界" width="400" height="225" %} 58 | 59 | ### 搭档任务 秘密搜查组 60 | 我头一次玩这种四个主角全是男人的游戏……系统上比较新颖,有文字冒险部分也有QTE(快速反应事件)部分,不过都比较简单。比较有挑战性的部分大概是根据每个地图选择搭档,经常会因为漏过某条线索而选错。剧情整体来说还是挺跌宕起伏的,最终BOSS的身份也让我吓了一跳。以及这作有隐藏结局,虽然我也是在看了攻略之后才知道的。总体来说如果是冲剧情来的还是值得一玩的,如果是冲推理来的我觉得还是算了。 61 | 62 | {% include figure.html src="e0205c732680eed652c36d1bf91df0dd.jpg" alt="搭档任务 秘密搜查组" width="400" height="225" %} 63 | 64 | ### 集合啦!动物森友会 65 | 这个也是我考虑了很久才买的游戏,因为一直担心没人和我一起建岛。趁着新学期开学、买了显示器,我也买了动森,准备岛建。不过实际上岛之后才发现要想建岛还得多赚钱,要想多赚钱还得倒卖大头菜,于是没玩了几天就搁置了。不过这种慢节奏的游戏或许对于舒缓心情来说很有必要吧。 66 | 67 | {% include figure.html src="4d6fc01264a48352ab3521a7dd29d8f1.jpg" alt="集合啦!动物森友会" width="400" height="225" %} 68 | 69 | ## 动画 70 | ### 无能的奈奈 71 | 标题有两种译名:“无能的奈奈”和“无能力者娜娜”。看完之后认为前者更适合这部作品。动画第一集就来了个神反转,随着剧情推进我才逐渐理解“無能”的意义:不只是“没有超能力”,还代表了“没有改变的能力”——主角奈奈只是一个被利用的工具人,没有超能力的她无法反抗上级,也无法改变这个世界。建议看完动画之后去看漫画,后面的剧情更精彩。以及,片尾曲的歌词其实算是奈奈的真实写照。 72 | 73 | {% include figure.html src="773be8f244115ca5ae738ed6504f8612.jpg" alt="无能的奈奈" width="400" height="225" %} 74 | 75 | ### 辉夜大小姐想让我告白~天才们的恋爱头脑战~ 76 | 作为恋爱番来说很好地表现了少年少女的小心思,两个人“勾心斗角”最后往往是“两败俱伤”。作为搞笑番来说笑点很足,除了御行和辉夜的智熄操作外,藤原书记和石上会计的乱入也增加了许多笑点。搞笑番嘛,开心就好了。 77 | 78 | {% include figure.html src="b072e77df1b19ee2b02fca2f05a3c176.jpg" alt="辉夜大小姐想让我告白~天才们的恋爱头脑战~" width="400" height="225" %} 79 | 80 | ### 名侦探柯南 绯色的子弹 81 | 和茂茂两人一起看的,柯南剧场版首次同步上映。剧场版发挥很稳定,果不其然还是动作片。 小哀的戏份还是挺丰富的,但还是有些工具人的感觉。 八百里开外一枪打死鬼子,先不说这子弹为何能飞这么远还不掉下来(假设这个磁悬浮系统真的能让子弹磁悬浮),在真空行驶的列车破了个洞,里面的气压竟然不降?里面的空气应该漏完了吧?列车出了隧道竟然还能跑1000 km/h,空气阻力不存在么?推理桥段智商基本为0,这么大的餐车消失了柯南竟然还需要元太提示才能发现,实属不正常。而且“美国人看不懂日本假名”,美国人总看得懂罗马字吧? 82 | 83 | {% include figure.html src="b15092b8911be6f7ad4ebcf998740fe0.jpg" alt="名侦探柯南 绯色的子弹" width="400" height="225" %} 84 | 85 | ### 宝可梦 皮卡丘和可可的冒险 86 | 和奇奇、茂茂三人一起看的。中配的效果还可以,至少没让我觉得突兀、不适应,只不过中配版没字幕,有几处背景音乐音量有些高没听清在说什么。剧情上来说,这部作品除了传统的“宝可梦与人的关系”之外,还描绘了萨戮德“阿爸”和可可的亲情,角色塑造上是比较成功的,最终结局也很圆满。除此之外,贪心栗鼠、古月鸟、列阵兵等等第八世代宝可梦的登场活跃了气氛,也让这些宝可梦更加活灵活现,而不是沦为填补图鉴的道具。 87 | 88 | {% include figure.html src="467ebd1bb510e1f59b3ac1a219fd584b.jpg" alt="宝可梦 皮卡丘和可可的冒险" width="400" height="225" %} 89 | 90 | ## 影视 91 | ### 半泽直树 92 | 打工人的战争。剧情看着很爽,又不失真实性,结局出乎意料,却又在情理之中。只不过为了成大事有时还需要人脉,这恰恰是普通人难以获得的。 93 | 94 | ### 唐人街探案3 95 | 和高中同学六人一起看的。作为喜剧片来说还算可以,作为推理片来说完全不合格。除了有“γ-羟基丁酸”读成了“Y-羟基丁酸”这种低级错误,剧情的逻辑也非常混乱,日本警方就像是一群废物,连现场勘查都做不好。顶多图个乐呵。 96 | 97 | ### 民王 98 | 日语课老师推荐的电视剧。看题材还以为是严肃的政治斗争剧,但看完第一集就发现实际上是政治题材的喜剧。严肃的政治家和不成器的儿子,两者形成了鲜明对比,再加上不时出现的音效,让剧情增加了很多乐趣。 99 | 100 | ### 重版出来! 101 | 让人很有活力的打工剧。无论是出版社的编辑还是漫画家,剧中出现的每个人都不是坏人,每个人都在用自己的方式实现梦想。主角小熊的乐观感染了身边的人,让幽灵般神出鬼没的销售部员小泉变得开朗,也帮助了两位对前途感到迷茫的新人找到了方向。尽管剧中也有无法实现梦想的遗憾,但总体来说每个人都找到了自己未来的方向。生活可能不像日剧中的那么美好,但还是要对未来充满信心。 102 | 103 | ### 凪的新生活 104 | 和《重版出来!》同样是黑木华主演。凪和慎二,实际上是同一种人的两个极端。两个人都在因“读懂空气”(看懂气氛)而喘不过气,只不过凪选择了低声下气,慎二选择了自嘲。作为结果,凪每天都在怀疑自己的选择,而慎二的自嘲则伤害到了自己最喜欢的人。电视剧的最后,两个人都有了改变,不再苦恼于读空气。尽管结局并不如我所愿,但或许对于凪来说这才是最好的选择。 105 | 106 | ### 扬名立万 107 | 剧情多次反转,有几次我觉得“我已经看透了编剧的想法”,但直到最后一刻真相大白我才感叹一句“原来是这样”。总体来说没有太大的疏漏,作为一部悬疑剧来说算是很不错了。对于故事的结局,主角团队的下场也在情理之中。在那个纷乱的年代,权势就是一切。“不求扬名立万,只愿无愧于心”,大概是最正直的选择了吧。 108 | 109 | ### 雄狮少年 110 | 我看过的为数不多的中国动画。没有神话背景,没有大IP加持,题材是很普通的舞狮,但却表现了平凡少年的不平凡的成长历程。生活很艰难,梦想很美好,能在艰难的生活中实现梦想固然很美好,但这种机会实在难得。影片的结局虽然不是最好的结局,但却是最真实的结局。 -------------------------------------------------------------------------------- /_posts/2023-05-28-DIY-My-Computer.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2023-05-28 11:16 3 | head_image: 04ec27f2e9a8f10d63e8a24434befcb2.jpg 4 | head_image_height: 800 5 | head_image_width: 1200 6 | info: 记录一下心路历程以及踩的坑。 7 | last_modified_at: 2025-06-10 20:06 8 | tags: Windows 杂记 9 | title: 我的第一台组装主机 10 | --- 11 | 4月份的时候,我突然萌生了一股自己配一台电脑的想法。早在2021年9月我就在办公室买了一台4K分辨率的显示器,但是我至今都没有什么设备能在4K分辨率下稳定地运行游戏。本来这台显示器是给Nintendo Switch升级款准备的,但是等了两年也没等来。我自己的笔记本电脑是全能本,显卡是RTX 3050 (Laptop),性能不足以支持4K游戏,甚至跑2K都有些费劲。我又考虑买台Xbox Series X或者PlayStation 5,但是我喜欢的日系游戏在XSX上比较少,PS5的游戏又比较贵。综合了一下,最终我还是决定自己组装一台电脑。 12 | 13 | ## 准备 14 | 虽然我之前重装过好多次系统,也给自己的笔记本和家里的台式机加装过配件,还帮办公室的兄弟组装过他买的电脑,但是完全从头开始配一台主机还是头一次。当然,现在的电脑配件都是标准化的,而且有很多防呆设计,基本上只要能插上就能用。但是为了避免出现不必要的麻烦,我还是决定先学习一下。 15 | 16 | 我主要参考了[硬件茶谈](https://space.bilibili.com/14871346)的[装机教程视频](https://www.bilibili.com/video/BV1BG4y137mG/),这个视频确实做的非常详细,用了三维动画的形式,把所有配件的安装过程都介绍了,甚至还贴心地介绍了怎么开机、怎么连显示器。他们其他的一些科普也很有意思,比如如何根据CPU和显卡选择电源、散片CPU和盒装CPU的区别等等,能学到不少东西。 17 | 18 | 此外,我还从[Epic游戏商城](https://store.epicgames.com/zh-CN/)买了[《装机模拟器2》](https://store.epicgames.com/zh-CN/p/pc-building-simulator-2),这个游戏的玩法就是模拟组装电脑,我在游戏里面练习了很久,也学到了不少东西。比如主板和CPU不能随便搭配,必须要有同样的接口;比如散热器不能直接怼到CPU上,要加硅脂,不然CPU会过热(游戏里会直接蓝屏)等等。这游戏甚至还能模拟3DMark跑分,算是非常逼真了。 19 | 20 | ## 配置 21 | 22 | | 配件 | 型号 | 价格 | 来源 | 23 | | --- | --- | --- | --- | 24 | | CPU | 英特尔 i5-13400 | 1137.8 | 拼多多 | 25 | | 主板 | 铭瑄 MS-终结者 B760M D4 | 646.8 | 拼多多 | 26 | | 显卡 | 铭瑄 RTX3060Ti 8GB GDDR6X 瑷珈 | 2699 | 淘宝 | 27 | | 内存 | 光威 16GB DDR4 3200 ×2 | 335.47 | 拼多多 | 28 | | 硬盘 | 金士顿 KC3000 1TB | 403.8 | 拼多多 | 29 | | 硬盘 | 希捷 银河 Exos 7E8 4TB | 253.8 | 拼多多 | 30 | | 散热 | 利民 AX120R SE 青春版 | 60.35 | 拼多多 | 31 | | 电源 | 鑫谷 AN750W | 215.8 | 拼多多 | 32 | | 无线网卡 | 英特尔 AX211 | 82 | 淘宝 | 33 | | 光驱 | 惠普 拆机光驱 | 26 | 淘宝 | 34 | | 机箱 | 先马 黑洞机箱 | 248.7 | 京东 | 35 | | 合计 | - | 6109.52 | - | 36 | {: data-caption="2023年5月的配置单" } 37 | 38 | 这个配置单我参考了许多其他人的配置单,也参考了我的钱包,最终决定了6000元人民币左右的这套配置。显示器、键盘、鼠标我早就买了,而且我也不玩FPS,不需要太高的配置,有手柄就行。 39 | 40 | ### CPU 41 | 6000元的配置单,CPU的选择范围不太多。首先排除AMD,因为AMD的命名我看不懂,而且似乎还有很多兼容性问题。Intel的CPU当然选择酷睿(Core)系列,13代相比12代虽然提升不多但也有提升,买新不买旧选了13代。13600以上价格太高,最后选了13400,也够用了。很多配置单会推荐带“F”的版本,也就是无核显版,价格会便宜一点。但我查了一下价格,13400和13400F散片价格差别在50元以内,而多个核显还能多个功能,就算是当个OBS录屏的编码器也有好处,最终还是选择了带核显的Intel i5-13400。 42 | 43 | ### 主板 44 | 定了CPU,主板基本也就定了。13400的接口是LGA1700,对应主板芯片组有H610、B660、B760。H610首先排除,太寒碜了。B660和B760差别不大,就是PCIe通道数量有区别。考虑到我之后可能会有加装内存条的需求,首选有4个内存插槽的主板,综合了价格和评价,最终选择了铭瑄 MS-终结者 B760M。虽然B660也不是不行,但似乎铭瑄的B660主板停产了,也算是买新不买旧了。 45 | 46 | ### 显卡 47 | 6000的预算,一半分给显卡。显卡的选择范围也不多,首先排除Intel,刚出的显卡兼容性不敢放心。其次排除AMD,因为很多科学计算相关的软件都是基于Nvidia显卡的CUDA,AMD太受限制。比较看好的显卡是Nvidia的3060Ti G6X版本,这个版本是最近才新出的,不会有矿卡,而且性价比比较高。作为一个第一次买显卡的人,我是不太敢接触矿卡和二手卡的,所以全新的最好。综合考虑了性能、售后服务、颜值等,我先选定了铭瑄 RTX3060Ti 8GB GDDR6X 瑷珈这个版本。 48 | 49 | 不过在我考虑配置单的时候,出现了4060Ti即将发布的传言,于是我买显卡的时间就拖了拖。等到4060Ti发布了,我发现价格比3060Ti G6X版本高了不少,但性能提升不值得这个价格。看了看评测,4060Ti比3060Ti G6X游戏性能提高不到10%,虽然功耗是降低了,但是省下来的电费并不多。AV1编码功能我暂时用不上,HEVC编码足够我用了。DLSS3我也用不上,我游戏库里的游戏很多连DLSS2都不支持,更别提DLSS3了。另外,4060Ti发布之后3060Ti G6X价格下降了不少,甚至有些店家都缺货了,于是我赶紧下单了3060Ti G6X。 50 | 51 | ### 内存 52 | 内存没啥好纠结的,直接上16GB×2。DDR5比DDR4贵一些,最后还是选了DDR4的。内存频率根据主板的描述选了3200MHz,但是我把电脑组装完之后发现有人说3600MHz的也能用,开XMP就行,不过内存频率提升对性能提升好像帮助也不大,无所谓了。 53 | 54 | ### 硬盘 55 | 硬盘肯定是固态+机械,固态硬盘装系统+放游戏,机械硬盘存视频和其他大文件。固态硬盘的选择方面,虽然最近国产固态硬盘价格很诱人,但是似乎有掉盘的风险,考虑到我电脑要存一些科研的数据,还是保险一点比较好,最终还是选了金士顿的固态。机械硬盘要求就没这么多了,本来还想买个二手的,但是发现一手的非国行硬盘价格和二手差不多,折合下来1TB还不到100块,这价格要啥自行车,直接买新的了。 56 | 57 | ### 散热 58 | 散热没啥好说的,13400发热量不大,百元以内的散热器都够用了。 59 | 60 | ### 电源 61 | 根据硬件茶谈的科普,加上谷歌搜出来的评测,13400+3060Ti G6X预备个650W的电源比较保险。本来想买个“大水牛”品牌的,但是看了一圈评测决定还是买个好点的厂商。最终选了鑫谷的白牌750W,品牌有保证,供电接口也足够多,虽然功耗可能大一点,不过也还能接受。 62 | 63 | ### 无线网卡 64 | 其实主板是有自带无线网卡的版本的,但是似乎AX211网卡更好一些,于是我就单独买了。但是买回来之后才想起来,我这办公室的路由器不支持Wi-Fi 6E,还不如主板自带网卡,免去了安装的麻烦。 65 | 66 | ### 光驱 67 | 这年头很少有人用光驱了,但有些共用仪器只能用光盘拷数据。虽然移动光驱也能用,但是不如直接买个内置的方便,于是就买了个光驱。 68 | 69 | ### 机箱 70 | 因为要放办公室,机箱还是买个中规中矩的办公机箱比较好。加上需要有光驱位,所以选了个带光驱位的机箱。综合考虑了以上的因素,最后还是选了先马的黑洞机箱。另外只有机箱我是在京东买的,考虑到这么大一个机箱如果要售后的话运费肯定不便宜,还是京东自营能上门寄件比较靠谱。 71 | 72 | ## 踩坑 73 | 配置单有了,就只差买和装了。本来我想攒到618再买,看看拼多多会不会给大额优惠券。但是我5月中旬看的时候优惠券已经有变少的趋势了,于是我就凑了一天赶紧下单了,最终一合计靠拼多多优惠券省了230块。而且拼多多最高额度的优惠券是满999减99,为了最大化利用,我把CPU和主板分开买了。显卡则是在4060Ti正式发售几天后买的,因为4060Ti不实惠,3060Ti G6X马上又要缺货了,最后还是买了3060Ti G6X。所有配件加起来6109.52元,还不错。 74 | 75 | {% include figure.html src="54082096903c2d9edab489a9a6bb59bb.jpg" alt="鲁大师硬件配置" width="490" height="300" %} 76 | 77 | {% include figure.html src="04ec27f2e9a8f10d63e8a24434befcb2.jpg" alt="机箱内的构造" width="600" height="400" %} 78 | 79 | {% include figure.html src="58c0de4fa25b9325cc09d554e19a25f8.jpg" alt="显卡还挺新,希望不会翻车" width="242.5" height="154.5" %} 80 | 81 | 拼装过程就没啥好说的了,完全是按照装机教程和游戏里的操作经验来的。只不过因为是第一次装机,还是遇到了几个坑。 82 | 83 | ### 主板的固定螺丝 84 | 这一点是最坑的,因为我看了硬件茶谈的教程里说固定主板的螺丝应该是六角的,就把几个六角螺丝安上去了。结果这几个六角螺丝很紧,装上去就拆不下来了,我拿了一把电动螺丝刀卸螺丝,直接把螺丝柱一块卸下来了。后来我才发现这个六角螺丝是固定PCI挡板用的,但是已经拧不下来了,好在还勉强能用。估计是不同机箱的螺丝型号不一样,不能一概而论。 85 | 86 | ### 机箱的排线 87 | 我选的这个机箱自带一个读卡器,但是读卡器是要走USB接口的,加上机箱面板也有一个USB接口,一共2个USB接口。而主板上只有一个USB接口,我又没有一分二线,就只能把读卡器接在了主板上,机箱面板的USB接口就没法用了。不过这个问题不大,还有两个USB 3.0接口能用。 88 | 89 | ### 双通道内存条 90 | 一开始我只买了一条16GB的内存,打算等今年双十一内存价格下降之后再组双通道。但是看了硬件茶谈的科普,双通道内存条最好是套条,因为套条是厂商调教过的,否则可能出现不稳定的情况。为了避免过几个月再买导致内存条批次相差较大,我又在下单了显卡之后下单了一个内存条。结果上机的时候差点翻车,插上新内存条之后主板的纠错灯常亮,连BIOS都进不去。最后我才想到可能是开了XMP的原因,我又把最初买的内存条插上去关了XMP,组成双通道才顺利开机,之后我又打开了XMP,目前一切正常。 91 | 92 | **2024-03-09更新**:在买了第二条内存条之后我经常会遇到蓝屏的情况,有时候一天能蓝屏好多次。我以为是两条内存不同批次开XMP不稳定的原因,于是之后又买了3600MHz的套条,一切正常了。当我时隔半年开始组装二号机的时候才发现,我买的第二条内存条有问题,即便是单独插在主板上不开XMP也会蓝屏,而且防伪码在官网上查不到,离了个大谱。于是我选择向商家投诉,对方同意直接换新,目前一切正常。 93 | 94 | ### 主板屏蔽核显 95 | 插了独显之后,主板默认把核显屏蔽了,而且不是屏蔽输出接口,是直接禁用了核显,导致我无论是跑分还是压制视频都无法调用核显。不过这个问题很好解决,改一下BIOS设置即可。 96 | 97 | **2023-06-02更新**:没想到有核显的情况下Premiere导出视频会调用独显“加速”,但这个所谓的“加速”实际上是减速,核显占用率100%,独显占用率不到20%。禁用核显之后Premiere导出视频的耗时从大约6分钟降低到了大约2分钟。 98 | 99 | ### 显卡支架 100 | 我以前没用过显卡支架,装完之后发现风扇嗡嗡地响,后来发现是显卡支架碰到风扇扇叶了。最后调整了一下显卡支架的位置,解决了。 101 | 102 | ## 效果 103 | 烤机啥的我也不太懂,就简单跑了个3DMark和鲁大师,分数还可以。 104 | 105 | {% include figure.html src="68867b0160f565c3630674427bd16fa9.jpg" alt="3DMark跑分结果" width="612" height="374" %} 106 | 107 | {% include figure.html src="6ebd3631d1023e31bd92f2e2428788e6.jpg" alt="鲁大师跑分结果" width="490" height="300" %} 108 | 109 | 用AIDA64监测了一下温度,CPU在满载的时候温度在70度左右,显卡在满载的时候温度在90度左右,都还可以接受。CPU最大功率大概80W,显卡最大功率大概260W。 110 | 111 | 虽说3060Ti评测基本都说这是张2K卡,但是我也不怎么喜欢那种吃配置的3A大作,日系游戏在4K分辨率下也不是驾驭不了。我用最近玩的游戏测了一下帧率,《女神异闻录5 皇家版》4K最高画质能跑满60FPS,《莱莎的炼金工房3》4K中等画质能跑在58FPS左右,也还不错了。 112 | 113 | ## 升级 114 | 115 | **2025-06-10更新**:两年过去了,最近有了点额外收入,把3060Ti G6X升级成了5070,CPU之前就已经从13400升级到了14600K。跑分看着还行。 116 | 117 | {% include figure.html src="https://i0.hdslb.com/bfs/new_dyn/1816c7e3f2d003eb51f84d3db0a9411816114399.jpg" alt="5070的包装" width="359.5" height="270" %} 118 | 119 | {% include figure.html src="b9a93c2d46be1d9c78eff4268b1b4909.webp" alt="5070的3DMark跑分结果" width="640" height="360" %} 120 | -------------------------------------------------------------------------------- /_posts/2025-04-25-Super-Princess-Peach-Chinese-Localization-4.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: 2025-04-25 16:21 3 | head_image: https://i0.hdslb.com/bfs/article/2869915f51689578432370f09aa19d8716114399.jpg 4 | head_image_height: 1080 5 | head_image_width: 1920 6 | info: 压缩数据大小。 7 | last_modified_at: 2025-04-25 23:10 8 | tags: DS 任天堂 汉化笔记 9 | title: 《超级碧姬公主》汉化笔记(四):数据压缩 10 | --- 11 | « [《超级碧姬公主》汉化笔记(一):文本和字库分析]({% link _posts/2025-04-11-Super-Princess-Peach-Chinese-Localization.md %}) 12 | {: .text-left } 13 | 14 | « [《超级碧姬公主》汉化笔记(二):字库扩容]({% link _posts/2025-04-13-Super-Princess-Peach-Chinese-Localization-2.md %}) 15 | {: .text-left } 16 | 17 | « [《超级碧姬公主》汉化笔记(三):图片数据导出]({% link _posts/2025-04-15-Super-Princess-Peach-Chinese-Localization-3.md %}) 18 | {: .text-left } 19 | 20 | (封面图由ChatGPT生成) 21 | 22 | [上回]({% link _posts/2025-04-15-Super-Princess-Peach-Chinese-Localization-3.md %})书说到,图片分析有了初步进展。接下来就需要尝试一下能否成功修改图片数据了。 23 | 24 | ## 导入图片数据 25 | 26 | 既然知道了如何导出图片,那么反过来操作不就可以导入图片了吗?理论上来说应该是这样的,然而——由于图片相关的数据被保存在了可执行文件中,这意味着我们修改后的文件大小最好和原始文件大小一致或者更小,这样就不会覆盖掉后面的数据。虽然也可以通过移动数据到新的位置来实现,但这又涉及到地址的修改,比较麻烦。 27 | 28 | 上篇笔记里提到了,原始数据经过了LZ10压缩,因此在修改了图片之后也要把新的数据压缩回去。ndspy库里提供了LZ10压缩的实现,因此我们可以直接使用它来压缩数据——本以为是这样的,但是ndspy库的LZ10压缩实现得到的压缩率太低,从ROM提取出来的压缩数据经过解压后再压缩得到的数据大小比原来的数据还要大很多,限制了我们的使用。因此,需要寻找其他的LZ10压缩实现。 29 | 30 | 既然如此,接下来就来研究研究LZ10算法究竟是个什么东西。 31 | 32 | ## LZ10算法及其解压实现 33 | 34 | LZ10算法是NDS主机上最常用的一种压缩算法,属于LZ77算法的变种。它的基本思路是通过查找数据中重复的部分来减少数据量。也即,如果一段字节序列在前面曾经出现过,并且字节序列的长度至少为3,那么可以用2个字节来表示重复序列的长度和偏移量,从而减少数据的大小。之所以称之为“LZ10”压缩,是因为压缩后数据的第一个字节必定为`0x10`。 35 | 36 | LZ10算法的大致逻辑如下:压缩后的数据可分为多个组,每组数据第一个字节的8位依次代表了8个数据块的类型。若为0,则将该数据块的1个字节直接复制到输出数据中。若为1,则将该数据块的2个字节作为指令,低12位表示偏移量,高4位表示长度。长度的计算方式为`length = (uint >> 12) + 3`,偏移量的计算方式为`offset = uint & 0xFFF`。接下来就可以根据偏移量从输出数据中复制出指定长度的数据了。 37 | 38 | {% include figure.html src="ca14858147c451b138aa671f92fa62a4.webp" alt="LZ10压缩数据示意图" width="600" height="298.5" %} 39 | 40 | 在上篇笔记中我给出了解压算法的伪代码,这里给出Python的实现(引自[ndspy的实现](https://github.com/RoadrunnerWMC/ndspy/blob/master/ndspy/lz10.py),基于GPLv3,略有修改): 41 | 42 | ``` python 43 | import struct 44 | 45 | 46 | def decompress(data: bytes) -> bytes: 47 | assert data[0] == 0x10, TypeError("This isn't a LZ10-compressed file.") 48 | 49 | decompressed_size = struct.unpack_from("> 8 50 | 51 | out = bytearray(decompressed_size) 52 | input_pos = 4 53 | output_pos = 0 54 | 55 | while decompressed_size > 0: 56 | byte = data[input_pos] 57 | input_pos += 1 58 | 59 | for bit in range(8): 60 | if byte & 0x80: 61 | (temp,) = struct.unpack_from(">H", data, input_pos) 62 | input_pos += 2 63 | 64 | length = (temp >> 12) + 3 65 | offset = temp & 0xFFF 66 | copy_from = output_pos - offset - 1 67 | 68 | for _ in range(length): 69 | out[output_pos] = out[copy_from] 70 | output_pos += 1 71 | copy_from += 1 72 | decompressed_size -= 1 73 | 74 | if decompressed_size == 0: 75 | return bytes(out) 76 | 77 | else: 78 | out[output_pos] = data[input_pos] 79 | output_pos += 1 80 | input_pos += 1 81 | decompressed_size -= 1 82 | 83 | if decompressed_size == 0: 84 | return bytes(out) 85 | 86 | byte <<= 1 87 | 88 | return bytes(out) 89 | ``` 90 | 91 | ## 压缩算法的编写与改进 92 | 93 | 解压算法非常简单,难度在于压缩算法。维基百科上有[关于LZ77算法的介绍](https://zh.wikipedia.org/wiki/LZ77%E4%B8%8ELZ78),其核心思想就是在当前位置下向前查找重复序列,并记录下重复序列的长度和偏移量。对于LZ10算法来说,重复序列的长度范围为3-18,偏移量范围为1-4096,其编码方式大致如下图所示: 94 | 95 | {% include figure.html src="43504f3a1df643c541835421e23cc656.webp" alt="LZ10压缩算法查找过程" width="600" height="445" %} 96 | 97 | 前面提到了ndspy给出的压缩算法压缩率太低,那么就来分析一下它是怎么实现的。`ndspy.lz10.compress`调用了`_lzCommon.compress`函数来实现压缩,而在`_lzCommon.compress`函数的核心逻辑中,最重要的是查找重复序列的函数`compressionSearch`。这个函数的实现逻辑如下: 98 | 99 | ``` python 100 | maxMatchDiff = 0x1000 101 | maxMatchLen = 18 102 | searchReverse = False 103 | 104 | def compressionSearch(pos): 105 | start = max(0, pos - maxMatchDiff) 106 | 107 | lower = 0 108 | upper = min(maxMatchLen, len(data) - pos) 109 | 110 | recordMatchPos = recordMatchLen = 0 111 | while lower <= upper: 112 | matchLen = (lower + upper) // 2 113 | match = data[pos : pos + matchLen] 114 | if searchReverse: 115 | matchPos = data.rfind(match, start, pos) 116 | else: 117 | matchPos = data.find(match, start, pos) 118 | 119 | if matchPos == -1: 120 | upper = matchLen - 1 121 | else: 122 | if matchLen > recordMatchLen: 123 | recordMatchPos, recordMatchLen = matchPos, matchLen 124 | lower = matchLen + 1 125 | 126 | return recordMatchPos, recordMatchLen 127 | ``` 128 | 129 | 可以看出,这个函数的核心逻辑是二分查找,查找以当前位置为起始的在前面出现过的最长序列。其中,为了保证查找方向是向前的(避免查找到当前位置,因为从当前位置复制数据没有意义),代码中有一行:`matchPos = data.find(match, start, pos)`。但是仔细思考可以发现,这样会错过一种特殊情况,即重复序列和自身重叠的情况。例如: 130 | 131 | {% include figure.html src="60058bdc3eecc7b900a1fba4ae0d4b53.webp" alt="重复序列和自身重叠的特殊情况" width="600" height="269.5" %} 132 | 133 | 维基百科中也提到了这种情况: 134 | 135 | > 许多关于LZ77算法的文档都将长度距离对描述为从滑动窗“复制”数据的命令:“在缓冲区中回退距离个字符然后从那点开始复制长度个字符。”尽管对于习惯于指令式编程的人们来说很直观,但是它仍然使得人们很难理解LZ77编码的一个特点:也就是说,长度距离对中的长度超过距离这样一种情况不仅是可接受的而且还是经常出现的情况。作为一个复制命令,就会让人费解:“回退一个字符然后从那点开始复制七个字符。”但是如果缓冲区中只有一个字符的话那该如何复制七个字符呢?然而将长度距离对看作对于特性的描述就可以避免这种混淆:后面的七个字符与前面的七个完全相同。**这就意味着每个字符都可以通过在缓冲区找到确定下来:即使在当前数据对解码开始的时候所要查找的字符并不在缓冲区中也可以。**通过这个定义,这样的数据对将是距离字符序列的多次重复,也就是说LZ77成了一个灵活容易的行程长度编码形式。 136 | > 137 | > (维基百科:LZ77与LZ78,CC BY-SA 4.0) 138 | 139 | 例如,测试一段特殊字节序列:`00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00`,采用ndspy的压缩算法得到的压缩数据为:`10 13 00 00 1C 00 00 00 00 02 30 05 40 0B`,但实际上还可以被简化为`10 13 00 00 40 00 F0 00`。可以简单地测试一下: 140 | 141 | ``` python 142 | import ndspy.lz10 143 | 144 | uncompressed = bytes.fromhex("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00") 145 | compressed_1 = bytes.fromhex("10 13 00 00 1C 00 00 00 00 02 30 05 40 0B") 146 | compressed_2 = bytes.fromhex("10 13 00 00 40 00 F0 00") 147 | 148 | assert ndspy.lz10.decompress(compressed_1) == uncompressed 149 | assert ndspy.lz10.decompress(compressed_2) == uncompressed 150 | ``` 151 | 152 | 那么该如何修改呢?其实很简单,把`matchPos = data.find(match, start, pos)`改成`matchPos = data.find(match, start, pos + matchLen - 1)`即可,这样就能在查找重复序列时考虑到重叠的情况了。 153 | 154 | ## 结尾 155 | 156 | 在NDS游戏中,除了最常见的LZ10压缩外,还有其他类型的LZ压缩算法,例如[《Another Code 两种记忆》]({% link _posts/2023-12-27-Another-Code-Chinese-Localization.md %})使用了文件头为“12 3D DA 01”的压缩方式。这些压缩方法核心原理都是类似的,只是表示重复序列长度和偏移量的方法可能会有所差异。在NDS后期的一些游戏中,`arm9.bin`也被压缩了,这采用的是一种被称为BLZ压缩的算法,B可能代表Backward,表示向后查找重复序列。ndspy也有对BLZ压缩的实现,即`ndspy.codeCompression.compress()`,感兴趣的话可以去看看。 157 | 158 | 到这里,压缩率不够的问题终于被解决了。然而,对于nce文件的研究还没有进展,这就留待以后再深入分析了。 159 | --------------------------------------------------------------------------------