From d73fef602484cb963a3c4c314f970af1a39e69c2 Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Mon, 26 Feb 2024 20:32:32 +0800 Subject: [PATCH 01/17] Update __init__.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复了在服务器无响应时,备份时产生线程阻塞的问题 --- region_backup/__init__.py | 57 ++++++++++++++++++++++++++++++++------- 1 file changed, 47 insertions(+), 10 deletions(-) diff --git a/region_backup/__init__.py b/region_backup/__init__.py index 3571643..866dd0c 100644 --- a/region_backup/__init__.py +++ b/region_backup/__init__.py @@ -32,6 +32,8 @@ back_state = None # 回档槽位 back_slot = None +# 超时 +time_out = 5 help_msg = ''' ------ {1} {2} ------ @@ -47,7 +49,7 @@ #sc=!!rb abort<>st=点击运行指令#§7{0} abort §a§l[▷] §e在任何时候键入此指令可中断回档 #sc=!!rb list<>st=点击运行指令#§7{0} list §a§l[▷] §e显示各槽位的存档信息 #sc=!!rb reload<>st=点击运行指令#§7{0} reload §a§l[▷] §e重载插件 -'''.format(Prefix, "Region BackUp", "1.0.0") +'''.format(Prefix, "Region BackUp", "1.2.0") def print_help_msg(source: CommandSource): @@ -75,8 +77,11 @@ def rb_make(source: InfoCommandSource, dic: dict): return source.get_server().broadcast("[RBU] §a备份§f中...请稍等") - t1 = time.time() + get_user_info(source) + if not data_list: + return + while len(data_list) < 4: time.sleep(0.01) @@ -88,11 +93,25 @@ def rb_make(source: InfoCommandSource, dic: dict): # 保存游戏 source.get_server().execute("save-off") + t1 = time.time() while backup_state != 1: + if time.time() - t1 > time_out: + source.get_server().broadcast("[RBU] §c备份§f超时,已取消备份") + source.get_server().execute("save-on") + backup_state = None + user = None + return time.sleep(0.01) source.get_server().execute("save-all flush") + t1 = time.time() while backup_state != 2: + if time.time() - t1 > time_out: + source.get_server().broadcast("[RBU] §c备份§f超时,已取消备份") + source.get_server().execute("save-on") + backup_state = None + user = None + return time.sleep(0.01) user = None @@ -125,7 +144,7 @@ def rb_make(source: InfoCommandSource, dic: dict): @new_thread("rb_pos_make") def rb_pos_make(source: InfoCommandSource, dic: dict): - global backup_state, user + global backup_state try: if backup_state is None: @@ -150,16 +169,26 @@ def rb_pos_make(source: InfoCommandSource, dic: dict): t1 = time.time() backup_pos = get_backup_pos(pos_list=[(int(x1 // 512), int(x2 // 512)), (int(z1 // 512), int(z2 // 512))]) - user = source.get_info().is_user # 保存游戏 source.get_server().execute("save-off") + t1 = time.time() while backup_state != 1: + if time.time() - t1 > time_out: + source.get_server().broadcast("[RBU] §c备份§f超时,已取消备份") + source.get_server().execute("save-on") + backup_state = None + return time.sleep(0.01) source.get_server().execute("save-all flush") + t1 = time.time() while backup_state != 2: + if time.time() - t1 > time_out: + source.get_server().broadcast("[RBU] §c备份§f超时,已取消备份") + source.get_server().execute("save-on") + backup_state = None + return time.sleep(0.01) - user = None valid_pos = search_valid_pos(dim, backup_pos) if all(not v for v in valid_pos.values()): @@ -187,7 +216,6 @@ def rb_pos_make(source: InfoCommandSource, dic: dict): return except Exception as e: - user = None backup_state = None source.reply(f"备份出错,错误信息:§c{e}") source.get_server().execute("save-on") @@ -208,7 +236,13 @@ def get_user_info(source): source.get_server().execute(f"data get entity {user} Pos") source.get_server().execute(f"data get entity {user} Dimension") + t1 = time.time() while len(data_list) < 2: + if time.time() - t1 >= time_out: + data_list.clear() + user = None + source.reply("§c获取用户信息超时,请重试") + return time.sleep(0.01) data_list.append([float(pos.strip('d')) for pos in data_list[0].strip("[]").split(',')]) @@ -308,10 +342,14 @@ def on_server_stop(server: PluginServerInterface, server_return_code: int): if get_file_size([os.path.join(slot_path.format(back_slot), backup_file)])[-1]: lst = os.listdir(os.path.join(slot_path.format(back_slot), backup_file)) for i in lst: + # 复制即将被替换的区域到overwrite shutil.copy2(os.path.join(path, backup_file, i), os.path.join(extra_slot, backup_file, i)) - + # 将备份的区域对存档里对应的区域替换 shutil.copy2(os.path.join(slot_path.format(back_slot), backup_file, i), os.path.join(path, backup_file, i)) + # 复制本次回档槽位的info文件到overwrite + shutil.copy2(os.path.join(slot_path.format(back_slot), "info.json"), + os.path.join(extra_slot, "info.json")) back_slot = None @@ -351,7 +389,7 @@ def rb_abort(source: CommandSource): back_state = True -def rb_confirm(source:CommandSource): +def rb_confirm(source: CommandSource): global back_state if back_state is None: source.reply("没有什么可确认的") @@ -451,8 +489,7 @@ def get_backup_pos(r=None, x=None, z=None, pos_list=None): backup_pos = [] if not pos_list: - - return get_backup_pos(pos_list=[((x - r)//32, (x + r)//32), ((z + r)//32, (z - r)//32)]) + return get_backup_pos(pos_list=[((x - r) // 32, (x + r) // 32), ((z + r) // 32, (z - r) // 32)]) left = min(pos_list[0]) right = max(pos_list[0]) From dbe5386aac956d14ea1d05a03790da0cc6383e7e Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Mon, 26 Feb 2024 21:53:43 +0800 Subject: [PATCH 02/17] Update __init__.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit bug修复 --- region_backup/__init__.py | 83 ++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 36 deletions(-) diff --git a/region_backup/__init__.py b/region_backup/__init__.py index 866dd0c..a1969b6 100644 --- a/region_backup/__init__.py +++ b/region_backup/__init__.py @@ -66,10 +66,11 @@ def rb_make(source: InfoCommandSource, dic: dict): return if backup_state is None: backup_state = False - text = dic["r_comment"] - lst = text.split() - r = int(lst[0]) + if "cmt" not in dic: + dic["cmt"] = "§7空" + + r = int(dic["r"]) if r < 0: source.reply("§c备份半径应为大于等于0的整数!") @@ -79,10 +80,15 @@ def rb_make(source: InfoCommandSource, dic: dict): source.get_server().broadcast("[RBU] §a备份§f中...请稍等") get_user_info(source) - if not data_list: - return + t = time.time() while len(data_list) < 4: + if time.time() - t > time_out: + source.get_server().broadcast("[RBU] §c备份§f超时,已取消备份") + source.get_server().execute("save-on") + backup_state = None + user = None + return time.sleep(0.01) data = data_list.copy() @@ -121,12 +127,12 @@ def rb_make(source: InfoCommandSource, dic: dict): copy_files(valid_pos, data[-1]) - make_info_file(data=data) + make_info_file(dic["cmt"], data=data) t2 = time.time() - source.get_server().broadcast(f"[RBU] §a备份§f完成,耗时§6{(t2 - t1):.2f}§f秒") + source.get_server().broadcast(f"[RBU] §a备份§f完成,耗时§6{(t2 - t):.2f}§f秒") source.get_server().broadcast( - f"[RBU] 日期: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}; 注释: {text.split(maxsplit=1)[-1] if len(text.split()) > 1 else '§7空'}") + f"[RBU] 日期: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}; 注释: {dic['cmt']}") source.get_server().execute("save-on") backup_state = None @@ -144,17 +150,17 @@ def rb_make(source: InfoCommandSource, dic: dict): @new_thread("rb_pos_make") def rb_pos_make(source: InfoCommandSource, dic: dict): - global backup_state + global backup_state, user try: if backup_state is None: backup_state = False x1, z1, x2, z2 = dic["x1"], dic["z1"], dic["x2"], dic["z2"] - text = dic["dim_comment"] - lst = text.split() + if "cmt" not in dic: + dic["cmt"] = "§7空" - dim = int(lst[0]) + dim = dic["dim"] if dim == 0: dim = "overworld" @@ -162,13 +168,17 @@ def rb_pos_make(source: InfoCommandSource, dic: dict): elif dim == 1: dim = "the_end" - else: + elif dim == -1: dim = "the_nether" + else: + source.reply("§c维度输入错误!") + return + source.get_server().broadcast("[RBU] §a备份§f中...请稍等") - t1 = time.time() backup_pos = get_backup_pos(pos_list=[(int(x1 // 512), int(x2 // 512)), (int(z1 // 512), int(z2 // 512))]) + user = source.get_info().is_user # 保存游戏 source.get_server().execute("save-off") t1 = time.time() @@ -177,6 +187,7 @@ def rb_pos_make(source: InfoCommandSource, dic: dict): source.get_server().broadcast("[RBU] §c备份§f超时,已取消备份") source.get_server().execute("save-on") backup_state = None + user = None return time.sleep(0.01) @@ -187,8 +198,11 @@ def rb_pos_make(source: InfoCommandSource, dic: dict): source.get_server().broadcast("[RBU] §c备份§f超时,已取消备份") source.get_server().execute("save-on") backup_state = None + user = None return time.sleep(0.01) + + user = None valid_pos = search_valid_pos(dim, backup_pos) if all(not v for v in valid_pos.values()): @@ -200,16 +214,15 @@ def rb_pos_make(source: InfoCommandSource, dic: dict): copy_files(valid_pos, dim) - make_info_file(backup_dim=dim, + make_info_file(dic["cmt"], backup_dim=dim, user_=source.get_info().player if source.get_info().player else "from_console", - cmd=source.get_info().content, - cmt="§7空" if len(text.split()) < 2 else text.split(maxsplit=1)[-1] + cmd=source.get_info().content ) t2 = time.time() source.get_server().broadcast(f"[RBU] §a备份§f完成,耗时§6{(t2 - t1):.2f}§f秒") source.get_server().broadcast( - f"[RBU] 日期: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}; 注释: {text.split(maxsplit=1)[-1] if len(text.split()) > 1 else '§7空'}") + f"[RBU] 日期: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}; 注释: {dic['cmt']}") source.get_server().execute("save-on") backup_state = None @@ -217,6 +230,7 @@ def rb_pos_make(source: InfoCommandSource, dic: dict): except Exception as e: backup_state = None + user = None source.reply(f"备份出错,错误信息:§c{e}") source.get_server().execute("save-on") return @@ -238,10 +252,7 @@ def get_user_info(source): t1 = time.time() while len(data_list) < 2: - if time.time() - t1 >= time_out: - data_list.clear() - user = None - source.reply("§c获取用户信息超时,请重试") + if time.time() - t1 > time_out: return time.sleep(0.01) @@ -253,6 +264,10 @@ def get_user_info(source): def rb_back(source: InfoCommandSource, dic: dict): global back_state, back_slot # 判断槽位非空 + + if not dic: + dic["slot"] = 1 + if not os.path.exists(os.path.join(slot_path.format(dic["slot"]), "info.json")): source.reply("§c该槽位无info.json文件,无法回档") return @@ -511,7 +526,7 @@ def check_folder(): os.makedirs(backup_path, exist_ok=True) -def make_info_file(data=None, backup_dim=None, user_=None, cmd=None, cmt=None): +def make_info_file(cmt, data=None, backup_dim=None, user_=None, cmd=None): file_path = os.path.join(slot_path.format(1), "info.json") info = rb_info.get_default().serialize() @@ -521,15 +536,7 @@ def make_info_file(data=None, backup_dim=None, user_=None, cmd=None, cmt=None): info["user"] = data[0] if not user_ else user_ info["user_pos"] = ",".join(str(pos) for pos in data[2]) if not user_ else "无" info["command"] = data[1] if not cmd else cmd - if not cmt: - if len(data[1].split(maxsplit=2)[-1].split()) > 1: - info["comment"] = data[1].split(maxsplit=3)[-1] - - else: - info["comment"] = "§7空" - - else: - info["comment"] = cmt + info["comment"] = cmt with codecs.open(file_path, "w", encoding="utf-8-sig") as fp: json.dump(info, fp, ensure_ascii=False, indent=4) @@ -632,21 +639,25 @@ def on_load(server: PluginServerInterface, old): builder = SimpleCommandBuilder() builder.command("!!rb", print_help_msg) - builder.command("!!rb make ", rb_make) - builder.command("!!rb pos_make ", rb_pos_make) + builder.command("!!rb make ", rb_make) + builder.command("!!rb make ", rb_make) + builder.command("!!rb pos_make ", rb_pos_make) + builder.command("!!rb pos_make ", rb_pos_make) builder.command("!!rb back ", rb_back) + builder.command("!!rb back", rb_back) builder.command("!!rb confirm", rb_confirm) builder.command("!!rb del ", rb_del) builder.command("!!rb abort", rb_abort) builder.command("!!rb list", rb_list) builder.command("!!rb reload", rb_reload) - builder.arg("r_comment", GreedyText) builder.arg("x1", Number) builder.arg("z1", Number) builder.arg("x2", Number) builder.arg("z2", Number) - builder.arg("dim_comment", GreedyText) + builder.arg("dim", Integer) + builder.arg("r", Integer) + builder.arg("cmt", GreedyText) builder.arg("slot", Integer) command_literals = ["make", "pos_make", "back", "confirm", "del", "abort", "list", "reload"] From bf84d8d592bf3f46c440355949429bd23d67a540 Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Tue, 27 Feb 2024 01:33:02 +0800 Subject: [PATCH 03/17] Update config.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 更新配置文件 --- region_backup/config.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/region_backup/config.py b/region_backup/config.py index 0c1267a..1a80ba9 100644 --- a/region_backup/config.py +++ b/region_backup/config.py @@ -18,7 +18,9 @@ class rb_config(Serializable): minimum_permission_level: Dict[str, int] = { "make": 1, "pos_make": 1, + "dim_make": 1, "back": 2, + "restore": 2, "del": 2, "confirm": 1, "abort": 1, @@ -26,3 +28,4 @@ class rb_config(Serializable): "list": 0 } slot: int = 5 + From ff87b15a14d8d0cffdeed194ffa330ab080d608c Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Tue, 27 Feb 2024 01:34:57 +0800 Subject: [PATCH 04/17] Update __init__.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复了一些bug,更新了两条指令 --- region_backup/__init__.py | 211 ++++++++++++++++++++++++++++++++------ 1 file changed, 181 insertions(+), 30 deletions(-) diff --git a/region_backup/__init__.py b/region_backup/__init__.py index a1969b6..ec2eff1 100644 --- a/region_backup/__init__.py +++ b/region_backup/__init__.py @@ -16,10 +16,14 @@ backup_path = "./rb_multi" # 默认的备份文件夹位置 slot_path = "./rb_multi/slot{0}" +# 默认的overwrite文件夹位置 +overwrite_path = f"{backup_path}/overwrite" # 默认的服务端存档位置 world_path = "./server/world" # 地狱,末地世界区域文件位置 dim_dict = {"the_nether": "DIM-1", "the_end": "DIM1"} +# 单维度完整备份列表 +dim_folder = ["data", "poi", "entities", "region"] # 全局分享列表 data_list = [] # 用户 @@ -42,14 +46,16 @@ §d【格式说明】 #sc=!!rb<>st=点击运行指令#§7{0} §a§l[▷] §e显示帮助信息 #sc=!!rb make<>st=点击运行指令#§7{0} make §b<区块半径> <注释> §a§l[▷] §e以玩家所在区块为中心,备份边长为2倍半径+1的区块所在区域 -#sc=!!rb pos_make<>st=点击运行指令#§7{0} pos_make §b <维度:0主世界,-1地狱,1末地> <注释> §a§l[▷] §e给定两个坐标点,备份以两坐标点对应的区域坐标为顶点形成的矩形区域 +#sc=!!rb dim_make<>st=点击运行指令#§7{0} dim_make §b<维度:0主世界,-1地狱,1末地> <注释> §a§l[▷] §e备份单个维度的所有区域 +#sc=!!rb pos_make<>st=点击运行指令#§7{0} pos_make §b <维度:格式见上条指令> <注释> §a§l[▷] §e给定两个坐标点,备份以两坐标点对应的区域坐标为顶点形成的矩形区域 #sc=!!rb back<>st=点击运行指令#§7{0} back §b<槽位> §a§l[▷] §e回档指定槽位所对应的区域 +#sc=!!rb restore<>st=点击运行指令#§7{0} restore §b<槽位> §a§l[▷] §e使存档还原到回档前状态 #sc=!!rb del<>st=点击运行指令#§7{0} del §b<槽位> §a§l[▷] §e删除某槽位 #sc=!!rb confirm<>st=点击运行指令#§7{0} confirm §a§l[▷] §e再次确认是否回档 #sc=!!rb abort<>st=点击运行指令#§7{0} abort §a§l[▷] §e在任何时候键入此指令可中断回档 #sc=!!rb list<>st=点击运行指令#§7{0} list §a§l[▷] §e显示各槽位的存档信息 #sc=!!rb reload<>st=点击运行指令#§7{0} reload §a§l[▷] §e重载插件 -'''.format(Prefix, "Region BackUp", "1.2.0") +'''.format(Prefix, "Region BackUp", "2.0.0") def print_help_msg(source: CommandSource): @@ -238,6 +244,94 @@ def rb_pos_make(source: InfoCommandSource, dic: dict): source.reply("§c§l备份正在进行,请不要重复备份!") +@new_thread("rb_dim_make") +def rb_dim_make(source: InfoCommandSource, dic: dict): + global backup_state, user + + try: + if backup_state is None: + backup_state = False + + if "cmt" not in dic: + dic["cmt"] = "§7空" + + dim = dic["dim"] + + if dim == 0: + dim = "overworld" + + elif dim == 1: + dim = "the_end" + + elif dim == -1: + dim = "the_nether" + + else: + source.reply("§c维度输入错误!") + return + + source.get_server().broadcast("[RBU] §a备份§f中...请稍等") + + user = source.get_info().is_user + # 保存游戏 + source.get_server().execute("save-off") + t = time.time() + while backup_state != 1: + if time.time() - t > time_out: + source.get_server().broadcast("[RBU] §c备份§f超时,已取消备份") + source.get_server().execute("save-on") + backup_state = None + user = None + return + time.sleep(0.01) + + source.get_server().execute("save-all flush") + t1 = time.time() + while backup_state != 2: + if time.time() - t1 > time_out: + source.get_server().broadcast("[RBU] §c备份§f超时,已取消备份") + source.get_server().execute("save-on") + backup_state = None + user = None + return + time.sleep(0.01) + + user = None + + rename_slot() + + if dim in dim_dict: + path = [dim_dict[dim]] + + else: + path = dim_folder + + for i in path: + shutil.copytree(os.path.join(world_path, i), os.path.join(backup_path, "slot1", i)) + + make_info_file(dic["cmt"], backup_dim=dim, + user_=source.get_info().player if source.get_info().player else "from_console", + cmd=source.get_info().content) + + t2 = time.time() + source.get_server().broadcast(f"[RBU] §a备份§f完成,耗时§6{(t2 - t):.2f}§f秒") + source.get_server().broadcast( + f"[RBU] 日期: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}; 注释: {dic['cmt']}") + + source.get_server().execute("save-on") + backup_state = None + return + + except Exception as e: + user = None + backup_state = None + source.reply(f"备份出错,错误信息:§c{e}") + source.get_server().execute("save-on") + return + + source.reply("§c§l备份正在进行,请不要重复备份!") + + # 玩家信息类型有如下两种 坐标,即Pos 维度,即Dimension @new_thread("user_info") def get_user_info(source): @@ -266,15 +360,20 @@ def rb_back(source: InfoCommandSource, dic: dict): # 判断槽位非空 if not dic: - dic["slot"] = 1 + if source.get_info().content.split()[1] == "restore": + dic["slot"] = "overwrite" + else: + dic["slot"] = 1 + + path = slot_path.format(dic["slot"]) if isinstance(dic["slot"], int) else os.path.join(backup_path, dic["slot"]) - if not os.path.exists(os.path.join(slot_path.format(dic["slot"]), "info.json")): + if not os.path.exists(os.path.join(path, "info.json")): source.reply("§c该槽位无info.json文件,无法回档") return - if not get_file_size([os.path.join(slot_path.format(dic["slot"]), "entities"), - os.path.join(slot_path.format(dic["slot"]), "poi"), - os.path.join(slot_path.format(dic["slot"]), "region")])[-1]: + if not get_file_size( + [os.path.join(path, f) for f in os.listdir(path) if + os.path.isdir(os.path.join(path, f))])[-1]: source.reply("§c该槽位无区域文件,无法回档") return @@ -284,7 +383,7 @@ def rb_back(source: InfoCommandSource, dic: dict): back_state = 0 # 等待确认 - with codecs.open(os.path.join(slot_path.format(dic["slot"]), "info.json"), encoding="utf-8-sig") as fp: + with codecs.open(os.path.join(path, "info.json"), encoding="utf-8-sig") as fp: info = json.load(fp) t = info["time"] cmt = info["comment"] @@ -336,15 +435,17 @@ def on_server_stop(server: PluginServerInterface, server_return_code: int): return server.logger.error("正在运行文件替换") - extra_slot = f"{backup_path}/overwrite" - if os.path.exists(extra_slot): - shutil.rmtree(extra_slot) - os.makedirs(extra_slot) - os.makedirs(extra_slot + "/entities") - os.makedirs(extra_slot + "/region") - os.makedirs(extra_slot + "/poi") - - with codecs.open(os.path.join(slot_path.format(back_slot), "info.json"), encoding="utf-8-sig") as fp: + if os.path.exists(overwrite_path) and back_slot != "overwrite": + shutil.rmtree(overwrite_path) + os.makedirs(overwrite_path) + + path_ = slot_path.format(back_slot) if isinstance(back_slot, int) else os.path.join(backup_path, + str(back_slot)) + + back_folder = [f for f in os.listdir(path_) if + os.path.isdir(os.path.join(path_, f))] + + with codecs.open(os.path.join(path_, "info.json"), encoding="utf-8-sig") as fp: info = json.load(fp) dim = info["backup_dimension"] if dim in dim_dict: @@ -353,18 +454,65 @@ def on_server_stop(server: PluginServerInterface, server_return_code: int): else: path = world_path - for backup_file in ["entities", "region", "poi"]: - if get_file_size([os.path.join(slot_path.format(back_slot), backup_file)])[-1]: - lst = os.listdir(os.path.join(slot_path.format(back_slot), backup_file)) - for i in lst: - # 复制即将被替换的区域到overwrite - shutil.copy2(os.path.join(path, backup_file, i), os.path.join(extra_slot, backup_file, i)) - # 将备份的区域对存档里对应的区域替换 - shutil.copy2(os.path.join(slot_path.format(back_slot), backup_file, i), - os.path.join(path, backup_file, i)) - # 复制本次回档槽位的info文件到overwrite - shutil.copy2(os.path.join(slot_path.format(back_slot), "info.json"), - os.path.join(extra_slot, "info.json")) + if info["command"].split()[1] == "dim_make": + + if info["backup_dimension"] == "overworld": + if back_slot != "overwrite": + for i in back_folder: + shutil.copytree(os.path.join(path, i), os.path.join(overwrite_path, i)) + shutil.rmtree(os.path.join(path, i)) + shutil.copytree(os.path.join(path_, i), os.path.join(path, i)) + shutil.copy2(os.path.join(path_, "info.json"), + os.path.join(overwrite_path, "info.json")) + + else: + for i in back_folder: + shutil.rmtree(os.path.join(path, i)) + shutil.copytree(os.path.join(path_, i), os.path.join(path, i)) + + else: + if back_slot != "overwrite": + shutil.copytree(os.path.join(path), os.path.join(overwrite_path, dim_dict[dim])) + shutil.rmtree(os.path.join(path)) + shutil.copytree(os.path.join(path_, dim_dict[dim]), + os.path.join(os.path.join(path))) + shutil.copy2(os.path.join(path_, "info.json"), + os.path.join(overwrite_path, "info.json")) + + else: + shutil.rmtree(os.path.join(path)) + shutil.copytree(os.path.join(path_, dim_dict[dim]), + os.path.join(os.path.join(path))) + + else: + + if back_slot != "overwrite": + + for i in back_folder: + os.makedirs(overwrite_path + "/" + i) + + for backup_file in back_folder: + if get_file_size([os.path.join(path_, backup_file)])[-1]: + lst = os.listdir(os.path.join(path_, backup_file)) + for i in lst: + # 复制即将被替换的区域到overwrite + shutil.copy2(os.path.join(path, backup_file, i), + os.path.join(overwrite_path, backup_file, i)) + # 将备份的区域对存档里对应的区域替换 + shutil.copy2(os.path.join(path_, backup_file, i), + os.path.join(path, backup_file, i)) + # 复制本次回档槽位的info文件到overwrite + shutil.copy2(os.path.join(path_, "info.json"), + os.path.join(overwrite_path, "info.json")) + + else: + for backup_file in back_folder: + if get_file_size([os.path.join(path_, backup_file)])[-1]: + lst = os.listdir(os.path.join(path_, backup_file)) + for i in lst: + # 将备份的区域对存档里对应的区域替换 + shutil.copy2(os.path.join(path_, backup_file, i), + os.path.join(path, backup_file, i)) back_slot = None @@ -641,10 +789,13 @@ def on_load(server: PluginServerInterface, old): builder.command("!!rb", print_help_msg) builder.command("!!rb make ", rb_make) builder.command("!!rb make ", rb_make) + builder.command("!!rb dim_make ", rb_dim_make) + builder.command("!!rb dim_make ", rb_dim_make) builder.command("!!rb pos_make ", rb_pos_make) builder.command("!!rb pos_make ", rb_pos_make) builder.command("!!rb back ", rb_back) builder.command("!!rb back", rb_back) + builder.command("!!rb restore", rb_back) builder.command("!!rb confirm", rb_confirm) builder.command("!!rb del ", rb_del) builder.command("!!rb abort", rb_abort) @@ -660,7 +811,7 @@ def on_load(server: PluginServerInterface, old): builder.arg("cmt", GreedyText) builder.arg("slot", Integer) - command_literals = ["make", "pos_make", "back", "confirm", "del", "abort", "list", "reload"] + command_literals = ["make", "pos_make", "dim_make", "back", "restore", "confirm", "del", "abort", "list", "reload"] for literal in command_literals: permission = level_dict[literal] From 17fa1898f6d9e47d5464f0d8fcf21329a868983f Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Tue, 27 Feb 2024 01:46:06 +0800 Subject: [PATCH 05/17] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 更新文档 --- README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 102f586..4ac9883 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ # Region_BackUp 一个以区域为单位备份或回档的MCDR插件 > [!TIP] +> +> 尽可能的使用最新版本,以避免潜藏的问题,升级版本后请重新生成配置文件 +> > 如果您想为这个项目作贡献,请直接发送PR,而不是创建issue :) 需要 `v2.6.0` 以上的 [MCDReforged](https://github.com/Fallen-Breath/MCDReforged) ## 用前需知 @@ -36,9 +39,13 @@ `!!rb make <区块半径> <注释>` 以玩家所在区块为中心,备份边长为2倍半径+1的区块所在区域 -`!!rb pos_make <维度:0主世界,-1地狱,1末地> <注释>` 给定两个坐标点,备份以两坐标点对应的区域坐标为顶点形成的矩形区域 +`!!rb dim_make <维度:0主世界,-1地狱,1末地> <注释>` 备份单个维度的所有区域 -`!!rb back []` 回档指定槽位所对应的区域 +`!!rb pos_make <维度:用法见上>` 给定两个坐标点,备份以两坐标点对应的区域坐标为顶点形成的矩形区域 + +`!!rb back ` 回档指定槽位所对应的区域 + +`!!rb restore` 使存档还原到回档前状态 `!!rb del ` 删除某槽位 @@ -68,7 +75,9 @@ 默认值:`{ "make": 1, "pos_make": 1, + "dim_make": 1, "back": 2, + "restore": 2, "del": 2, "confirm": 1, "abort": 1, From 2672790c3687e6f1a748327d5c3ae8baaa25056e Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Tue, 27 Feb 2024 01:47:55 +0800 Subject: [PATCH 06/17] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4ac9883..2e219b4 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ `!!rb dim_make <维度:0主世界,-1地狱,1末地> <注释>` 备份单个维度的所有区域 -`!!rb pos_make <维度:用法见上>` 给定两个坐标点,备份以两坐标点对应的区域坐标为顶点形成的矩形区域 +`!!rb pos_make <维度> <注释>` 给定两个坐标点,备份以两坐标点对应的区域坐标为顶点形成的矩形区域 `!!rb back ` 回档指定槽位所对应的区域 From a2458097f35fc08ea38e81b19654c40b11756138 Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Tue, 27 Feb 2024 01:55:45 +0800 Subject: [PATCH 07/17] Update __init__.py --- region_backup/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/region_backup/__init__.py b/region_backup/__init__.py index ec2eff1..3633ad1 100644 --- a/region_backup/__init__.py +++ b/region_backup/__init__.py @@ -391,8 +391,12 @@ def rb_back(source: InfoCommandSource, dic: dict): source.reply(Message.get_json_str("\n".join([f"[RBU] 准备将存档恢复至槽位§6{dic['slot']}§f,日期 {t}; 注释: {cmt}", "[RBU] 使用#sc=!!rb confirm<>st=点击确认#§7!!rb confirm " "§f确认§c回档§f,#sc=!!rb abort<>st=点击取消#§7!!qb abort §f取消"]))) - + t1 = time.time() while not back_state: + if time.time() - t1 > 10: + source.reply("§a回档超时,已取消本次回档") + back_state = None + return time.sleep(0.01) if back_state is True: From 02b3ed803370d5d22a3d3a24b778c72aed6279d0 Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Tue, 27 Feb 2024 01:59:30 +0800 Subject: [PATCH 08/17] Update __init__.py --- region_backup/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/region_backup/__init__.py b/region_backup/__init__.py index 3633ad1..21401fe 100644 --- a/region_backup/__init__.py +++ b/region_backup/__init__.py @@ -368,7 +368,7 @@ def rb_back(source: InfoCommandSource, dic: dict): path = slot_path.format(dic["slot"]) if isinstance(dic["slot"], int) else os.path.join(backup_path, dic["slot"]) if not os.path.exists(os.path.join(path, "info.json")): - source.reply("§c该槽位无info.json文件,无法回档") + source.reply("§c该槽位无info.json文件或槽位不存在,无法回档") return if not get_file_size( From db4e5e8c215feccebeb707ee3a10e35090d51b97 Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Tue, 27 Feb 2024 02:10:52 +0800 Subject: [PATCH 09/17] Update __init__.py --- region_backup/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/region_backup/__init__.py b/region_backup/__init__.py index 21401fe..b405ca5 100644 --- a/region_backup/__init__.py +++ b/region_backup/__init__.py @@ -305,6 +305,8 @@ def rb_dim_make(source: InfoCommandSource, dic: dict): else: path = dim_folder + + time.sleep(0.1) for i in path: shutil.copytree(os.path.join(world_path, i), os.path.join(backup_path, "slot1", i)) From ba5b3716b58f59897b5feb5c0f66d63394524847 Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Tue, 27 Feb 2024 02:26:18 +0800 Subject: [PATCH 10/17] Update __init__.py --- region_backup/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/region_backup/__init__.py b/region_backup/__init__.py index b405ca5..61c4c91 100644 --- a/region_backup/__init__.py +++ b/region_backup/__init__.py @@ -49,7 +49,7 @@ #sc=!!rb dim_make<>st=点击运行指令#§7{0} dim_make §b<维度:0主世界,-1地狱,1末地> <注释> §a§l[▷] §e备份单个维度的所有区域 #sc=!!rb pos_make<>st=点击运行指令#§7{0} pos_make §b <维度:格式见上条指令> <注释> §a§l[▷] §e给定两个坐标点,备份以两坐标点对应的区域坐标为顶点形成的矩形区域 #sc=!!rb back<>st=点击运行指令#§7{0} back §b<槽位> §a§l[▷] §e回档指定槽位所对应的区域 -#sc=!!rb restore<>st=点击运行指令#§7{0} restore §b<槽位> §a§l[▷] §e使存档还原到回档前状态 +#sc=!!rb restore<>st=点击运行指令#§7{0} restore §b<槽位> §a§l[▷] §e使区域还原到上次回档前状态 #sc=!!rb del<>st=点击运行指令#§7{0} del §b<槽位> §a§l[▷] §e删除某槽位 #sc=!!rb confirm<>st=点击运行指令#§7{0} confirm §a§l[▷] §e再次确认是否回档 #sc=!!rb abort<>st=点击运行指令#§7{0} abort §a§l[▷] §e在任何时候键入此指令可中断回档 @@ -305,7 +305,7 @@ def rb_dim_make(source: InfoCommandSource, dic: dict): else: path = dim_folder - + time.sleep(0.1) for i in path: From da359c7e439a4995e1a40ba4cde0075a217ee52f Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Tue, 27 Feb 2024 02:30:01 +0800 Subject: [PATCH 11/17] Update __init__.py --- region_backup/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/region_backup/__init__.py b/region_backup/__init__.py index 61c4c91..9071dac 100644 --- a/region_backup/__init__.py +++ b/region_backup/__init__.py @@ -49,7 +49,7 @@ #sc=!!rb dim_make<>st=点击运行指令#§7{0} dim_make §b<维度:0主世界,-1地狱,1末地> <注释> §a§l[▷] §e备份单个维度的所有区域 #sc=!!rb pos_make<>st=点击运行指令#§7{0} pos_make §b <维度:格式见上条指令> <注释> §a§l[▷] §e给定两个坐标点,备份以两坐标点对应的区域坐标为顶点形成的矩形区域 #sc=!!rb back<>st=点击运行指令#§7{0} back §b<槽位> §a§l[▷] §e回档指定槽位所对应的区域 -#sc=!!rb restore<>st=点击运行指令#§7{0} restore §b<槽位> §a§l[▷] §e使区域还原到上次回档前状态 +#sc=!!rb restore<>st=点击运行指令#§7{0} restore §a§l[▷] §e使区域还原到上次回档前状态 #sc=!!rb del<>st=点击运行指令#§7{0} del §b<槽位> §a§l[▷] §e删除某槽位 #sc=!!rb confirm<>st=点击运行指令#§7{0} confirm §a§l[▷] §e再次确认是否回档 #sc=!!rb abort<>st=点击运行指令#§7{0} abort §a§l[▷] §e在任何时候键入此指令可中断回档 From 8c2cfd285f45fe45616d20e9ddcf449595c65cfc Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Tue, 27 Feb 2024 02:35:48 +0800 Subject: [PATCH 12/17] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e219b4..bf016ce 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,9 @@ 5.尽量不要在插件进行备份回档操作时重载插件。 -6.如果在回档后你想撤销本次回档,你可以在./rb_multi里的overwrite文件夹里将回档前的区域文件放到存档里的对应文件夹里来进行还原,注意在还原时不要忘记你想还原的是哪个维度的区域。 +6.备份时会在槽位里创建一个info.json文件,该文件存储着槽位的所有信息,请不要删除它,否则该槽位会被认定为无效槽位 + +6.如果在回档后你想撤销本次回档,你可以使用!!rb restore 指令,也可以在./rb_multi里的overwrite文件夹里将回档前的区域文件放到存档里的对应文件夹里来进行还原,注意在还原时不要忘记你想还原的是哪个维度的区域。 ## 命令格式说明 From ecf2d553b303e20cdfd9385093673a30365110bc Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Tue, 27 Feb 2024 02:36:04 +0800 Subject: [PATCH 13/17] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bf016ce..507edb7 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ 6.备份时会在槽位里创建一个info.json文件,该文件存储着槽位的所有信息,请不要删除它,否则该槽位会被认定为无效槽位 -6.如果在回档后你想撤销本次回档,你可以使用!!rb restore 指令,也可以在./rb_multi里的overwrite文件夹里将回档前的区域文件放到存档里的对应文件夹里来进行还原,注意在还原时不要忘记你想还原的是哪个维度的区域。 +7.如果在回档后你想撤销本次回档,你可以使用!!rb restore 指令,也可以在./rb_multi里的overwrite文件夹里将回档前的区域文件放到存档里的对应文件夹里来进行还原,注意在还原时不要忘记你想还原的是哪个维度的区域。 ## 命令格式说明 From 9e2e7085b734fa25631749e2862ff75ff28c13e6 Mon Sep 17 00:00:00 2001 From: GHS_Official <84139787+GHS-Official@users.noreply.github.com> Date: Tue, 27 Feb 2024 02:37:10 +0800 Subject: [PATCH 14/17] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 507edb7..4e141f7 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ (3)任何你只希望局部备份的地方。 -3.插件目前有两种备份指令,具体见指令说明。不管你使用了哪种备份指令,实际使用时备份的范围往往会比你想要的大。 +3.插件目前有三种种备份指令,两种回档指令,具体见指令说明。除单维度备份外,实际使用时备份的范围往往会比你想要的大。 4.由于插件在备份时会保存区域的方块数据、实体数据和兴趣点数据,因此可能会有玩家用此来刷取物品,因为插件只会备份与区域有关的数据,而不会与其他数据产生交互。 From 5fff6cc31f855d5e80b9560ea6010dc56ee08196 Mon Sep 17 00:00:00 2001 From: mc_doge_ <77102592+mc-doge666@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:28:48 +0800 Subject: [PATCH 15/17] Update mcdreforged.plugin.json Update version to 1.5.0 --- mcdreforged.plugin.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mcdreforged.plugin.json b/mcdreforged.plugin.json index ca7d2a3..651b5ae 100644 --- a/mcdreforged.plugin.json +++ b/mcdreforged.plugin.json @@ -1,6 +1,6 @@ { "id": "region_backup", - "version": "1.0.0", + "version": "1.5.0", "name": "Region-BackUp", "description": { "en_us": "An MCDR plugin that backs up or backs up files on a regional basis", @@ -17,4 +17,4 @@ "resources": [ "LICENSE" ] -} \ No newline at end of file +} From 8c718faccd05b039142b7ad1f93eb36f4a8f5ae5 Mon Sep 17 00:00:00 2001 From: mc_doge_ <77102592+mc-doge666@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:30:49 +0800 Subject: [PATCH 16/17] Update __init__.py Change version v2.0.0 to v1.5.0 --- region_backup/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/region_backup/__init__.py b/region_backup/__init__.py index 9071dac..09a9425 100644 --- a/region_backup/__init__.py +++ b/region_backup/__init__.py @@ -55,7 +55,7 @@ #sc=!!rb abort<>st=点击运行指令#§7{0} abort §a§l[▷] §e在任何时候键入此指令可中断回档 #sc=!!rb list<>st=点击运行指令#§7{0} list §a§l[▷] §e显示各槽位的存档信息 #sc=!!rb reload<>st=点击运行指令#§7{0} reload §a§l[▷] §e重载插件 -'''.format(Prefix, "Region BackUp", "2.0.0") +'''.format(Prefix, "Region BackUp", "1.5..0") def print_help_msg(source: CommandSource): From 8e96001c948b8fd6c5fc6a75347cf74d334ba7d0 Mon Sep 17 00:00:00 2001 From: mc_doge_ <77102592+mc-doge666@users.noreply.github.com> Date: Tue, 27 Feb 2024 12:31:30 +0800 Subject: [PATCH 17/17] Update __init__.py Delete "." --- region_backup/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/region_backup/__init__.py b/region_backup/__init__.py index 09a9425..1c63329 100644 --- a/region_backup/__init__.py +++ b/region_backup/__init__.py @@ -55,7 +55,7 @@ #sc=!!rb abort<>st=点击运行指令#§7{0} abort §a§l[▷] §e在任何时候键入此指令可中断回档 #sc=!!rb list<>st=点击运行指令#§7{0} list §a§l[▷] §e显示各槽位的存档信息 #sc=!!rb reload<>st=点击运行指令#§7{0} reload §a§l[▷] §e重载插件 -'''.format(Prefix, "Region BackUp", "1.5..0") +'''.format(Prefix, "Region BackUp", "1.5.0") def print_help_msg(source: CommandSource):