你是否想要给自己的地图添加一个有逼格而又硬核的结尾?
那就试试这个数据包!
简单的字幕是一个如此简单的数据包,以至于不同版本之间命令的隔阂也不能让它失去作用。换句话说,它在1.14到1.18的版本,乃至未来的版本都可能通用!
简单字幕允许使用者创建、播放一个电影结尾般的滚动字幕,而不用改变终末之诗,就像下面一样。

这个数据包的原理就是利用命名盔甲架不断上升的方式,以每个盔甲架展示每一行字幕,盔甲架上升就是字幕的滚动。
由于这次是一个前置数据包,因此没有过多的操作页面。下面将详细说明这个数据包的使用方法。别担心!很简单的!
字幕文件的格式
要想生成一个字幕,首先需要定义一个字幕文件(不然你的字幕要怎么显示出来啊)。字幕文件应当被统一储存在<存档名>\datapacks\Subtitle\data\subtitle\functions\txt文件夹下,这样程序才能读取出来。每一个字幕文件都是一个.txt文本文档,而这个文件的名字则是将会生成的字幕的文字。字幕文件的编辑格式非常简单,下面就是一个样本。这个样本也被包含在了数据包中。
datapacks\Subtitle\data\subtitle\functions\txt\example.txt
#/#/本文件储存字幕的内容,程序将逐行读取该文件的内容 #/#/以#/#/开头的一行不会被转为字幕函数,也就是注释 #/#/文件的名字即为字幕的名字,所有函数都将自动生成并写入 #/#/值得注意的是,所有的字幕默认中间对齐 #/#/以####开头的一行定义了下一行文字的颜色等属性,错误的属性将被忽略。不同属性间用|分割,属性不分先后 ------------------------ ####gold 简单的字幕 ####gold Simple Subtitle ####bold 制作 Alumopper ####bold 发布于 mcbbs BiliBili ####bold|green mcbbs ID Alumopper ####bold|aqua BiliBili Alumopper ####bold -感谢使用-
文件中的属性也就是指原始JSON文本中的斜体、粗体、删除线、下划线、混乱属性。颜色属性就是16中颜色。详细查看wiki:原始JSON文本格式 – Minecraft Wiki_BWIKI_哔哩哔哩 (biligame.com)
生成程序的使用
在\datapacks\Subtitle\data\subtitle\functions\文件夹下(也就是和命令函数一个文件夹)有一个叫做Subtitle.exe的程序,这个程序承担了读取字幕文件生成字幕的工作。你可以直接双击打开这个程序,然后输入这个字幕文件的文件名。注意,不用加上文件的.txt拓展名。如果成功解析了字幕文件,就会生成一堆字幕函数。如果找不到字幕文件或者字幕文件中有错误,那么程序发出错误或者警告。
当然,程序中有一些简单的命令,分别是:
<字幕文件名> 生成字幕
*exit 退出
*help 帮助(展示所有程序内部命令)
*list 展示所有可用字幕文件
*set 设置

关于设置,目前只有一个设置可以改变,就是interval 即行间距。默认是30(也就是每隔30tick生成一个盔甲架)。使用方法输入*set查看。
游戏中调用字幕
如果你成功地生成了一段字幕,那么展示字幕用的函数将会包含在..(路径省略)/functions/subtitles/<字幕名>/文件夹下,一共包含start、timer、end三个函数。调用start函数会让调用者进入观看字幕的状态,也就是说,一人一字幕,同时也要注意在调用时指明观看字幕的实体。timer就是生成字幕用的。end将会停止播放字幕。字幕播放完毕会自动调用end函数,你也可以手动调用打断字幕的播放。
例如,执行/function subtitle:subtitles/example/start就能显示example字幕。
在播放字幕时,玩家会被锁定视角以及位置。
下载
最后更新于:2021.8.5
b站使用介绍以及演示视频戳这里~:
教你在mc中做出电影般的结尾!地图瞬间高级了!
源码
Program.cs
using System;
using System.Collections;
using System.IO;
using System.Text;
namespace Subtitle
{
class Program
{
static int interval = 10;
static void Main(string[] args)
{
Console.WriteLine("字幕生成器 by Alumopper");
Console.WriteLine("注意,请将字幕文件放到functions下的txt文件夹中,将本程序直接放到functions文件夹下,否则会读取失败");
bool b = true;
while (b)
{
Console.Write(">>>");
string s = Console.ReadLine();
//命令使用
if (s.StartsWith("*"))
{
if (s.StartsWith("*set"))
{
s = s.Substring(4);
string[] arg = s.Split(' ');
if (arg.Length == 1)
{
//设置帮助
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("用法:*set <设置项> [参数]");
Console.WriteLine("可用的<设置项>有:\ninterval\t\t行间距");
Console.WriteLine("参数若不设置,则为默认值");
Console.ResetColor();
}
else if (arg.Length == 3)
{
//读取参数
switch (arg[1])
{
case "interval":
{
try
{
interval = int.Parse(arg[2]);
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("已将设置interval设置为{0}", interval);
Console.ResetColor();
}
catch (Exception e)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("[错误]" + e.Message);
Console.ResetColor();
}
break;
}
default:
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("[错误]未知的设置项" + arg[1]);
Console.ResetColor();
break;
}
}
}
}
else
{
switch (s)
{
case "*exit":
{
//退出
b = false;
break;
}
case "*help":
{
//帮助
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("<字幕文件名>\t\t生成字幕");
Console.WriteLine("*exit\t\t\t退出");
Console.WriteLine("*help\t\t\t帮助");
Console.WriteLine("*list\t\t\t展示所有可用字幕文件");
Console.WriteLine("*set\t\t\t设置");
Console.ResetColor();
break;
}
case "*list":
{
//列出可用文件
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine("目前可用文件");
string[] files = Directory.GetFiles("txt", "*.txt");
foreach (string file in files)
{
Console.WriteLine(file);
}
Console.ResetColor();
break;
}
default:
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("[错误]未知的命令" + s);
Console.ResetColor();
break;
}
}
}
continue;
}
Console.WriteLine("正在尝试读取" + s + ".txt");
try
{
string[] ss = File.ReadAllLines("txt\\" + s + ".txt");
Directory.CreateDirectory("subtitles\\" + s);
File.Create("subtitles\\" + s + "\\timer.mcfunction").Close();
File.Create("subtitles\\" + s + "\\start.mcfunction").Close();
File.Create("subtitles\\" + s + "\\end.mcfunction").Close();
//写入timer.mcfunction
ReadAndWrite(ss, s);
//写入start.mcfunction
WriteStart(s);
//写入tick.mcfunction
WriteTick(s);
//写入end.mcfunction
WriteEnd(s);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("字幕{0}生成完毕!", s);
Console.ResetColor();
}
catch (Exception e)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("[错误]" + e.Message);
Console.ResetColor();
}
}
}
static void WriteEnd(string s)
{
//tag @a remove subt_example_tag
//tag @a remove subt_watching
//scoreboard players set subt_example subt_timer -1
//kill @e[tag = subt_line, type = armor_stand]
File.WriteAllLines("subtitles\\" + s + "\\end.mcfunction", new string[] { "tag @a remove subt_" + s + "_tag", "tag @a remove subt_watching", "scoreboard players set subt_" + s + " subt_timer -1", "kill @e[tag=subt_line, type=armor_stand]" });
}
static void WriteTick(string s)
{
//execute if score subt_example subt_timer matches 0.. run scoreboard players add subt_example subt_timer 1
//execute as @a[tag = subt_example_tag] at @s run function subtitle: subtitles / example / timer
File.AppendAllLines("subtitles\\tick.mcfunction", new string[] { "execute as @a[tag=subt_" + s + "_tag] at @s run function subtitle:subtitles/" + s + "/timer", "execute if score subt_" + s + " subt_timer matches 0.. run scoreboard players add subt_" + s + " subt_timer 1" });
}
static void WriteStart(string s)
{
//tag @s add subt_example_tag
//scoreboard players set subt_example subt_timer 0
File.AppendAllLines("subtitles\\" + s + "\\start.mcfunction", new string[] { "tag @s add subt_watching" });
File.AppendAllLines("subtitles\\" + s + "\\start.mcfunction", new string[] { "tag @s add subt_" + s + "_tag" });
File.AppendAllLines("subtitles\\" + s + "\\start.mcfunction", new string[] { "scoreboard players set subt_" + s + " subt_timer 0" });
}
static void ReadAndWrite(string[] ss, string name)
{
//储存文本属性
Text t = new Text();
//tick数
int timer = 0;
for (int i = 0; i < ss.Length; i++)
{
//分析每一行文字
if (ss[i].StartsWith("#/#/"))
{
//为注释,忽略
continue;
}
else if (ss[i].StartsWith("####"))
{
//声明了属性,进行分割
string a = ss[i].Substring(4);
string[] b = a.Split('|');
t.Set(b, i);
}
else
{
//为字幕文本,进行输出
//execute if score subt_example subt_timer matches 10 run summon armor_stand ~1 ~-5 ~ {Invisible:true,CustomNameVisible:true,Tags:["subt_line"],NoGravity:1b,CustomName:'{"text
string output = ("execute if score subt_" + name + " subt_timer matches " + timer + " run summon armor_stand ~2 ~-5 ~ {Invisible:true,CustomNameVisible:true,Tags:[\"subt_line\"],NoGravity:1b,CustomName:'{\"text\":\"" + ss[i] + "\"");
// + "}'}"
if (t.Color != null)
{
//如果有颜色
output += (",\"color\":\"" + t.Color + "\"");
}
if (t.Other.Count != 0)
{
//如果有属性
foreach (string s in t.Other)
{
output += (",\"" + s + "\":true");
}
}
output += "}'}\n";
//Console.WriteLine(output);
using (FileStream f = new FileStream("subtitles\\" + name + "\\timer.mcfunction", FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
{
byte[] buffer = Encoding.UTF8.GetBytes(output);
f.Write(buffer, 0, buffer.Length);
}
timer += interval;
t = new Text();
}
}
File.AppendAllLines("subtitles\\" + name + "\\timer.mcfunction", new string[] { "execute if score subt_" + name + " subt_timer matches " + (timer + 120) + " run function subtitle:subtitles/" + name + "/end" });
}
}
}
Text.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Subtitle
{
public class Text{
private string _color;
public string Color
{
get { return this._color;}
}
private ArrayList _other = new ArrayList();
public ArrayList Other
{
get { return this._other; }
}
public static ArrayList colors = new ArrayList();
public static ArrayList others = new ArrayList();
public Text()
{
colors.Add("black");
colors.Add("dark_blue");
colors.Add("dark_green");
colors.Add("dark_aqua");
colors.Add("dark_red");
colors.Add("dark_purple");
colors.Add("gold");
colors.Add("gray");
colors.Add("dark_gray");
colors.Add("blue");
colors.Add("green");
colors.Add("aqua");
colors.Add("red");
colors.Add("light_purple");
colors.Add("yellow");
colors.Add("white");
others.Add("bold");
others.Add("italic");
others.Add("underlined");
others.Add("strikethrough");
others.Add("obfuscated");
}
public static bool IsColor(string s)
{
return colors.Contains(s);
}
public static bool IsOther(string s)
{
return others.Contains(s);
}
public void Set(string[] ss,int i)
{
//分析属性
foreach(string s in ss)
{
if (IsColor(s))
{
if (_color != null)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("[警告]在{0}行出现过多的颜色属性", i - 1);
Console.ResetColor();
}
_color = s;
}
else if (IsOther(s))
{
_other.Add(s);
}
else
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("[警告]在{0}行出现无效的属性", i - 1);
Console.ResetColor();
}
}
}
}
}