最近迷上了TRPG(Tabletop Role-playing game,桌上角色扮演游戏),即俗称的“跑团”。玩家在主持人的引导下,扮演自己的游戏角色进行冒险。在结束之后,会有想要将这个过程记录下来的欲望,从而有了各种各样的“跑团replay视频”。
制作跑团replay视频比较复杂,但回声工坊 这一高效工具的出现,让这个过程变得非常简单,只需要找好媒体素材(角色立绘、背景图片、BGM、音效等)以及处理一下跑团Log(即跑团游戏记录)就可以很快输出一集视频。
为了更加方便跑团replay视频的制作,我编写了一个vscode插件——TRPG Replay Generator Log
——来方便跑团Log的处理。
本文对编写这个插件的过程做一个记录和总结。
参考链接
目标 回声工坊这个软件所做的工作其实是根据输入的特定格式的Log文件、媒体定义文件、角色配置文件,将准备好的各种素材按照一定的规则拼接在一起。
回声工坊的Log文件的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 # 综合演示 <set:formula>:sincurve <set:am_method_default>:<pass_up_black=20> <set:tx_method_default>:<w2w=1> <set:bb_method_default>:<replace=0> <set:BGM>:BGM1 <set:speech_speed>:500 <background><replace=30>:bg1 [张安翔]:^本视频是DanDDXuanX 编写的#TRPG-Replay-Generator的基本演示工程。{SE1;*3.5} [KP]:项目链接:#https://github.com/DanDDXuanX/TRPG-Replay-Generator{SE1;5} <set:speech_speed>:300 <hitpoint>:(张安翔,10,10,9) [张安翔]:^本工具基于python3 和 pygame2.0,在windows10系统上开发。#演示使用的媒体素材来自网络,侵删。{SE1;5} [张安翔]:那么,演示开始。{SE1;5} <dice>:(测试姓名1 力量,100,75,3),(测试姓名2 sancheck,100,60,25),(测试姓名3 图书馆,100,75,85),(测试姓名4 侦察,100,60,100) <hitpoint>:(张安翔,10,9,5) <dice>:(测试姓名1 力量,100,75,3),(测试姓名2 sancheck,100,60,25),(测试姓名3 图书馆,100,75,85),(测试姓名4 侦察,100,60,100) <dice>:(1d8,8,NA,4),(1d4,4,NA,4) <hitpoint>:(短,4,4,1) <hitpoint>:(用来测试的一极长文本,4,1,4) <background><cross=60>:bg2 <set:speech_speed>:250 <set:am_method_default>:<replace=0> <set:tx_method_default>:<all=0> <set:am_dur_default>:10 <set:tx_dur_default>:7 <set:BGM>:stop [张安翔]:在对话行里建立最基本的发言小节,播放基本音效。{SE1;5} [KP]<black>:使用切换效果修饰符,指定切换模式为渐隐。{SE1;5} <hitpoint>:(张安翔,10,5,7) [张安翔]<black=30>:在切换效果修饰符中,指定切换时间为30。{SE1;5} [KP]<black>:使用文本效果修饰符,指定文字显示模式为逐字显示。<w2w>{SE1;5} [张安翔]<black>:在文本效果修饰符中,指定单位时间为2。<w2w=2>{SE1;5} <hitpoint>:(张安翔,10,7,4) [张安翔,KP.double]<black>:在角色框里指定多位角色,实现多人同框。<w2w=2>{SE1;5} [KP.double,张安翔]<black>:置于首位的角色为主要发言人,其余角色设置为半透明。<w2w=2>{SE1;5} <set:BGM>:BGM1 [旁白]<black>:没有立绘的文本框同样以角色的形式在角色表里定义,可以作为旁白或者骰子使用。<w2w=2> <hitpoint>:(张安翔,10,4,9) <set:BGM>:stop <background><black=60>:bg1 [张安翔(60),KP.double]<replace=0>:调整角色的透明度参数,手动设置立绘透明度。<w2w=5>{SE1;5} [张安翔.scared,KP.double]:指明角色的subtype,展示差分立绘。<w2w=5>{SE1;5} [张安翔,KP.double]:在发言文本中以井号作为换行符;#设置手动换行模式;#并逐行显示内容。<l2l=5>{SE1;5} [旁白]<black>:———————演示结束—————— <hitpoint>:(张安翔,10,9,0)
回声工坊的作者用的是Sublime
,所以他只写了适用于Sublime
的语法高亮文件,用vscode
编辑跑团Log的我就没法享受到语法高亮了。
于是我打算照着作者发在交流群里的Sublime语法高亮文件来写一个vscode语法高亮文件之类的东西,不过后来发现还是得开发一个语言扩展才行。
找到了这样一篇官网的文档:Visual Studio Code Syntax Highlight Guide-官网文档 ,接着开始开发vscode扩展。
搭建环境 安装脚手架工具 按照Your First Extension 这篇文章中说的那样,首先安装Node.js 和Git ,接着用下面的命令安装Yeoman和VS Code Extension Generator:
1 npm install -g yo generator-code
Yeoman是个脚手架工具,可以用简单的指令快速搭建好开发环境。安装完毕之后,使用如下指令唤出一个命令行菜单,用上下箭头按键来选择要搭建的环境。
选择要搭建的扩展 借用官网文档中的图片:
输入一些基本信息
从回声工坊的作者写的sublime
语法高亮文件RepGenLog.sublime-syntax
中可以知道他将回声工坊的log文件的扩展名定义为“.rgl”,也就是Replay Generator Log
的首字母缩写(一开始我还记错成“.rpl”,以为是“replay”的缩写),所以这个语言扩展的名字就定为了“TRPG Replay Generator Log”,语言名称也定为“rgl”
因为官网的文档已经说的很详细了,这部分就不细说了,不想单纯复制粘贴。
package.json文件 生成好的文件当中,比较重要的就是这个package.json
文件了,因为这个扩展插件的基本信息都在这个里面,主要的文件的路径也是在这里配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 { "name" : "trpg-replay-generator-log" , "displayName" : "TRPG Replay Generator Log" , "description" : "Syntax highlighting and code snippets for TRPG-Replay-Generator-Log language" , "version" : "0.0.1" , "engines" : { "vscode" : "^1.67.0" }, "publisher" : "yxChangingSelf" , "categories" : [ "Programming Languages" ,"Themes" ,"Snippets" ], "contributes" : { "languages" : [{ "id" : "rgl" , "aliases" : ["rgl" , "rgl" ], "extensions" : [".rgl" ], "configuration" : "./language-configuration.json" }] ,"grammars" : [{ "language" : "rgl" , "scopeName" : "source.rgl" , "path" : "./syntaxes/rgl.tmLanguage.json" }] } }
这里注意其中的contributes
,这里配置了languages
和grammars
两个属性。
前者配置了语言相关的内容,包括id、与该语言关联的文件扩展名以及语言配置文件的路径”./language-configuration.json”。
后者配置了语法相关的内容,包括展示给人看的语言名称、根scope以及语法定义文件的路径”./syntaxes/rgl.tmLanguage.json”。
因为目前只需要语法高亮,可以先看后面这个文件。
标记化(Tokenization) 要实现语法高亮,首先需要将这个语言标记化,学过编译原理的应该知道这就是词法分析那一步,也就是将输入划分为一个个词法单元(Token),告诉计算机每一个词法单元是哪一类。(Breaking text into a list of tokens)
Each token is associated with a scope that defines the context of the token. A scope is a dot separated list of identifiers that specify the context of the current token. The +
operation in JavaScript, for example, has the scope keyword.operator.arithmetic.js
.
这里的scope
就是我们需要为token
打上的“标记”了。
简单来说,就是我们需要先将各种token
分好类,之后才方便将同类的东西染上相同的颜色。
TextMate
VS Code 使用 TextMate
语法作为语法标记引擎。为 TextMate 编辑器发明,由于开源社区创建和维护的大量语言包,它们已被许多其他编辑器和 IDE 采用。
TextMate的语法详见:TextMate language_grammars
详细的就不说了,只说用到的部分。
主要有两种形式:
1 2 3 4 { "name" : "comment.line" , "match" : "^#.+$" }
就是将name
所定义的scope
分配给match
用正则表达式匹配出对应的token
。
另一种形式是:
1 2 3 4 5 6 7 8 9 10 11 { "name" :'string.quoted.double.untitled', "begin" : "\"" , "end" : "\"" , "patterns" : [ { "name" = 'constant.character.escape.untitled', "match" = "\\." } ] }
begin
和end
定义了首尾,将其中所有的内容分配为name
定义的scope
,其中的patterns
属性是在被begin
和end
框定的范围内继续进行标记。
调试 写好之后用f5运行一个加载了该扩展的vscode窗口来检查写的是否正确,可以在ctrl+shift+p
调出来的命令面板中输入Developer: Inspect Editor Tokens and Scopes
来开启Scope inspector
这个东西,它可以显示光标所在位置的token
的scope
,方便检查
最后写好的语法高亮文件 rgl.tmLanguage.json
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 { "$schema" : "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json" , "name" : "rgl" , "patterns" : [ {"include" : "#comments" } ,{"include" : "#dialog" } ,{"include" : "#command" } ,{"include" : "#error" } ], "repository" : { "comments" :{ "patterns" : [{ "name" : "comment.line" , "match" : "^#.+$" }] }, "dialog" :{ "patterns" : [{ "name" : "entity.name.function" , "begin" : "(?=^\\[)" , "end" :"\n" , "patterns" : [{ "name" : "variable.parameter" , "match" : "^\\[([\\ \\w\\.\\;\\(\\)\\,]+)\\]" } ,{ "name" : "punctuation.colon" , "match" : "\\B:" } ,{ "name" : "keyword.operator" , "match" : "(\\^|#)" } ,{ "name" : "storage.type" , "match" : "<\\w+(\\=\\d+)?>" } ,{ "name" : "string.quoted.double" , "match" : "({.+})?$" } ] }] }, "command" :{ "patterns" : [{ "name" : "entity.name.function" , "begin" : "(?=^<(set:[^>]+|background|dice|hitpoint)>)" , "end" :"\n" , "patterns" : [{ "name" : "keyword.control" , "match" : "^<(set:[^>]+|background|dice|hitpoint)>" },{ "name" : "punctuation.colon" , "match" : "\\B:" } ,{ "name" : "constant.numeric" , "match" : "\\b(-)?\\d+$\\b" } ,{ "name" : "keyword.declaration.function" , "match" : "(linear|quadratic|quadraticR|sigmoid|right|left|sincurve)" } ,{ "name" : "storage.type" , "match" : "<\\w+(\\=\\d+)?>" } ,{ "name" : "variable.parameter" , "match" : "\\((.+?),(\\d+),([\\d]+|NA),(\\d+)\\)" } ] }] }, "error" :{ "patterns" : [{ "name" : "invalid.illegal" , "match" : "^[\\t\\ ]+$" }] } }, "scopeName" : "source.rgl" }
主题化(Theming) 标记好了所有的元素之后,就可以开始给它们染色了,也就是“使用主题或用户设置将标记映射到特定的颜色和样式”(Using themes or user settings to map the tokens to specific colors and styles)
其实没有这一步也是可以的,因为标记了这些token
之后,运行时可以看到已经染好色了,这是正在使用的vscode主题根据这些标记染的色。
不过为了和回声工坊作者的语法高亮显示效果尽量一致,我自定义了一个主题rgl theme
,调整配色。
因为不知道怎么在项目中创建主题,官网文档里面也只是说在一开始的时候用脚手架创建,我就用yo code
命令创建了一个自定义主题的插件的项目,对比两个项目的不同,接着合并两个项目。
在package.json
里面新增了themes
这一项,指定了主题定义文件的路径,最后再在自动生成的文件中修改需要修改的颜色就行了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 { "contributes" : { "languages" : [{ "id" : "rgl" , "aliases" : ["rgl" , "rgl" ], "extensions" : [".rgl" ], "configuration" : "./language-configuration.json" }] ,"grammars" : [{ "language" : "rgl" , "scopeName" : "source.rgl" , "path" : "./syntaxes/rgl.tmLanguage.json" }] ,"themes" : [ { "label" : "rgl theme" , "uiTheme" : "vs-dark" , "path" : "./themes/rgl theme-color-theme.json" } ] } }
发布 详细步骤参考:Visual Studio Code publishing extension-官网文档
简要步骤(请查看官网文档,这里仅仅是简化步骤):
安装VSCE。vsce是“Visual Studio Code Extensions”的缩写,是一个用于打包、发布和管理 VS Code 扩展的命令行工具。
在Azure DevOps中创建自己的组织 ,需要微软账号
在组织主页获取Personal access tokens
,这个token需要开放Marketplace
下的Manage
权限
创建发布者 ,需要和刚才创建组织时登录的是同一个微软账号
使用vsce login <publisher name>
命令,并用之前获取的Personal access tokens
来验证
在扩展插件的文件夹内使用vsce publish
命令发布扩展
看起来很复杂,但实际上做起来很快,没有遇到什么困难(除了纠结用什么名字之外)
前面的步骤都完成之后,以后发布新版本就只需要最后一步,即使用vsce publish
命令发布扩展,很方便。