-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit c7b4e86
Showing
9 changed files
with
816 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
|
||
# Mac OS | ||
.DS_Store | ||
|
||
# output | ||
/output/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"id": "smart_backup", | ||
"version": "0.0.1", | ||
"name": "SmartBackup", | ||
"description": "A Minecraft Backup Plugin", | ||
"author": "zyxkad", | ||
"link": "https://github.com/zyxkad/smart_backup_mcdr", | ||
"dependencies": { | ||
"mcdreforged": ">=2.0.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#!/bin/bash | ||
|
||
COMMIT=true | ||
RELEASE=true | ||
|
||
while [ -n "$1" ]; do | ||
case $1 in | ||
-n | --no-commit) | ||
COMMIT='' | ||
;; | ||
-R | --no-release) | ||
RELEASE='' | ||
;; | ||
esac | ||
shift | ||
done | ||
|
||
cd $(dirname $0) | ||
|
||
echo '==> Reading plugin metadata...' | ||
data=($(python3 -c 'import sys,json;o=json.load(open("mcdreforged.plugin.json","r"));n=o["name"];d=o["id"];v=o["version"];an=o.get("archive_name");print(((n and n.replace(" ", ""))or d)+"-v"+v if not an else an.format(id=d,version=v));print(v)')) | ||
if [ $? -ne 0 ]; then | ||
echo '[ERROR] Cannot parse "mcdreforged.plugin.json"' | ||
exit 1 | ||
fi | ||
name="${data[0]}" | ||
version="v${data[1]}" | ||
|
||
echo '==> Packing source files...' | ||
python3 -m mcdreforged pack -o ./output -n "$name" || exit $? | ||
|
||
if [ -n "$COMMIT" ]; then | ||
|
||
echo '==> Commiting git repo...' | ||
( git add . && git commit -m "$version" && git push ) || exit $? | ||
|
||
if [ -n "$RELEASE" ]; then | ||
|
||
echo '==> Creating github release...' | ||
gh release create "$version" "./output/${name}.mcdr" -t "$version" -n '' || exit $? | ||
|
||
fi | ||
fi | ||
|
||
echo '==> Done' |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
|
||
import mcdreforged.api.all as MCDR | ||
from .utils import * | ||
from . import globals as GL | ||
from . import commands as CMD | ||
|
||
def on_load(server: MCDR.PluginServerInterface, prev_module): | ||
if prev_module is None: | ||
log_info('Smart backup is on LOAD') | ||
else: | ||
log_info('Smart backup is on RELOAD') | ||
GL.init(server) | ||
CMD.register(server) | ||
|
||
def on_unload(server: MCDR.PluginServerInterface): | ||
log_info('Smart backup is on UNLOAD') | ||
GL.destory() | ||
|
||
def on_info(server: MCDR.ServerInterface, info: MCDR.Info): | ||
CMD.on_info(server, info) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
|
||
import mcdreforged.api.all as MCDR | ||
from .utils import * | ||
from . import globals as GL | ||
from .objects import * | ||
|
||
Prefix = '!!smb' | ||
|
||
HelpMessage = ''' | ||
{0} help 显示帮助信息 | ||
{0} list [<limit>] 列出[所有/<limit>条]备份 | ||
{0} query <id> 查询备份详细信息 | ||
{0} make [<comment>] 创建新备份(差异/全盘) | ||
{0} makefull [<comment>] 创建全盘备份 | ||
{0} rm <id> [force] 删除指定备份(及其子备份) | ||
{0} restore [<id>] 回档至[上次/指定id]备份 | ||
{0} confirm 确认操作 | ||
{0} abort 取消操作 | ||
{0} reload 重新加载配置文件 | ||
{0} save 保存配置文件 | ||
'''.strip().format(Prefix) | ||
|
||
game_saved_callback = None | ||
|
||
def on_info(server: MCDR.ServerInterface, info: MCDR.Info): | ||
if not info.is_user: | ||
global game_saved_callback | ||
if game_saved_callback is not None and GL.Config.test_backup_trigger(info.content): | ||
c, game_saved_callback = game_saved_callback, None | ||
c() | ||
|
||
def register(server: MCDR.PluginServerInterface): | ||
server.register_command( | ||
MCDR.Literal(Prefix). | ||
runs(command_help). | ||
then(GL.Config.literal('help').runs(command_help)). | ||
then(GL.Config.literal('list'). | ||
runs(lambda src: command_list_backup(src, 10)). | ||
then(MCDR.Integer('limit').at_min(0). | ||
runs(lambda src, ctx: command_list_backup(src, ctx['limit'])))). | ||
then(GL.Config.literal('query'). | ||
then(MCDR.Text('id'). | ||
runs(lambda src, ctx: command_query_backup(src, ctx['id'])))). | ||
then(GL.Config.literal('make'). | ||
runs(lambda src: command_make(src, 'None')). | ||
then(MCDR.GreedyText('comment').runs(lambda src, ctx: command_make(src, ctx['comment'])))). | ||
then(GL.Config.literal('makefull'). | ||
runs(lambda src: command_makefull(src, 'None')). | ||
then(MCDR.GreedyText('comment').runs(lambda src, ctx: command_makefull(src, ctx['comment'])))). | ||
then(GL.Config.literal('confirm').runs(command_confirm)). | ||
then(GL.Config.literal('abort').runs(command_abort)). | ||
then(GL.Config.literal('reload').runs(command_config_load)). | ||
then(GL.Config.literal('save').runs(command_config_save)) | ||
) | ||
|
||
def command_help(source: MCDR.CommandSource): | ||
send_block_message(source, HelpMessage) | ||
|
||
def command_list_backup(source: MCDR.CommandSource, limit: int): | ||
send_message(source, 'TODO: list "{}" backup'.format(limit)) | ||
|
||
@new_thread | ||
def command_query_backup(source: MCDR.CommandSource, bid: str): | ||
send_message(source, 'TODO: query backup "{}"'.format(bid)) | ||
|
||
@new_thread | ||
@new_job('make backup') | ||
def command_make(source: MCDR.CommandSource, comment: str): | ||
server = source.get_server() | ||
send_message(source, 'Making backup "{}"'.format(comment), log=True) | ||
tuple(map(server.execute, GL.Config.befor_backup)) | ||
|
||
def call(): | ||
mode = BackupMode.FULL | ||
if 'differential_count' not in GL.Config.cache or GL.Config.cache['differential_count'] >= GL.Config.differential_backup_limit: | ||
GL.Config.cache['differential_count'] = 0 | ||
else: | ||
mode = BackupMode.DIFFERENTIAL | ||
GL.Config.cache['differential_count'] += 1 | ||
backup = Backup.create(mode, comment, | ||
source.get_server().get_mcdr_config()['working_directory'], GL.Config.backup_needs, GL.Config.backup_ignores) | ||
tuple(map(server.execute, GL.Config.after_backup)) | ||
send_message(source, 'Saving backup "{}"'.format(comment), log=True) | ||
backup.save(GL.Config.backup_path) | ||
send_message(source, 'Saved backup "{}"'.format(comment), log=True) | ||
|
||
if len(GL.Config.start_backup_trigger_info) > 0: | ||
begin_job() | ||
global game_saved_callback | ||
game_saved_callback = new_thread(lambda: (call(), after_job())) | ||
else: | ||
call() | ||
|
||
@new_thread | ||
@new_job('make full backup') | ||
def command_makefull(source: MCDR.CommandSource, comment: str): | ||
server = source.get_server() | ||
|
||
def call(): | ||
backup = Backup.create(BackupMode.FULL, comment, | ||
source.get_server().get_mcdr_config()['working_directory'], GL.Config.backup_needs, GL.Config.backup_ignores) | ||
tuple(map(server.execute, GL.Config.after_backup)) | ||
send_message(source, 'Saving backup "{}"'.format(comment), log=True) | ||
backup.save(GL.Config.backup_path) | ||
send_message(source, 'Saved backup "{}"'.format(comment), log=True) | ||
|
||
begin_job() | ||
global game_saved_callback | ||
game_saved_callback = new_thread(lambda: (call(), after_job())) | ||
|
||
send_message(source, 'Making full backup "{}"'.format(comment), log=True) | ||
tuple(map(server.execute, GL.Config.befor_backup)) | ||
|
||
|
||
def command_confirm(source: MCDR.CommandSource): | ||
confirm_map.pop(source.player if source.is_player else '', (lambda s: send_message(s, '当前没有正在执行的操作'), 0))[0](source) | ||
|
||
def command_abort(source: MCDR.CommandSource): | ||
c = confirm_map.pop(source.player if source.is_player else '', (0, 0))[1] | ||
if not c: | ||
c = confirm_map.pop(None, (0, lambda s: send_message(s, '当前没有正在执行的操作')))[1] | ||
c(source) | ||
|
||
@new_thread | ||
def command_config_load(source: MCDR.CommandSource): | ||
GL.Config = server.load_config_simple(target_class=GL.SMBConfig, source_to_reply=source) | ||
|
||
@new_thread | ||
def command_config_save(source: MCDR.CommandSource): | ||
GL.Config.save() | ||
send_message(source, 'Save config file SUCCESS') | ||
|
||
confirm_map = {} | ||
|
||
def __warp_call(call): | ||
def c(*b): | ||
return call(*b[:call.__code__.co_argcount]) | ||
return c | ||
|
||
def register_confirm(player: str, confirm_call, abort_call=lambda: 0): | ||
confirm_map[player] = (__warp_call(confirm_call), __warp_call(abort_call)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
|
||
import re | ||
from typing import List, Dict, Any | ||
|
||
import mcdreforged.api.all as MCDR | ||
|
||
__all__ = [ | ||
'MSG_ID', 'BIG_BLOCK_BEFOR', 'BIG_BLOCK_AFTER', 'SMBConfig', 'Config', 'SERVER_INS', 'init', 'destory' | ||
] | ||
|
||
MSG_ID = MCDR.RText('[SMB]', color=MCDR.RColor.green) | ||
BIG_BLOCK_BEFOR = '------------ {0} v{1} ::::' | ||
BIG_BLOCK_AFTER = ':::: {0} v{1} ============' | ||
|
||
class SMBConfig(MCDR.Serializable): | ||
differential_backup_limit: int = 10 | ||
full_backup_limit: int = 10 | ||
backup_interval: int = 60 * 60 * 1 # 1 hours | ||
last_backup_time: int = 0 | ||
restore_timeout: int = 30 | ||
backup_path: str = './smt_backups' | ||
overwrite_path: str = './smt_backup_overwrite' | ||
backup_needs: List[str] = ['world'] | ||
backup_ignores: List[str] = ['session.lock'] | ||
befor_backup: List[str] = ['save-off', 'save-all flush'] | ||
start_backup_trigger_info: str = r'Saved the (?:game|world)' | ||
after_backup: List[str] = ['save-on'] | ||
# 0:guest 1:user 2:helper 3:admin 4:owner | ||
minimum_permission_level: Dict[str, int] = { | ||
'help': 0, | ||
'status': 1, | ||
'list': 1, | ||
'make': 2, | ||
'makefull': 3, | ||
'back': 3, | ||
'confirm': 1, | ||
'abort': 1, | ||
'reload': 3, | ||
'save': 3, | ||
} | ||
_cache: Dict[str, Any] = {} | ||
|
||
def test_backup_trigger(self, info: str): | ||
if not hasattr(self, '__start_backup_trigger') or self.__start_backup_trigger_info != self.start_backup_trigger_info: | ||
self.__start_backup_trigger_info = self.start_backup_trigger_info | ||
self.__start_backup_trigger = re.compile(self.start_backup_trigger_info) | ||
return self.__start_backup_trigger.fullmatch(info) is not None | ||
|
||
@property | ||
def cache(self): | ||
return self._cache | ||
|
||
def literal(self, literal: str): | ||
lvl = self.minimum_permission_level.get(literal, 0) | ||
return MCDR.Literal(literal).requires(lambda src: src.has_permission(lvl), | ||
lambda: MCDR.RText(MSG_ID.to_plain_text() + ' 权限不足', color=MCDR.RColor.red)) | ||
|
||
def save(self): | ||
SERVER_INS.save_config_simple(self) | ||
|
||
|
||
Config: SMBConfig = SMBConfig() | ||
SERVER_INS: MCDR.PluginServerInterface = None | ||
|
||
def init(server: MCDR.PluginServerInterface): | ||
global SERVER_INS | ||
SERVER_INS = server | ||
global BIG_BLOCK_BEFOR, BIG_BLOCK_AFTER | ||
metadata = server.get_self_metadata() | ||
BIG_BLOCK_BEFOR = BIG_BLOCK_BEFOR.format(metadata.name, metadata.version) | ||
BIG_BLOCK_AFTER = BIG_BLOCK_AFTER.format(metadata.name, metadata.version) | ||
global Config | ||
Config = server.load_config_simple(target_class=SMBConfig) | ||
|
||
def destory(): | ||
global SERVER_INS | ||
Config.save() | ||
SERVER_INS = None |
Oops, something went wrong.