• 欢迎!在发帖前请阅读每个板块置顶的版块须知。论坛 QQ 群:931748551
    鼓励大家多多发帖,这里有问必答。论坛左下角可切换明亮 / 黑暗模式哦。

Part 7.插件配置文件 (临时加更)

  • 查看 查看: 22
  • 最后更新 最后更新:
  • Part 7.插件配置文件 (临时加更)​

    本章你将学到:
    • 如何优雅的创造、读取、写入配置文件

    啥是配置文件?​

    • 配置文件用于存放插件的相关设置,TShock插件的配置文件格式一般为json(可带注释)。
    • 配置文件一般直接面向服主,可读性要求高
    • 配置文件在插件中一般初始化时读取一次,/reload的时候读取一次

    Newtonsoft.Json​

    • Newtonsoft.Json是TShock所使用的json库,拥有十分强大的功能.使用Newtonsoft.Json的工具操作json需要使用using语句导入
    C#:
    using Newtonsoft.Json;

    定义配置文件​

    1. 首先我们要创造一个新的.cs文件用来存放我们的配置文件类。我们可以右键解决方案管理器-添加-类/接口,文件名一般和类名一样,通常使用Conifg(PS: Visual Studio新建类的快捷键是Ctrl+Shift+A)
      alt textalt text

    2.首先我们可以套一个模板

    C#:
    using Newtonsoft.Json;

    namespace TestPlugin; //这里要改成和你插件命名空间一样

    public class Config
    {
    /// <summary>
    /// 配置文件路径
    /// </summary>
    private const string ConfigPath = "tshock/TestPlugin.json";

    /// <summary>
    /// 配置文件实例
    /// </summary>
    public static Config Instance = new();

    private static readonly JsonSerializerSettings JsonSettings = new() //配置文件格式化相关,不熟悉Newtonsoft.Json不要更改
    {
    Formatting = Formatting.Indented,
    ObjectCreationHandling = ObjectCreationHandling.Replace
    };

    /*
    *从这开始,就算是正式的配置项部分, 这里以 `在服务器发送表情踢出玩家为例`
    */

    /// <summary>
    /// 允许玩家发表情
    /// </summary>
    [JsonProperty]
    public bool AllowSendEmoji;

    /// <summary>
    /// 玩家发表情后踢出的消息
    /// </summary>
    [JsonProperty]
    public string SendEmojiKickMessage = "此服务器不允许发表情!!!";



    /// <summary>
    /// 将配置文件写入硬盘
    /// </summary>
    public void Write()
    {
    using FileStream fileStream = new(ConfigPath, FileMode.Create, FileAccess.Write, FileShare.Write);
    using StreamWriter streamWriter = new(fileStream);
    streamWriter.Write(JsonConvert.SerializeObject(this, JsonSettings));
    }

    /// <summary>
    /// 从硬盘读取配置文件
    /// </summary>
    public void Read()
    {
    Config result;
    if (!File.Exists(ConfigPath))
    {
    result = new Config();
    result.Write();
    }
    else
    {
    using FileStream fileStream = new(ConfigPath, FileMode.Open, FileAccess.Read, FileShare.Read);
    using StreamReader streamReader = new(fileStream);
    result = JsonConvert.DeserializeObject<Config>(streamReader.ReadToEnd(), JsonSettings)!;
    }
    Instance = result;
    }
    }

    注意:​

    命名空间:​


    C#:
    namespace TestPlugin;

    TestPlugin就是你插件的命名空间如图
    alt text


    配置文件路径问题:​

    C#:
    private const string ConfigPath = "tshock/TestPlugin.json";

    "tshock/TestPlugin.json"是你配置文件的路径,这里不能套文件夹,要套文件夹可以使用TryCreatingDirectory

    C#:
    private const string ConfigPath = "tshock/TestPlugin/TestPlugin.json"; //套文件夹的配置文件

    public void Read()
    {
    Config result;
    if (!File.Exists(ConfigPath))
    {
    Terraria.Utils.TryCreatingDirectory("tshock/TestPlugin"); //创建文件夹,返回值是bool(文件夹是否可用)
    result = new Config();
    result.Write();
    }
    else
    {
    using FileStream fileStream = new(ConfigPath, FileMode.Open, FileAccess.Read, FileShare.Read);
    using StreamReader streamReader = new(fileStream);
    result = JsonConvert.DeserializeObject<Config>(streamReader.ReadToEnd(), JsonSettings)!;
    }
    Instance = result;
    }

    关于JsonProperty​

    • [JsonProperty]是Newtonsoft.Json的一个特性(Attribute),这个东西是挂在字段头上或者前面,用来标记字段的。[JsonProperty]可用来标记需要被写入配置文件的字段,当然默认情况下如果你使用public字段,即使不使用[JsonProperty],也会写入配置中,但是private字段不会。
    • 当然还有个特性叫[JsonIgnore],有这个特性的字段不会被写进配置文件

    初始化&使用配置文件​

    让我们回到插件主体,我们可用在Initialize()方法中加载我们的配置文件

    C#:
    public override void Initialize()
    {
    Config.Instance.Read(); //读取配置文件
    }

    初始化后,tshock文件夹下就会出现我们的配置文件啦! (tshock\TestPlugin.json)


    C#:
    {
    "AllowSendEmoji": false,
    "SendEmojiKickMessage": "此服务器不允许发表情!!!"
    }

    在使用配置项时可用直接从Instance中获取...
    C++:
    if (!Config.Instance.AllowSendEmoji)
    {
    TSPlayer.All.Kick(Config.Instance.SendEmojiKickMessage);
    }

    如果插件修改了某些配置,需要保存可用使用Write()方法

    C#:
    Config.Instance.SendEmojiKickMessage = "5555,服主大人不让你发表情捏~"; //修改配置
    Config.Instance.Write(); //写入配置文件

    使用/reload重载配置文件​

    TShock提供了一个Reload事件,当运行/reload命令时会触发,我们可以在Initialize()方法中注册它

    C#:
    public override void Initialize()
    {
    Config.Instance.Read(); //读取配置文件
    GeneralHooks.ReloadEvent += OnReloadEvent; //注册Reload事件
    }
    protected override void Dispose(bool disposing)
    {
    if (disposing)
    {
    GeneralHooks.ReloadEvent -=OnReloadEvent; //卸载Reload事件
    }
    base.Dispose(disposing);
    }
    private void OnReloadEvent(ReloadEventArgs e)
    {
    Config.Instance.Read(); //读取配置文件
    e.Player.SendSuccessMessage("[TestPlugin]插件配置已重载喵~"); //向玩家发送提示~
    }

    [JsonProperty]的进阶用法​

    自定义字段名​

    让我们回到Conifg.cs,有时候我们在代码里不想使用中文字段,但是我想要在配置文件中,让一些配置项是中文的要咋做呢?此时我们就可以使用JsonProperty的参数了,没错这玩意是有参数的 : (

    C#:
    [JsonProperty("允许玩家发表情")]
    public bool AllowSendEmoji;

    [JsonProperty("发表情踢出消息")]
    public string SendEmojiKickMessage = "此服务器不允许发表情!!!";


    此时初始化的配置文件

    C#:
    {
    "允许玩家发表情": false,
    "玩家发表情后踢出的消息": "此服务器不允许发表情!!!"
    }

    Order排序​

    有时候格式化代码的时候,IDEA会按照字母顺序排列这些字段,这样可能会导致配置中的字段乱掉。此时我们可以使用JsonProperty的Order参数来解决这个问题


    C#:
    [JsonProperty("玩家发表情后踢出的消息",Order = 2)] //Oder 2更大排在后面
    public string SendEmojiKickMessage = "此服务器不允许发表情!!!";

    [JsonProperty("允许玩家发表情",Order = 1)] //Oder 1更小排在前面
    public bool AllowSendEmoji;

    此时初始化的配置文件的配置项是按照我们给定Order排列的

    C#:
    {
    "允许玩家发表情": false,
    "玩家发表情后踢出的消息": "此服务器不允许发表情!!!"
    }

    课后习题​

    写一个插件: 踢出在服务器发指定表情的玩家 ,要求可以配置表情的ID(多个)、是否踢出和踢出消息

    Plugin.cs​

    C#:
    using Terraria;
    using TerrariaApi.Server;
    using TShockAPI;
    using TShockAPI.Hooks;

    namespace KickEmoji;

    [ApiVersion(2, 1)]
    public class KickEmoji : TerrariaPlugin
    {
    public KickEmoji(Main game) : base(game)
    {
    }

    public override string Author => "Cai";
    public override string Description => "踢出哪些乱发表情的坏蛋~";
    public override string Name => "KickEmoji";
    public override Version Version => new(2024, 12, 21, 0); //版本号可以用日期哦~~~

    public override void Initialize()
    {
    Config.Instance.Read(); //读取配置文件
    GeneralHooks.ReloadEvent += OnReloadEvent; //注册Reload事件
    GetDataHandlers.Emoji.Register(OnPlayerSendEmoji); //注册发表情事件
    }

    protected override void Dispose(bool disposing)
    {
    if (disposing)
    {
    GeneralHooks.ReloadEvent -=OnReloadEvent; //卸载Reload事件
    GetDataHandlers.Emoji.UnRegister(OnPlayerSendEmoji); //卸载发表情事件
    }
    base.Dispose(disposing);
    }

    private void OnPlayerSendEmoji(object? sender, GetDataHandlers.EmojiEventArgs e)
    {
    if (Config.Instance.DisallowEmoji.Contains(e.EmojiID)) //判断是否为`禁用表情`
    {
    e.Handled = true; //处理掉这个`表情`

    if (Config.Instance.KickPlayer) //判断是否需要踢出玩家
    {
    e.Player.Kick(Config.Instance.SendEmojiKickMessage, true); //踢出玩家,Kick的第二个形参`force`是`强制踢出`,可踢管理员
    }
    else
    {
    e.Player.SendWarningMessage(Config.Instance.SendEmojiKickMessage); //警告玩家
    }
    }

    }
    private void OnReloadEvent(ReloadEventArgs e)
    {
    Config.Instance.Read(); //读取配置文件
    e.Player.SendSuccessMessage("[TestPlugin]插件配置已重载喵~"); //向玩家发送提示~
    }

    }
  • 正在加载……