From ef8a920d087c9986f2f957eedf2cc2209dc62062 Mon Sep 17 00:00:00 2001 From: Mooling0602 Date: Fri, 18 Oct 2024 18:17:05 +0800 Subject: [PATCH] Update to v2.3.1 --- LICENSE | 201 ++++++++++++++++++ MatrixSync-v2.3.1.mcdr | Bin 0 -> 19292 bytes README.md | 159 +++++++++++++- README_en_us.md | 89 ++++++++ config.ini | 8 + doc/introduction-zh_cn.md | 3 + doc/introduction.md | 1 + lang/en_us.yml | 48 +++++ lang/zh_cn.yml | 48 +++++ matrix_sync/client.py | 65 ++++++ matrix_sync/config.py | 51 +++++ matrix_sync/entry.py | 194 +++++++++++++++++ matrix_sync/receiver.py | 97 +++++++++ matrix_sync/reporter.py | 38 ++++ matrix_sync/token.py | 27 +++ mcdreforged.plugin.json | 13 +- pack_plugin.sh | 25 +++ .../advancement_tips/__init__.py | 56 +++++ .../AdvancementTips/mcdreforged.plugin.json | 15 ++ .../DeathTips/death_tips/__init__.py | 83 ++++++++ .../DeathTips/mcdreforged.plugin.json | 16 ++ subpacks(rolling)/README.md | 3 + .../[MSync]AutoReply/mcdreforged.plugin.json | 15 ++ .../msync_auto_reply/__init__.py | 18 ++ .../MSync.MoreMessages.mcdr | Bin 0 -> 1154 bytes .../mcdreforged.plugin.json | 15 ++ .../msync_more_msg/__init__.py | 34 +++ subpacks(rolling)/[MSync]PlayerBind/.temp | 1 + .../[MSync]PlayingTips/MSync.PlayingTips.mcdr | Bin 0 -> 1140 bytes .../mcdreforged.plugin.json | 15 ++ .../msync_playing_tips/__init__.py | 28 +++ .../mcdreforged.plugin.json | 15 ++ .../msync_debugger/__init__.py | 12 ++ 33 files changed, 1382 insertions(+), 11 deletions(-) create mode 100644 LICENSE create mode 100644 MatrixSync-v2.3.1.mcdr create mode 100644 README_en_us.md create mode 100644 config.ini create mode 100644 doc/introduction-zh_cn.md create mode 100644 doc/introduction.md create mode 100644 lang/en_us.yml create mode 100644 lang/zh_cn.yml create mode 100644 matrix_sync/client.py create mode 100644 matrix_sync/config.py create mode 100644 matrix_sync/entry.py create mode 100644 matrix_sync/receiver.py create mode 100644 matrix_sync/reporter.py create mode 100644 matrix_sync/token.py create mode 100644 pack_plugin.sh create mode 100644 subpacks(rolling)/AdvancementTips/advancement_tips/__init__.py create mode 100644 subpacks(rolling)/AdvancementTips/mcdreforged.plugin.json create mode 100644 subpacks(rolling)/DeathTips/death_tips/__init__.py create mode 100644 subpacks(rolling)/DeathTips/mcdreforged.plugin.json create mode 100644 subpacks(rolling)/README.md create mode 100644 subpacks(rolling)/[MSync]AutoReply/mcdreforged.plugin.json create mode 100644 subpacks(rolling)/[MSync]AutoReply/msync_auto_reply/__init__.py create mode 100644 subpacks(rolling)/[MSync]MoreMessages/MSync.MoreMessages.mcdr create mode 100644 subpacks(rolling)/[MSync]MoreMessages/mcdreforged.plugin.json create mode 100644 subpacks(rolling)/[MSync]MoreMessages/msync_more_msg/__init__.py create mode 100644 subpacks(rolling)/[MSync]PlayerBind/.temp create mode 100644 subpacks(rolling)/[MSync]PlayingTips/MSync.PlayingTips.mcdr create mode 100644 subpacks(rolling)/[MSync]PlayingTips/mcdreforged.plugin.json create mode 100644 subpacks(rolling)/[MSync]PlayingTips/msync_playing_tips/__init__.py create mode 100644 subpacks(rolling)/[MSync]plgDebugger/mcdreforged.plugin.json create mode 100644 subpacks(rolling)/[MSync]plgDebugger/msync_debugger/__init__.py diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/MatrixSync-v2.3.1.mcdr b/MatrixSync-v2.3.1.mcdr new file mode 100644 index 0000000000000000000000000000000000000000..050e805c54e5867989a961b27dd20a754814a117 GIT binary patch literal 19292 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 K3B}00qkjW(8K*b^ literal 0 HcmV?d00001 diff --git a/README.md b/README.md index 7e839b3..e01b2ed 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,156 @@ -# Matrix-MCDR -一个MCDR(全称MCDReforged)插件,用于同步Matrix群组和线上游戏之间的消息。 -当前已完成预览开发版本,支持线上游戏的消息上报到群组中。 +- 中文 +- [English](https://github.com/Mooling0602/MatrixSync-MCDR/blob/2.3.0/README_en_us.md) -用法:从Release下载最新版本,甩到plugins文件夹或你设置的存放插件的文件夹内,然后注意控制台输出的提示即可。 +# MatrixSync-MCDR +一个MCDR(全称[MCDReforged](https://mcdreforged.com/))插件,用于同步Matrix群组和《我的世界》服务器的线上游戏之间的消息。 -注意:首次加载插件会初始化配置并自动卸载插件,你需要修改完默认配置后,重启服务器或重载插件才能正常使用。 +关于[Matrix](https://matrix.org/): 一个开放的去中心化通讯协议,用于聊天软件。 + +开发过程中用到的pypi项目:[matrix-nio](https://pypi.org/project/matrix-nio/)。 + +当前分支版本:主分支@2.3.1 + +## 用法 +从release下载最新版本,在MCDReforged的启动环境中安装好需要的Python依赖,然后扔到plugins文件夹里面即可。 + +### 使用 Git +> This part doesn't support English yet, please use translate tools at present. +> +> 依赖软件包`zip` +> +> 在终端上运行`git clone https://github.com/Mooling0602/MatrixSync-MCDR.git`,然后进入`MatrixSync-MCDR`目录下并运行`pack_plugin.sh`(记得给文件设置可执行权限) +> +> 若无法正常访问GitHub,可以运行`git clone https://mirror.ghproxy.com/https://github.com/Mooling0602/MatrixSync-MCDR.git` +> +> 懒人用命令:`git clone https://mirror.ghproxy.com/https://github.com/Mooling0602/MatrixSync-MCDR.git && cd MatrixSync-MCDR && chmod +x pack_plugin.sh && ./pack_plugin.sh` +> +> 正常情况下,请不要修改脚本内容及所用配置(config.ini) + +在使用此插件之前,你必须知道什么是[Matrix](https://matrix.org/),然后准备一个账号作为matrix机器人用于消息同步,并认真阅读下面的内容以进行插件配置。 + +配置完毕并启用插件后,若有测试消息成功发送到matrix群组,则表示消息同步开始工作。 + +若消息同步的过程中有任意方向的消息转发出现问题,也请按下面的内容检查配置是否正确。 + +### 配置文件 +#### config.json + +| 配置项 | 配置内容 | +| - | - | +| **homeserver** | 机器人账号登录所使用的根服务器 | +| **user_id** | 机器人的账号ID,格式为@<用户名>:<根服务器>,如@mcchatbot:example.com | +| **password** | 机器人账号的密码,一般仅在初次登录使用 | +| **room_id** | 需要接收游戏消息的房间的ID,目前只能设置一个 | +| **room_name** | 需要转发消息到游戏内的房间的显示名称(必须准确无误,若发生更新也需要同步修改,否则你将看不到任何消息),目前只能设置一个 | +| **device_id** | 登录用的设备名,一般无需修改,可自定义 | + +#### settings.json + +| 配置项 | 配置内容 | +| - | - | +| plugin-enabled | 插件是否启用,请确保配置文件和所需设置修改无误后再开启 | +| allow_all_rooms_msg | 是否允许来自所有房间的消息,若开启,则来自机器人账号所加入的房间的消息都会被转发到游戏中,并注明房间的显示名称,否则只转发已设置的房间的消息 | +| sync_old_msg | 是否同步旧的消息,默认开启,可在插件配置目录下的token.json文件中增加有效的`next_batch`项后关闭 | + +## 接口(API) +插件提供了一个协程函数`sendMsg()`供其他开发者调用以实现向Matrix群组发送自定义内容,其回调参数为`message`,下面是代码参考: +```python +import asyncio +import ... + +from mcdreforged.api.all import * +from matrix_sync.reporter import sendMsg +from ... import ... + +def main(): + pass + asyncio.run(sendMsg(message)) +``` +如果要在协程内调用该接口: +```python +import asyncio +import ... + +from mcdreforged.api.all import * +from matrix_sync.reporter import sendMsg +from ... import ... + +async def main(): + pass + await sendMsg(message) +``` +将主插件(MatrixSync)添加到MCDR依赖中,并将其Python依赖一并添加到自己的插件中,然后在开发过程中把`message`替换成你想要发送的自定义内容即可。 + +请注意,该接口的支持是实验性的,若要调用此接口,请确保用户安装并配置好了主插件(MatrixSync)。 + +2.2.0版本以后,机器人的初始化将直接在加载插件时进行,所以如果需要判断主插件的消息上报器是否能够正常工作,可以在调用函数前导入相关的全局变量并加入判断条件,下面是示例代码: +```python +import asyncio +import matrix_sync.client +import ... + +from mcdreforged.api.all import * +from matrix_sync.reporter import sendMsg + +def main(): + pass + clientStatus = matrix_sync.client.clientStatus + if clientStatus: + asyncio.run(sendMsg(message)) + else: + # 可以在此自定义报错的内容,也可以直接删除此部分忽略该接口 + server.logger.info("error") +``` +协程函数示例: +```python +import asyncio +import matrix_sync.client +import ... + +from mcdreforged.api.all import * +from matrix_sync.reporter import sendMsg + +async def main(): + pass + clientStatus = matrix_sync.client.clientStatus + if clientStatus: + await sendMsg(message) + else: + # 可以在此自定义报错的内容,也可以直接删除此部分忽略该接口 + server.logger.info("error") +``` +由于2.3.0版本新增了Matrix房间消息的分发事件,且2.3.1版本重构了这部分接口,所以该部分内容已过时。 + +这些过时的内容仍然持续有效,但其做法不再推荐,请等待后续更详细的文档更新。 + +重构后接口的简单用法: +```python +import matrix_sync.client + +def main(): + clientStatus = matrix_sync.client.clientStatus + if clientStatus: + sender(message) + +# 消息将在独立线程中被发送到Matrix,不再可能会阻塞MCDR主线程 +``` + +## 热重载(reload)及消息互通控制 +插件默认在游戏服务端启动完成时才会自动启动房间消息接收进程,重新加载插件后,消息接收器并不会自动启动。 + +要手动启动房间消息接收进程,请执行MCDR命令`!!msync start`,游戏内和控制台上都可以使用。 + +要关闭房间消息接收进程,可以在控制台使用`!!msync stop`,直到下次服务器启动完成前消息接收器都必须手动重启。 + +要在详细阅读后关闭2.3.1版本新增的大量提示,可以使用`!!msync closetip`,目前想重新查看提示,只能在源码中查看语言文件,或自行修改token.json + +插件会自动在解析到游戏内的消息时尝试转发到配置好的Matrix房间内,暂时无法禁用。 + +该指令没有权限要求,但设置了进程锁(安全机制),重复执行会警告提示,不会影响插件功能的正常运行。 + +请注意,该功能是实验性的,若发现任何错误请及时通过GitHub Issue向插件作者反馈! + +## 注意 +- 首次加载插件的时候,插件将自动初始化配置并卸载自己。你需要正确修改默认的配置文件,并在settings.json中启用plugin_enabled配置项以启用插件,然后重启服务器或着重载插件以正常使用。 +- 不打算支持加密信息(EE2E),有需要可以二次开发修改插件,欢迎PR。 +- 多语言目前只支持中文(简体)和英语(用谷歌和ChatGPT从中文翻译),任何人都可以联系我帮助完善翻译,欢迎PR到/lang语言文件中。 diff --git a/README_en_us.md b/README_en_us.md new file mode 100644 index 0000000..87ef267 --- /dev/null +++ b/README_en_us.md @@ -0,0 +1,89 @@ +- [中文](https://github.com/Mooling0602/MatrixSync-MCDR/blob/2.3.0/README.md) +- English + +# MatrixSync-MCDR +A MCDR (full name [MCDReforged](https://mcdreforged.com/)) plugin, use to sync messages between Matrix groups and online gaming in Minecraft servers. + +About [Matrix](https://matrix.org/): an open decentralized network communication protocol for chat software. + +The following project is used in the development process: [matrix-nio](https://pypi.org/project/matrix-nio/)。 + +Thanks for ChatGPT and Google Translate's help to translate the content from Chinese, if anything wrong, please issue to feedback or PR to `/lang`. + +Present branch version: released@2.3.1 + +## Usage +Download the latest version from the release, install the necessary Python dependencies in the MCDReforged startup environment, and then throw it into the plugins folder. + +Before using this plugin, you must know what [Matrix](https://matrix.org/) is, then prepare an account as a matrix bot for message synchronization, and carefully read the following content to configure the plugin. + +After configuration and enabling the plugin, if the test message is successfully sent to the matrix group, it means that message synchronization has started to work. + +If there is any issue with message forwarding in any direction during the message synchronization process, please check the configuration according to the following content to ensure it is correct. + +### Configuration File +#### config.json + +| Configuration Item | Content | +| - | - | +| **homeserver** | The home server used to log in to the bot account | +| **user_id** | The bot account ID, formatted as @username:example.com | +| **password** | The password of the bot account, generally only used for the initial login | +| **room_id** | The ID of the room to receive game messages, currently only one can be set | +| **room_name** | The display name of the room to forward messages to the game (must be accurate, if updated, it also needs to be modified synchronously, otherwise you will not see any messages), currently only one can be set | +| **device_id** | The device name used for login, generally no need to modify, can be customized | + +#### settings.json + +| Configuration Item | Content | +| - | - | +| plugin-enabled | Whether the plugin is enabled, please ensure the configuration file and necessary settings are modified correctly before enabling | +| allow_all_rooms_msg | Whether to allow messages from all rooms, if enabled, messages from rooms joined by the bot account will be forwarded to the game, with the room display name specified, otherwise only messages from the configured room will be forwarded | +| sync_old_msg | Whether to sync old messages, enabled on default, can turn it off after vaild `next_batch` appeared in token.json in config path of the plugin | + +## Interface (API) +The plugin provides a coroutine function `sendMsg()` for other developers to call to send custom content to the Matrix group. Its callback parameter is `message`. Here is the code reference: +```python +import asyncio +import matrix_sync.client +import ... + +from mcdreforged.api.all import * +from matrix_sync.reporter import sendMsg +from ... import ... + +def main(): + pass + clientStatus = matrix_sync.client.clientStatus + if clientStatus: + asyncio.run(sendMsg(message)) + +# async def main(): +# pass +# clientStatus = matrix_sync.client.clientStatus +# if clientStatus: +# await sendMsg(message) +``` +Add the main plugin (MatrixSync) to the dependencies of MCDR, and include its Python dependencies in your plugin as well. Then, during development, replace `message` with the custom content you want to send. + +Please note that support for this interface is experimental, and it cannot be guaranteed that the message forwarding functionality of the main plugin (MatrixSync) will work when calling this interface (there may be situations where the bot is not properly configured, or existing login information and tokens cannot be used). If you want to call this interface, please ensure that the user has installed and configured the main plugin (MatrixSync). + +Outdated after version 2.3.1, please wait new document finished. + +## Hot Reload (reload) & message sync control + +By default, the plugin will only start the room message receive process after the game server has finished starting up. After reloading the plugin, the MatrixReceiver sub thread will not start automatically. + +To manually start the room message receive process, execute the MCDR command `!!msync start`, which can be used both in-game and in the console. + +To stop the room message receive process, execute the command `!!msync stop`, which can be only used in the console and need manually restart until next time the server startup. + +Plugin will send game messages to the matrix room configured after parsed them, you can't disable this at present. + +This command does not require any permissions, but it sets up a process lock (a safety mechanism). Repeated execution will trigger a warning prompt, but it will not affect the normal operation of the plugin. + +Please note that this feature is experimental. If you encounter any errors, please provide feedback to the plugin author through GitHub Issues! + +## Notes +- When the plugin is first loaded, it will automatically initialize the configuration and then unload itself. You need to correctly modify the default configuration file and enable the `plugin_enabled` configuration item in `settings.json` to enable the plugin. After that, restart the server or reload the plugin to use it normally. +- End-to-end encryption (EE2E) is not supported. If needed, you can customize and modify the plugin yourself, or submit a pull request (PR) with your changes. diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..83b64f4 --- /dev/null +++ b/config.ini @@ -0,0 +1,8 @@ +# Do not edit this file! +# 不要修改这个文件! +[framework] +ver=1 +[main] +ver=2.3.1 +[release] +test=1 diff --git a/doc/introduction-zh_cn.md b/doc/introduction-zh_cn.md new file mode 100644 index 0000000..d033cf1 --- /dev/null +++ b/doc/introduction-zh_cn.md @@ -0,0 +1,3 @@ +一个MCDR(全称MCDReforged)插件,用于同步Matrix群组和《我的世界》服务器的线上游戏之间的消息。 + +2.2.0 版本修复了久未解决的许多问题,并从该版本开始正式使用 Apache-2.0 开源协议。 diff --git a/doc/introduction.md b/doc/introduction.md new file mode 100644 index 0000000..259df3d --- /dev/null +++ b/doc/introduction.md @@ -0,0 +1 @@ +A MCDR (full name "MCDReforged") plugin sync messages between online game and Matrix groups. diff --git a/lang/en_us.yml b/lang/en_us.yml new file mode 100644 index 0000000..939fd98 --- /dev/null +++ b/lang/en_us.yml @@ -0,0 +1,48 @@ +matrix_sync: + init_tips: + config_path: Config path + need_edit_config: Please edit the default config.json to the correct configuration information, and then restart the plugin after enabling the plugin_enabled item in settings.json! + read_config: Applying precent config, please waiting... + hotload_tip: If reloading plugin needs to enable message sync manually, to transfer messages from matrix to the game, please execute !!msync + on_console: + commands: Excute command + on_server_stop: Server stopped, stopping messages sync. + on_server_crash: Server crashed or not stopped normally, stopping messages sync, unknown errors may happen. + on_unload: Unloading plugin, waiting for message sync process to exit... + old_msg_sync: If there are no errors, you can now modify the "sync_old_msg" item in the settings.json file in the plugin configuration directory to false, which will prevent the plugin from syncing old messages that have already been sent. + old_msg_sync2: Please note that messages sent in the chat room when message synchronization is not running will not be sent out anymore. + old_msg_sync3: This is an experimental feature. If there are any issues, please report them via GitHub Issues. + old_msg_sync4: If there are any errors, please first change the "sync_old_msg" item to true, and once the message receiver is functioning correctly, check if the token.json file in the plugin configuration directory contains a valid "next_batch" item. If it does, you can follow the steps mentioned above to retry. + old_msg_sync5: This prompt text is quite lengthy. If you have read and understood it, you can use !!msync closetip to close this prompt. + on_tip_read: Tips closed, you can see these in GitHub page after. + run_tips: + failed: Failed to login! + first_time_login: First login, continuing with password... + login_success: Login successfully, caching token for later uses. + get_token: Token Cached! + error: Please check your account, password and network conditions, you can issue in GitHub for any help. + manual_sync: + start_sync: Room message receiver (as sub thread 'MatrixReceiver') started! + start_tip: Room message receiver reloaded with possible history messages reprinting. + stop_sync: Room message receiver stopped! Before next time server startup, it needs to be started manually. + start_error: Room message receiver is already running, do not restart it in cases not special such as non-reloading or after stopped! + stop_error: Unknown errors happened when stop room message receiver! + stop_denied: Please run in console! + not_running: Room message receiver is not running! + sync_tips: + server_stopping: MC Server is stopping now... + server_stopped: MC Server stopped. + server_started: MC Server started successfully! + server_crashed: MC Server crashed or not stopped normally! + reporter_status: Message sync has inited on MC Server! + start_report: Bot login successfully, sent a test message. + test: Player message detected, trying to send to Matrix group... + tr: + hs: Homeserver + ac: Account + cs: Console + help_tips: + title: "!!msync Command Help" + start_command: "!!msync start - Start message sync process. (will automatically start when server startup) " + stop_command: "!!msync stop - Stop message sync process. (will automatically stop when server stopped)" + closetip_command: Use !!msync closetip to close the numerous prompts that appear after starting message sync. It is recommended to read and understand them carefully before closing. diff --git a/lang/zh_cn.yml b/lang/zh_cn.yml new file mode 100644 index 0000000..856afdc --- /dev/null +++ b/lang/zh_cn.yml @@ -0,0 +1,48 @@ +matrix_sync: + init_tips: + config_path: 配置文件所在目录 + need_edit_config: 请将默认配置config.json修改为正确的配置信息,然后启用settings.json中的plugin_enabled项后重启插件! + read_config: 正在应用当前配置,请稍等…… + hotload_tip: 若重载插件需要手动开启消息同步,以将Matrix的消息转发到游戏中,请执行!!msync + on_console: + commands: 执行命令 + on_server_stop: 服务器已关闭,停止消息同步。 + on_server_crash: 服务器崩溃或者非正常退出,已停止消息同步,可能出现未知报错。 + on_unload: 正在卸载插件,等待消息同步进程退出…… + old_msg_sync: 如果没有报错,现在你可以修改插件配置目录下的settings.json中的"sync_old_msg"项为false,让插件不再同步发送过的旧消息 + old_msg_sync2: 请注意,在消息同步未运行时房间内的聊天消息,不会再发送出来 + old_msg_sync3: 这是一项实验性功能,如果有问题请通过GitHub Issues反馈 + old_msg_sync4: 若有报错,请先修改"sync_old_msg"项为true,待消息接收器正常工作后检查插件配置目录下的token.json是否存在含有有效数据的“next_batch”项,若是则按上面的步骤重新操作即可 + old_msg_sync5: 此提示文本内容较多,若你已经阅读并理解完毕,可以使用!!msync closetip关闭此提示 + on_tip_read: 已关闭提示,后续可在GitHub页面重新查看! + run_tips: + failed: 登录失败! + first_time_login: 首次登录,将使用密码继续…… + login_success: 登录成功,正在缓存Token以供后续使用。 + get_token: Token缓存完成! + error: 请检查你的账号密码以及网络情况,你可以在GitHub提出issue以获取任何帮助。 + manual_sync: + start_sync: 已开始接收房间消息!(启动子线程MatrixReceiver) + start_tip: 房间消息接收器开始重载,已发送的历史消息可能会重新输出! + stop_sync: 已停止接收房间消息,到下次服务器启动完成前都只能手动重启! + start_error: 已在接收房间消息,非重载等特殊情况或手动停止后,不要再次尝试启动! + stop_error: 关闭房间消息接收器时发生未知错误! + stop_denied: 请在控制台执行! + not_running: 房间消息接收器未在运行! + sync_tips: + server_stopping: "[!]服务器正在关闭……" + server_stopped: "[×]服务器已停止运行" + server_started: "[√]服务器启动完成!" + server_crashed: "[×]服务器崩溃或非正常退出!" + reporter_status: "[!]消息互通已在游戏服务器上初始化完成" + start_report: 机器人登录成功,已发送测试消息。 + test: 检测到玩家消息,正在尝试发送到Matrix群组…… + tr: + hs: 根服务器 + ac: 账户 + cs: 控制台 + help_tips: + title: "!!msync 指令帮助" + start_command: "使用!!msync start开始消息同步(服务器启动完成时会自动开始)" + stop_command: "使用!!msync stop关闭消息同步(服务端停止运行后会自动关闭)" + closetip_command: "使用!!msync closetip关闭消息同步开始后出现的大量提示,建议认真阅读理解后再关闭" diff --git a/matrix_sync/client.py b/matrix_sync/client.py new file mode 100644 index 0000000..bb0e00e --- /dev/null +++ b/matrix_sync/client.py @@ -0,0 +1,65 @@ +import asyncio +import json +import os +import sys +import matrix_sync.config +from matrix_sync.reporter import sendMsg +from mcdreforged.api.all import * +from nio import AsyncClient, LoginResponse + +psi = ServerInterface.psi() + +clientStatus = False + +# Cache Token. +def cache_token(resp: LoginResponse): + TOKEN_FILE = matrix_sync.config.TOKEN_FILE + with open(TOKEN_FILE, "w") as f: + json.dump( + { + "token": resp.access_token + }, + f, + ) + +# Init Matrix bot. +@new_thread('MatrixInitClient') +def init(): + asyncio.run(init_task()) + +async def init_task(): + await init_client() + +async def init_client() -> None: + TOKEN_FILE = matrix_sync.config.TOKEN_FILE + homeserver = matrix_sync.config.homeserver + user_id = matrix_sync.config.user_id + password = matrix_sync.config.password + device_id = matrix_sync.config.device_id + psi.logger.info(user_id) + if not os.path.exists(TOKEN_FILE): + psi.logger.info(psi.rtr("matrix_sync.run_tips.first_time_login")) + client = AsyncClient(homeserver, user_id) + resp = await client.login(password, device_name=f"{device_id}") + if isinstance(resp, LoginResponse): + psi.logger.info(psi.rtr("matrix_sync.run_tips.login_success")) + cache_token(resp) + psi.logger.info(psi.rtr("matrix_sync.run_tips.get_token")) + await test_client() + else: + failed_tip = psi.rtr("matrix_sync.run_tips.failed") + homeserver_tr = psi.rtr("matrix_sync.tr.hs") + account_tr = psi.rtr("matrix_sync.tr.ac") + psi.logger.info(f"{failed_tip}: {resp}") + psi.logger.info(f'{homeserver_tr}: "{homeserver}", {account_tr}: "{user_id}"') + psi.logger.info(psi.rtr("matrix_sync.run_tips.error")) + sys.exit(1) + else: + await test_client() + +# Send test messages. +async def test_client(): + global clientStatus + message = psi.rtr("matrix_sync.sync_tips.reporter_status") + await sendMsg(message) + clientStatus = True diff --git a/matrix_sync/config.py b/matrix_sync/config.py new file mode 100644 index 0000000..2587a7d --- /dev/null +++ b/matrix_sync/config.py @@ -0,0 +1,51 @@ +from mcdreforged.api.all import * + +psi = ServerInterface.psi() +lock_is_None = True + +# Default config. +account_config = { + "homeserver": "https://matrix.example.org", + "user_id": "@username:matrix.example.org", + "password": "your_password", + "room_id": "!your-room_id:matrix.example.org", + "room_name": "your-room-display-name", + "device_id": "mcdr" +} + +# Bot manage config. +bot_config = { + "plugin_enabled": False, + "allow_all_rooms_msg": False, + "sync_old_msg": True +} + +def load_config(): + global config, user_id, password, room_id, room_name, settings, use_token, DATA_FOLDR, TOKEN_FILE, device_id, homeserver, load_tip, sync_old_msg + config = psi.load_config_simple("config.json", account_config) + user_id = config["user_id"] + password = config["password"] + room_id = config["room_id"] + room_name = config["room_name"] + settings = psi.load_config_simple("settings.json", bot_config) + sync_old_msg = settings["sync_old_msg"] + DATA_FOLDER = psi.get_data_folder() + tip_path = psi.rtr("matrix_sync.init_tips.config_path") + load_tip = f"{tip_path}: {DATA_FOLDER}" + TOKEN_FILE = f"{DATA_FOLDER}/token.json" + device_id = config["device_id"] + homeserver = config["homeserver"] + if not (homeserver.startswith("https://") or homeserver.startswith("http://")): + homeserver = "https://" + config["homeserver"] + +# Check the config. +def check_config(): + global lock_is_None, do_unload + if not settings["plugin_enabled"]: + lock_is_None = True + psi.logger.info(psi.rtr("matrix_sync.init_tips.need_edit_config")) + do_unload = True + else: + lock_is_None = False + do_unload = False + psi.logger.info(psi.rtr("matrix_sync.init_tips.read_config")) diff --git a/matrix_sync/entry.py b/matrix_sync/entry.py new file mode 100644 index 0000000..177a261 --- /dev/null +++ b/matrix_sync/entry.py @@ -0,0 +1,194 @@ +import asyncio +import threading +import json +import matrix_sync.config +import matrix_sync.client +import matrix_sync.receiver +import matrix_sync.reporter + +from matrix_sync.client import init +from matrix_sync.config import load_config, check_config +from matrix_sync.receiver import getMsg +from matrix_sync.reporter import sender +from matrix_sync.token import get_tip_read +from mcdreforged.api.all import * + +# Framwork ver: 2.3.0-1 +psi = ServerInterface.psi() +tLock = threading.Lock() +lock_is_None = matrix_sync.config.lock_is_None +cleaned = False +sync_task = None + +def on_load(server: PluginServerInterface, old): + load_config() + server.logger.info(matrix_sync.config.load_tip) + check_config() + do_unload = matrix_sync.config.do_unload + if do_unload: + server.unload_plugin("matrix_sync") + else: + init() + server.register_command( + Literal('!!msync') + .runs( + lambda src: src.reply(help()) + ) + .then( + Literal('start') + .runs( + lambda src: src.reply(manualSync()) + ) + ) + # .then( + # Literal('restart') + # .runs( + # lambda src: src.reply(restartSync()) + # ) + # ) + .then( + Literal('stop') + .runs( + lambda src: src.reply(stopSync(src)) + ) + ) + .then( + Literal('closetip') + .runs( + lambda src: src.reply(closeTip()) + ) + ) + ) + server.logger.info(psi.rtr("matrix_sync.init_tips.hotload_tip")) + +# Help tips. +def help() -> RTextList: + return RTextList( + psi.rtr("matrix_sync.help_tips.title") + "\n", + psi.rtr("matrix_sync.help_tips.start_command") + "\n", + psi.rtr("matrix_sync.help_tips.stop_command") + "\n", + psi.rtr("matrix_sync.help_tips.closetip_command") + "\n" + ) + +# Manually run sync processes. +def manualSync(): + if not tLock.locked(): + start_room_msg() + psi.say(psi.rtr("matrix_sync.manual_sync.start_tip")) + read = asyncio.run(get_tip_read()) + if not read: + return RTextList( + psi.rtr("matrix_sync.manual_sync.start_sync") + "\n", + psi.rtr("matrix_sync.old_msg_sync") + "\n", + psi.rtr("matrix_sync.old_msg_sync2") + "\n", + psi.rtr("matrix_sync.old_msg_sync3") + "\n", + psi.rtr("matrix_sync.old_msg_sync4") + "\n", + psi.rtr("matrix_sync.old_msg_sync5") + "\n" + ) + else: + return psi.rtr("matrix_sync.manual_sync.start_sync") + else: + return psi.rtr("matrix_sync.manual_sync.start_error") + +# Manually stop sync processes. +def stopSync(src): + global sync_task + if src.is_console: + try: + if sync_task is not None: + sync_task.cancel() + return psi.rtr("matrix_sync.manual_sync.stop_sync") + else: + return psi.rtr("matrix_sync.manual_sync.not_running") + except Exception: + return psi.rtr("matrix_sync.manual_sync.stop_error") + else: + return psi.rtr("matrix_sync.manual_sync.stop_denied") + +def closeTip(): + TOKEN_FILE = matrix_sync.config.TOKEN_FILE + with open(TOKEN_FILE, "r") as f: + existing_data = json.load(f) + existing_data["tip_read"] = True + with open(TOKEN_FILE, "w") as f: + json.dump(existing_data, f) + return psi.rtr("matrix_sync.on_tip_read") + +# Restart room message receiver, not recommend. +# def restartSync(src): +# stopSync(src) +# manualSync() + +# Automatically run sync processes. +def on_server_startup(server: PluginServerInterface): + clientStatus = matrix_sync.client.clientStatus + if not tLock.locked(): + if clientStatus: + message = psi.rtr("matrix_sync.sync_tips.server_started") + sender(message) + start_room_msg() + else: + server.logger.info(server.rtr("matrix_sync.manual_sync.start_error")) + +# Sub thread to receive room messages from matrix without block main MCDR thread. +@new_thread('MatrixReceiver') +def start_room_msg(): + with tLock: + asyncio.run(on_room_msg()) + +async def on_room_msg(): + global sync_task + if sync_task is not None and not sync_task.done(): + sync_task.cancel() + await sync_task + sync_task = asyncio.create_task(getMsg()) + await sync_task + +# Game message reporter +def on_user_info(server: PluginServerInterface, info: Info): + # formater(server, info) + if info.player is not None and not info.content.startswith("!!"): + playerMsg = f"<{info.player}> {info.content}" + clientStatus = matrix_sync.client.clientStatus + if clientStatus: + sender(playerMsg) + +# Exit sync process when server stop. +def on_server_stop(server: PluginServerInterface, server_return_code: int): + global cleaned, sync_task + if server_return_code == 0: + server.logger.info(server.rtr("matrix_sync.on_server_stop")) + clientStatus = matrix_sync.client.clientStatus + stopTip = server.rtr("matrix_sync.sync_tips.server_stopped") + if clientStatus: + sender(stopTip) + else: + server.logger.info(server.rtr("matrix_sync.on_server_crash")) + crashTip = server.rtr("matrix_sync.sync_tips.server_crashed") + clientStatus = matrix_sync.client.clientStatus + if clientStatus: + sender(crashTip) + + if sync_task is not None: + sync_task.cancel() + try: + pass + except asyncio.TimeoutError: + server.logger.warning("Timed out waiting for sync_task to finish.") + + cleaned = True + +def on_unload(server: PluginServerInterface): + global sync_task, cleaned + if cleaned: + server.logger.info(server.rtr("matrix_sync.on_unload")) + else: + if sync_task is not None: + sync_task.cancel() + try: + pass + except asyncio.TimeoutError: + server.logger.warning("Timed out waiting for sync_task to finish.") + sync_task = None + if not lock_is_None: + server.logger.info(server.rtr("matrix_sync.on_unload")) diff --git a/matrix_sync/receiver.py b/matrix_sync/receiver.py new file mode 100644 index 0000000..a2d8b49 --- /dev/null +++ b/matrix_sync/receiver.py @@ -0,0 +1,97 @@ +# Codes sub thread MatrixReceiver running. +import asyncio +import json +import matrix_sync.config + +from matrix_sync.token import getToken, get_next_batch +from mcdreforged.api.all import * +from nio import AsyncClient, MatrixRoom, RoomMessageText, SyncResponse, SyncError +from typing import Optional + +psi = ServerInterface.psi() +homeserver_online = True +refresh = True +next_batch = None +client = None + +class RoomMessageEvent(PluginEvent): + def __init__(self, message: str, sender: str, room: Optional[str] = None): + super().__init__('MatrixRoomMessage') # 使用固定的事件ID + self.message = message + self.sender = sender + self.room = room + +async def message_callback(room: MatrixRoom, event: RoomMessageText) -> None: + user_id = matrix_sync.config.user_id + room_name = matrix_sync.config.room_name + roomMsg = f"[MSync|{room.display_name}] {room.user_name(event.sender)}: {event.body}" + transfer = True + # Avoid echo messages. + if event.sender == user_id: + transfer = False + # Apply settings config + if not matrix_sync.config.settings["allow_all_rooms_msg"]: + roomMsg = f"[MSync] {room.user_name(event.sender)}: {event.body}" + if not room.display_name == room_name: + transfer = False + else: + psi.dispatch_event(RoomMessageEvent(event.body, room.user_name(event.sender)), (event.body, room.user_name(event.sender))) + else: + psi.dispatch_event(RoomMessageEvent(event.body, room.user_name(event.sender), room.display_name), (event.body, room.user_name(event.sender), room.display_name)) + if transfer: + psi.broadcast(f"{roomMsg}") + +def sync_cache(data): + TOKEN_FILE = matrix_sync.config.TOKEN_FILE + with open(TOKEN_FILE, "r") as f: + existing_data = json.load(f) + existing_data["next_batch"] = data + with open(TOKEN_FILE, "w") as f: + json.dump(existing_data, f) + +def on_sync_response(response: SyncResponse): + global refresh + if refresh: + next_batch = response.next_batch + sync_cache(next_batch) + refresh = False + else: + pass + +def on_sync_error(response: SyncError): + global homeserver_online + psi.logger.error(f"Sync error: {response.status_code}") + if response.status_code >= 500: + homeserver_online = False + +async def getMsg() -> None: + homeserver = matrix_sync.config.homeserver + device_id = matrix_sync.config.device_id + user_id = matrix_sync.config.user_id + sync_old_msg = matrix_sync.config.sync_old_msg + global client + client = AsyncClient(f"{homeserver}") + client.access_token = await getToken() + client.user_id = user_id + client.device_id = device_id + + client.add_response_callback(on_sync_response, SyncResponse) + client.add_response_callback(on_sync_error, SyncError) + client.add_event_callback(message_callback, RoomMessageText) + + try: + if homeserver_online: + if sync_old_msg is True: + await client.sync_forever(timeout=5) + else: + next_batch = await get_next_batch() + await client.sync_forever(timeout=5, since=next_batch) + else: + psi.logger.error("Sync failed: homeserver is down or your network disconnected with it.") + psi.logger.info("Use !!msync start after homeserver is running or your network restored.") + except Exception as e: + psi.logger.error(f"Sync error: {e}") + except asyncio.CancelledError: + await client.close() + finally: + await client.close() diff --git a/matrix_sync/reporter.py b/matrix_sync/reporter.py new file mode 100644 index 0000000..b96555e --- /dev/null +++ b/matrix_sync/reporter.py @@ -0,0 +1,38 @@ +import asyncio +import matrix_sync.client +import matrix_sync.config + +from mcdreforged.api.all import * +from nio import AsyncClient +from matrix_sync.token import getToken + +psi = ServerInterface.psi() + +# Game Message reporter. +@new_thread('MatrixReporter') +def sender(message): + asyncio.run(send(message)) + +async def send(message): + await sendMsg(message) + +async def sendMsg(message) -> None: + homeserver = matrix_sync.config.homeserver + user_id = matrix_sync.config.user_id + room_id = matrix_sync.config.room_id + device_id = matrix_sync.config.device_id + client = AsyncClient(f"{homeserver}") + client.access_token = await getToken() + client.user_id = user_id + client.device_id = device_id + + try: + await client.room_send( + room_id, + message_type="m.room.message", + content={"msgtype": "m.text", "body": f"{message}"}, + ) + + await client.close() + except Exception as e: + psi.logger.error(f"Send to matrix error: {e}") diff --git a/matrix_sync/token.py b/matrix_sync/token.py new file mode 100644 index 0000000..57b481c --- /dev/null +++ b/matrix_sync/token.py @@ -0,0 +1,27 @@ +import aiofiles +import json +import matrix_sync.config + +async def getToken(): + TOKEN_FILE = matrix_sync.config.TOKEN_FILE + async with aiofiles.open(TOKEN_FILE, "r") as f: + contents = await f.read() + cache = json.loads(contents) + return cache["token"] + +async def get_next_batch(): + TOKEN_FILE = matrix_sync.config.TOKEN_FILE + async with aiofiles.open(TOKEN_FILE, "r") as f: + contents = await f.read() + cache = json.loads(contents) + return cache["next_batch"] + +async def get_tip_read(): + TOKEN_FILE = matrix_sync.config.TOKEN_FILE + async with aiofiles.open(TOKEN_FILE, "r") as f: + contents = await f.read() + cache = json.loads(contents) + try: + return cache["tip_read"] + except KeyError: + return False \ No newline at end of file diff --git a/mcdreforged.plugin.json b/mcdreforged.plugin.json index 402b9f8..c259145 100644 --- a/mcdreforged.plugin.json +++ b/mcdreforged.plugin.json @@ -1,14 +1,15 @@ { "id": "matrix_sync", - "version": "0.1.0", + "version": "2.3.1", "name": "MatrixSync", "description": { - "en_us": "Sync messages between online game and Matrix groups. First preview, just send game msg to Matrix groups.", - "zh_cn": "同步Matrix群组和线上游戏的消息. 首个预览版本,只能向Matrix群组上报消息." + "en_us": "Sync messages between online game and Matrix groups.", + "zh_cn": "同步Matrix群组和线上游戏的消息。" }, "dependencies": { "mcdreforged": ">=2.1.0" }, - "author": "CleMooling", - "link": "https://www.staringplanet.top" -} \ No newline at end of file + "author": "Mooling0602", + "link": "https://github.com/Mooling0602/MatrixSync-MCDR", + "entrypoint": "matrix_sync.entry" +} diff --git a/pack_plugin.sh b/pack_plugin.sh new file mode 100644 index 0000000..f9a7b94 --- /dev/null +++ b/pack_plugin.sh @@ -0,0 +1,25 @@ +#!/bin/bash +package_config() { + ini_file=$1 + section=$2 + key=$3 + + value=$(awk -F '=' -v section="$section" -v key="$key" ' + /^\[/{in_section=0} + /^\['$section'\]/{in_section=1} + in_section && $1==key{print $2; exit} + ' "$ini_file") + + echo $value +} + +config_file="config.ini" +framework_ver=$(package_config "$config_file" "framework" "ver") +main_ver=$(package_config "$config_file" "main" "ver") +is_stable=$(package_config "$config_file" "release" "test") + +if [ "$is_stable" -eq 1 ]; then + zip -r "MatrixSync-v${main_ver}-${framework_ver}.mcdr" README.md README_en_us.md mcdreforged.plugin.json requirements.txt LICENSE lang matrix_sync +else + zip -r "MatrixSync-v${main_ver}.mcdr" README.md README_en_us.md mcdreforged.plugin.json requirements.txt LICENSE lang matrix_sync +fi diff --git a/subpacks(rolling)/AdvancementTips/advancement_tips/__init__.py b/subpacks(rolling)/AdvancementTips/advancement_tips/__init__.py new file mode 100644 index 0000000..6d283e9 --- /dev/null +++ b/subpacks(rolling)/AdvancementTips/advancement_tips/__init__.py @@ -0,0 +1,56 @@ +import asyncio +import re +import matrix_sync.client + +from mcdreforged.api.all import * +from matrix_sync.reporter import sendMsg +from atl_api import parseKey, parseValue, parseContent + +psi = ServerInterface.psi() + +lang_files = { + "raw_lang": "server/plugins/Geyser-Spigot/locales/en_us.json", + "translated_lang": "server/plugins/Geyser-Spigot/locales/zh_cn.json" +} + +config = psi.load_config_simple("config.json", lang_files) + +raw_lang = config["raw_lang"] +translated_lang = config["translated_lang"] + +def on_load(server: PluginServerInterface, old): + server.logger.info("MatrixSync 子包: AdvancementsTips 已加载") + server.logger.info("本插件仅供简体中文用户使用") + server.logger.info("语言文件默认使用Geyser配置,若未使用Geyser请自行获取语言文件并配置其路径") + +def on_info(server: PluginServerInterface, info: Info): + if info.is_from_server and re.fullmatch(r'(.+) has completed the challenge (.+)', info.content): + match = re.fullmatch(r'(.+) has completed the challenge (.+)', info.content) + if match: + player = match.group(1) + raw_content = match.group(2) + content = parseContent(raw_content) + key = parseKey(raw_lang, content) + tr_content = parseValue(translated_lang, key) + if matrix_sync.client.clientStatus: + asyncio.run(sendMsg(f"[!]玩家 {player} 完成了挑战 [{tr_content}]")) + if info.is_from_server and re.fullmatch(r'(.+) has reached the goal (.+)', info.content): + match = re.fullmatch(r'(.+) has reached the goal (.+)', info.content) + if match: + player = match.group(1) + raw_content = match.group(2) + content = parseContent(raw_content) + key = parseKey(raw_lang, content) + tr_content = parseValue(translated_lang, key) + if matrix_sync.client.clientStatus: + asyncio.run(sendMsg(f"[!]玩家 {player} 达成了目标 [{tr_content}]")) + if info.is_from_server and re.fullmatch(r'(.+) has made the advancement (.+)', info.content): + match = re.fullmatch(r'(.+) has made the advancement (.+)', info.content) + if match: + player = match.group(1) + raw_content = match.group(2) + content = parseContent(raw_content) + key = parseKey(raw_lang, content) + tr_content = parseValue(translated_lang, key) + if matrix_sync.client.clientStatus: + asyncio.run(sendMsg(f"[!]玩家 {player} 取得了进度 [{tr_content}]")) \ No newline at end of file diff --git a/subpacks(rolling)/AdvancementTips/mcdreforged.plugin.json b/subpacks(rolling)/AdvancementTips/mcdreforged.plugin.json new file mode 100644 index 0000000..9b07588 --- /dev/null +++ b/subpacks(rolling)/AdvancementTips/mcdreforged.plugin.json @@ -0,0 +1,15 @@ +{ + "id": "advancements_tips", + "version": "0.0.1", + "name": "AdvancementTips", + "description": { + "en_us": "A subpack of MatrixSync, send tips to the group when player finished advancements.", + "zh_cn": "MatrixSync的子包,在玩家完成成就时在群内进行提示。" + }, + "dependencies": { + "mcdreforged": ">=2.1.0", + "matrix_sync": ">=2.0.2" + }, + "author": "Mooling0602", + "link": "https://github.com/Mooling0602/MatrixSync-MCDR" +} \ No newline at end of file diff --git a/subpacks(rolling)/DeathTips/death_tips/__init__.py b/subpacks(rolling)/DeathTips/death_tips/__init__.py new file mode 100644 index 0000000..7bc75f2 --- /dev/null +++ b/subpacks(rolling)/DeathTips/death_tips/__init__.py @@ -0,0 +1,83 @@ +import asyncio +import re +import json +import matrix_sync.client + +from mcdreforged.api.all import * +from atl_api import parseKey, parseValue +from matrix_sync.reporter import sendMsg + +psi = ServerInterface.psi() + +lang_files = { + "raw_lang": "server/plugins/Geyser-Spigot/locales/en_us.json", + "translated_lang": "server/plugins/Geyser-Spigot/locales/zh_cn.json" +} + +config = psi.load_config_simple("config.json", lang_files) + +raw_lang = config["raw_lang"] +translated_lang = config["translated_lang"] + +death_messages = {} + +def on_load(server: PluginServerInterface, old): + server.logger.info("MatrixSync子包: DeathTips 已加载") + server.logger.info("本插件仅供简体中文用户使用") + server.logger.info("语言文件默认使用Geyser配置,若未使用Geyser请自行获取语言文件并配置其路径") + +def on_info(server: PluginServerInterface, info: Info): + global death_messages + if info.is_from_server: + key, groups = match_death_msg(raw_lang, info.content) + if key: + deathRawFormat = parseValue(raw_lang, key) + deathMsg = parseValue(translated_lang, key) + partten_deathRawFormat = re.compile(r"%(\d+)\$s") + matches_deathRawFormat = partten_deathRawFormat.findall(deathRawFormat) + regex_template = re.escape(deathRawFormat) + regex_template = regex_template.replace(r"%1\$s", r"(.+)").replace(r"%2\$s", r"(.+)").replace(r"%3\$s", r"\[(.+)\]|(.+)") + content_matches = re.match(regex_template, info.content) + if content_matches: + placeholder_to_content = {int(matches_deathRawFormat[i]): content_matches.group(i + 1) for i in range(len(matches_deathRawFormat))} + deathTip = deathMsg + for placeholder, content in placeholder_to_content.items(): + placeholder_str = f"%{placeholder}$s" + if placeholder_str == "%2$s": + contentKey = parseKey(raw_lang, content) + tr_content = parseValue(translated_lang, contentKey) + if tr_content is not None: + content = tr_content + else: + content = content + # if placeholder_str == "%3$s": + # content = re.escape(content) + deathTip = deathTip.replace(placeholder_str, content) + # 修正部分 + if re.fullmatch(r'(.+)被(.+) using \[(.+)\]|(.+)杀死了', deathTip): + match = re.fullmatch(r'(.+)被(.+) using (.+)杀死了', deathTip) + if match: + player = match.group(1) + killer = match.group(2) + weapon = match.group(3) + deathTip = f"{player}被{killer}用{weapon}杀死了" + clientStatus = matrix_sync.client.clientStatus + if clientStatus: + asyncio.run(sendMsg(deathTip)) + +def match_death_msg(lang, content): + global death_messages + with open(lang, 'r') as file: + lang = file.read() + lang = json.loads(lang) + for key in lang.keys(): + if key.startswith("death."): + value = lang.get(key, None) + if value: + value = re.sub(r'%(\d+)\$s', r'(?P.+)', value) + death_messages[key] = value + for key, value in death_messages.items(): + match = re.fullmatch(value, content) + if match: + return key, match.groupdict() + return None, None diff --git a/subpacks(rolling)/DeathTips/mcdreforged.plugin.json b/subpacks(rolling)/DeathTips/mcdreforged.plugin.json new file mode 100644 index 0000000..458e234 --- /dev/null +++ b/subpacks(rolling)/DeathTips/mcdreforged.plugin.json @@ -0,0 +1,16 @@ +{ + "id": "death_tips", + "version": "0.0.1", + "name": "DeathTips", + "description": { + "en_us": "A subpack of MatrixSync, send tips to the group when player finished advancements.", + "zh_cn": "MatrixSync的子包,在玩家死亡时在群内进行提示。" + }, + "dependencies": { + "mcdreforged": ">=2.1.0", + "matrix_sync": ">=2.0.2", + "atl_api": ">=0.0.1" + }, + "author": "Mooling0602", + "link": "https://github.com/Mooling0602/MatrixSync-MCDR" +} diff --git a/subpacks(rolling)/README.md b/subpacks(rolling)/README.md new file mode 100644 index 0000000..213d158 --- /dev/null +++ b/subpacks(rolling)/README.md @@ -0,0 +1,3 @@ +Subpacks for MatrixSync, rolling update + +MatrixSync的子包,滚动更新 diff --git a/subpacks(rolling)/[MSync]AutoReply/mcdreforged.plugin.json b/subpacks(rolling)/[MSync]AutoReply/mcdreforged.plugin.json new file mode 100644 index 0000000..6c3d31e --- /dev/null +++ b/subpacks(rolling)/[MSync]AutoReply/mcdreforged.plugin.json @@ -0,0 +1,15 @@ +{ + "id": "msync_auto_reply", + "version": "0.0.1", + "name": "[MSync]AutoReply", + "description": { + "en_us": "A subpack of MatrixSync, automatically reply messages from room.", + "zh_cn": "MatrixSync的子包,自动回复房间内消息" + }, + "dependencies": { + "mcdreforged": ">=2.1.0", + "matrix_sync": ">=2.3.1" + }, + "author": "Mooling0602", + "link": "https://github.com/Mooling0602/MatrixSync-MCDR" +} \ No newline at end of file diff --git a/subpacks(rolling)/[MSync]AutoReply/msync_auto_reply/__init__.py b/subpacks(rolling)/[MSync]AutoReply/msync_auto_reply/__init__.py new file mode 100644 index 0000000..d3cd5d7 --- /dev/null +++ b/subpacks(rolling)/[MSync]AutoReply/msync_auto_reply/__init__.py @@ -0,0 +1,18 @@ +import matrix_sync.config +import matrix_sync.client + +from mcdreforged.api.all import * +from matrix_sync.reporter import sender + +def on_load(server: PluginServerInterface, old): + server.logger.info("[MSync]AutoReply loaded.") + server.register_event_listener('MatrixRoomMessage', main) + +def main(server: PluginServerInterface, message: str, sender: str): + user_id = matrix_sync.config.user_id + if not sender == user_id: + if message == "服务器连接信息": + clientStatus = matrix_sync.client.clientStatus + if clientStatus: + sender("服务器名称:星块服务器\n地址:play.staringplanet.top\n* 已进行SRV解析,Java版无需添加端口\n端口:21152") + server.logger.info("解析到指定内容,已自动发送回复") diff --git a/subpacks(rolling)/[MSync]MoreMessages/MSync.MoreMessages.mcdr b/subpacks(rolling)/[MSync]MoreMessages/MSync.MoreMessages.mcdr new file mode 100644 index 0000000000000000000000000000000000000000..f660268b06b738f80669d4470eab40fefd2ff4fb GIT binary patch literal 1154 zcmWIWW@Zs#00GM_?vY>yl;8)_xy6-v$?>`QMXB+*#p(J1V8u)f91I^eyGP#mD0}fN zBLhPX3j>1`rsDYc%)HE!_;|g7%B_=p^KTpQw7vf)+M~a%+s|SBu}#(ddTdW-u(oAg zUS|+#q){0y@MM4gC-+Awy4z0IOkkW?^Yg>fkn7Q(93)(MZ}M5a^!%%J_hLws!I23L zzMg!(y(Z5?O%sz>9*sH?$GP(Bq;CSQdxJN$%3k7Ml73jIcTK>D+*z)Hy}S{@S=z6! z^lDnxTyJvFEEp0wqF8*-kjnMJS0;i5yUv<#7)`{Uh)woeEZp}f> z`a}HJmKO5`_egB_GWU(jjb9q)a(wkEsdUq6^KL|c3!1RpBu@X#5pUH>Ez z_TpWKg`dVO$Lz2b_kz6U*c{q^*V(97XUAOk$D6Y~e^_0gR@|aF>9VEZWs#S=JSM!} z`YDrX&9^CU=kwj{J@x3S*sLF)Us~Px$vr1b_T0y%Tw4!E3*D|xJ?kF!p)EZ!?UhyL ztD`f%OMIKnyvFc>$;$Z;g@xCuM=R>`#lN}X^k&c7$A6mb-Z!-^{<5k(sj5A7!i%Yy z>341)d|$=&T($Ch@Xzfg_i`S+v5($T75M+z#rfIFUzlfpH2lYgNCdkwTp}&ovfZqK ziC_Z|i-QtDa!OHZT7FS_YKmS#PHB2(o?cdQex7fDulHdC3A^q4m7dt#&TDFKYwBkwJmMUcV1d0tFpY7W|XSe13L+!llwPcRty@|NPO8`Su}| zW3eqOZBhdrb~ZGe64`E2z~dxzj^~x-yvys_b(SQkvH#nrCi837gXSrTT$_$1Pnf8% zGfIGcTWVs0qats*^vOlj+XLl4viw{q^yEm#mI*?NlQ}t3{shk75HU;i7RO?jg02uY zjjQkaK5qOFDdtkTZR&-Zs!+T8(;mORfBxh7>%o>gSHHV|>iEk)Ul-TxxR_x&J9M$< zSG!euar@5eZ_MQtpIMw>xS^vVrfpfEj>1Ew)?M?~p6$C_W|P}Ht3C6r^o)Dcq+jn^ z;%2N9a?EvZ|7YbxLHUPYo0P2iU(1~8^>owgU7CTB7mJnr?$+Oa_iB@AeR?_n?Zfr~ z-i%E4%((L?G`ljqbp)|6ax6qMt~?9VyrfYVQ!`QyhB*Rc4z_4Vm}A6*GZ6%Mv$BB{ OG6Uf$Aiang!~+0$-s4UH literal 0 HcmV?d00001 diff --git a/subpacks(rolling)/[MSync]MoreMessages/mcdreforged.plugin.json b/subpacks(rolling)/[MSync]MoreMessages/mcdreforged.plugin.json new file mode 100644 index 0000000..9dbffdd --- /dev/null +++ b/subpacks(rolling)/[MSync]MoreMessages/mcdreforged.plugin.json @@ -0,0 +1,15 @@ +{ + "id": "msync_more_msg", + "version": "0.0.1", + "name": "[MSync]MoreMessages", + "description": { + "en_us": "A subpack of MatrixSync, transfer more kinds of messages from the game.", + "zh_cn": "MatrixSync的子包,转发更多类型的游戏消息。" + }, + "dependencies": { + "mcdreforged": ">=2.1.0", + "matrix_sync": ">=2.3.1" + }, + "author": "Mooling0602", + "link": "https://github.com/Mooling0602/MatrixSync-MCDR" +} \ No newline at end of file diff --git a/subpacks(rolling)/[MSync]MoreMessages/msync_more_msg/__init__.py b/subpacks(rolling)/[MSync]MoreMessages/msync_more_msg/__init__.py new file mode 100644 index 0000000..a359dc7 --- /dev/null +++ b/subpacks(rolling)/[MSync]MoreMessages/msync_more_msg/__init__.py @@ -0,0 +1,34 @@ +import re + +from matrix_sync.reporter import sender +from mcdreforged.api.all import * + +psi = ServerInterface.psi() + +def on_load(server: PluginServerInterface, old): + server.logger.info("Subpack of MatrixSync: [Msync]MoreMessages loaded.") + +def on_user_info(server: PluginServerInterface, info: Info): + formatter(info) + if gameMsg is not None: + sender(gameMsg) + + +def formatter(info: Info): + global gameMsg + console_tr = psi.rtr("matrix_sync.tr.cs") + if info.player is None: + if re.fullmatch(r'say \S*', info.content): + msg_content = '{}'.format(info.content.rsplit(' ', 1)[1]) + gameMsg = f"<{console_tr}> {msg_content}" + else: + option = psi.rtr("matrix_sync.on_console.commands") + gameMsg = f"[!] {console_tr} {option} -> {info.content}" + if info.content == "stop": + gameMsg = psi.rtr("matrix_sync.sync_tips.server_stopping") + else: + if info.content.startswith("!!"): + option = psi.rtr("matrix_sync.on_console.commands") + gameMsg = f"[!] {info.player} {option} -> {info.content}" + else: + return None \ No newline at end of file diff --git a/subpacks(rolling)/[MSync]PlayerBind/.temp b/subpacks(rolling)/[MSync]PlayerBind/.temp new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/subpacks(rolling)/[MSync]PlayerBind/.temp @@ -0,0 +1 @@ + diff --git a/subpacks(rolling)/[MSync]PlayingTips/MSync.PlayingTips.mcdr b/subpacks(rolling)/[MSync]PlayingTips/MSync.PlayingTips.mcdr new file mode 100644 index 0000000000000000000000000000000000000000..e0d3a9b8ab49f8af8215c78ef6578cd2474c724a GIT binary patch literal 1140 zcmWIWW@Zs#0D&_*+#|sZC?O1_bBinUlH&_<5-T(F(&I}q3ySpvz#5nsI2e?-xkqM( z9c-G;$iQIE!oVPhT|<0)W?p7Ve7s&k<=UXrUPlZ>?ta(SyX&($*46)d?hMKksi)5BTHI!9!-iMz6ROLu&_2@k;i6^JDd(GA(6Yfy_Zd@xDa!7#+`K6ZZrsHmXWAV6{f&<$s|A}_{G0eb z<|3i(tmn2Zxf#pcotw<$_~H!vbc=Po{Y^%{x!Yf_ceYX8{Igbck&3|^}bNYb!SGK*xenCD^?Yq;Hg|OL+AyyO&cl|DU@kj)>BxtyYmnA&cXKfl+!2 zh{Zusnw(OUnwDRbo|>XpkW-qTnWvXkoS)}A!O;7#gUIpcPl9F4udBR$5D*{`%e^R1 zNzr%R$(zsg?!;b+;!?Wi*j=W*qWgj)yR5fnl6{Zw<+JM_#9j)>-~IjH|L=AGuU|Cn zu#I3fc#`|*R^aK(lQ z$6e`rX^C%h#|^{qX|e|%S3TL`>ma@08AqG`l^&r79Tg61S(}&y6&@H%xj(RRVA0Sz zazOJaOXY!yhs3fvVpIcpwuUxOZ+x4!;Pu9rmwi7Odi>gZe|_DjPt)x7sLy}=^GTlF zPXFbbj~1-yy1)3zw(WCl_2YkcA9u8x^)DvYIrjClK&6wd9o>TZn_AW#4`?=$Pi?<_ zZcW4@MdJPXU3fyp&66mts{tqHE%);z?C~;1}teb#BKmm jUWGXZWEQq$fiR1O31=b+@MdKLDP#u1OF+7Z8N>qsn%v3+ literal 0 HcmV?d00001 diff --git a/subpacks(rolling)/[MSync]PlayingTips/mcdreforged.plugin.json b/subpacks(rolling)/[MSync]PlayingTips/mcdreforged.plugin.json new file mode 100644 index 0000000..9c30315 --- /dev/null +++ b/subpacks(rolling)/[MSync]PlayingTips/mcdreforged.plugin.json @@ -0,0 +1,15 @@ +{ + "id": "msync_playing_tips", + "version": "0.0.1", + "name": "[MSync]PlayingTips", + "description": { + "en_us": "A subpack of MatrixSync, send tips to the group when player joined and left the game.", + "zh_cn": "MatrixSync的子包,在玩家上下线时在群内进行提示。" + }, + "dependencies": { + "mcdreforged": ">=2.1.0", + "matrix_sync": ">=2.3.1" + }, + "author": "Mooling0602", + "link": "https://github.com/Mooling0602/MatrixSync-MCDR" +} \ No newline at end of file diff --git a/subpacks(rolling)/[MSync]PlayingTips/msync_playing_tips/__init__.py b/subpacks(rolling)/[MSync]PlayingTips/msync_playing_tips/__init__.py new file mode 100644 index 0000000..782399f --- /dev/null +++ b/subpacks(rolling)/[MSync]PlayingTips/msync_playing_tips/__init__.py @@ -0,0 +1,28 @@ +import matrix_sync.client +import re +from matrix_sync.reporter import sender +from mcdreforged.api.all import * + +def on_load(server: PluginServerInterface, old): + server.logger.info("Subpack of MatrixSync: [MSync]PlayingTips loaded.") + +def on_player_joined(server: PluginServerInterface, player: str, info: Info): + tip = f"[+]{player}" + if matrix_sync.client.clientStatus: + sender(tip) + +def on_player_left(server: PluginServerInterface, player: str): + tip = f"[-]{player}" + if matrix_sync.client.clientStatus: + sender(tip) + +def on_info(server: PluginServerInterface, info: Info): + if info.is_from_server and re.fullmatch(r'(.+) issued server command: (.+)', info.content): + match = re.fullmatch(r'(.+) issued server command: (.+)', info.content) + if match: + player = match.group(1) + command = match.group(2) + server.say(f"* {player} 执行游戏指令 -> {command}") + clientStatus = matrix_sync.client.clientStatus + if clientStatus: + sender(f"* {player} 执行游戏指令 -> {command}") \ No newline at end of file diff --git a/subpacks(rolling)/[MSync]plgDebugger/mcdreforged.plugin.json b/subpacks(rolling)/[MSync]plgDebugger/mcdreforged.plugin.json new file mode 100644 index 0000000..76c68d9 --- /dev/null +++ b/subpacks(rolling)/[MSync]plgDebugger/mcdreforged.plugin.json @@ -0,0 +1,15 @@ +{ + "id": "msync_debugger", + "version": "0.0.1", + "name": "[MSync]plgDebugger", + "description": { + "en_us": "A subpack of MatrixSync, used to debug.", + "zh_cn": "MatrixSync的子包,用于调试。" + }, + "dependencies": { + "mcdreforged": ">=2.1.0", + "matrix_sync": ">=2.0.2" + }, + "author": "Mooling0602", + "link": "https://github.com/Mooling0602/MatrixSync-MCDR" +} \ No newline at end of file diff --git a/subpacks(rolling)/[MSync]plgDebugger/msync_debugger/__init__.py b/subpacks(rolling)/[MSync]plgDebugger/msync_debugger/__init__.py new file mode 100644 index 0000000..9b97f61 --- /dev/null +++ b/subpacks(rolling)/[MSync]plgDebugger/msync_debugger/__init__.py @@ -0,0 +1,12 @@ +from mcdreforged.api.all import * +from typing import Optional + +def on_load(server: PluginServerInterface, old): + server.logger.info("Subpack of MatrixSync: [MSync]plgDebugger loaded.") + server.register_event_listener('MatrixRoomMessage', main) + +def main(server: PluginServerInterface, message: str, sender: str, room: Optional[str] = None): + server.logger.info(f"Content: {message}") + server.logger.info(f"Sender: {sender}") + if room is not None: + server.logger.info(f"Room Name: {room}") \ No newline at end of file