Skip to content

Commit

Permalink
Merge pull request #27 from Ground-Hyper-Sky/dev
Browse files Browse the repository at this point in the history
增加了多维度备份
  • Loading branch information
mc-doge666 authored Mar 21, 2024
2 parents 2f151b1 + 900b5ea commit a1d8eec
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 79 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
>
> 尽可能的使用最新版本,以避免潜藏的问题,升级版本后请重新生成配置文件
>
> 如果您想为这个项目作贡献,请直接发送PR,而不是创建issue :)
> 发现问题请提交issue,如果您想为本项目做出贡献,欢迎提交pr
>
需要 `v2.6.0` 以上的 [MCDReforged](https://github.com/Fallen-Breath/MCDReforged)
## 用前需知
一个区域文件存储的范围被称为区域(Region),一个区域的大小是32×32区块。
Expand Down Expand Up @@ -41,7 +42,7 @@

`!!rb make <区块半径> <注释>` 以玩家所在区块为中心,备份边长为2倍半径+1的区块所在区域

`!!rb dim_make <维度:0主世界,-1地狱,1末地> <注释>` 备份单个维度的所有区域
`!!rb dim_make <维度:0主世界,-1地狱,1末地> <注释>` 备份给定维度的所有区域,维度间用,做区分 例 0 或 0,-1

`!!rb pos_make <x1坐标> <z1坐标> <x2坐标> <z2坐标> <维度> <注释>` 给定两个坐标点,备份以两坐标点对应的区域坐标为顶点形成的矩形区域

Expand Down Expand Up @@ -70,7 +71,7 @@
存储备份文件的路径

### word_path
默认值:`./server/world/`
默认值:`./server/world`
服务器存档的路径

### minimum_permission_level
Expand Down
153 changes: 77 additions & 76 deletions region_backup/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import datetime
import codecs
import json
import re

from mcdreforged.api.all import *
from region_backup.json_message import Message
Expand All @@ -22,6 +23,8 @@
world_path = "./server/world"
# 地狱,末地世界区域文件位置
dim_dict = {"the_nether": "DIM-1", "the_end": "DIM1"}
# 维度对应表
dim_list = {0: "overworld", 1: "the_end", -1: "the_nether"}
# 单维度完整备份列表
dim_folder = ["data", "poi", "entities", "region"]
# 全局分享列表
Expand All @@ -46,16 +49,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 dim_make<>st=点击运行指令#§7{0} dim_make §b<维度:0主世界,-1地狱,1末地> <注释> §a§l[▷] §e备份单个维度的所有区域
#sc=!!rb dim_make<>st=点击运行指令#§7{0} dim_make §b<维度:0主世界,-1地狱,1末地> <注释> §a§l[▷] §e备份给定维度的所有区域,维度间用,做区分 §a例 0 或 0,-1
#sc=!!rb pos_make<>st=点击运行指令#§7{0} pos_make §b<x1坐标> <z1坐标> <x2坐标> <z2坐标> <维度:格式见上条指令> <注释> §a§l[▷] §e给定两个坐标点,备份以两坐标点对应的区域坐标为顶点形成的矩形区域
#sc=!!rb back<>st=点击运行指令#§7{0} back §b<槽位> §a§l[▷] §e回档指定槽位所对应的区域
#sc=!!rb restore<>st=点击运行指令#§7{0} restore §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.5.0")
'''.format(Prefix, "Region BackUp", "1.6.0")


def print_help_msg(source: CommandSource):
Expand Down Expand Up @@ -166,21 +169,15 @@ def rb_pos_make(source: InfoCommandSource, dic: dict):
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"
dim = int(dic["dim"])

else:
source.reply("§c维度输入错误!")
if dim not in dim_list:
backup_state = None
source.reply("§c维度输入错误")
return

dim = dim_list[dim]

source.get_server().broadcast("[RBU] §a备份§f中...请稍等")

backup_pos = get_backup_pos(pos_list=[(int(x1 // 512), int(x2 // 512)), (int(z1 // 512), int(z2 // 512))])
Expand Down Expand Up @@ -257,18 +254,21 @@ def rb_dim_make(source: InfoCommandSource, dic: dict):

dim = dic["dim"]

if dim == 0:
dim = "overworld"

elif dim == 1:
dim = "the_end"
res = re.findall(r'-\d+|\d+', dim)
dim = [int(s) if s[0] != '-' else -int(s[1:]) for s in res]
if len(dim) != len(set(dim)):
backup_state = None
source.reply("§c维度输入重复")
return

elif dim == -1:
dim = "the_nether"
backup_list = []

else:
source.reply("§c维度输入错误!")
return
for i in dim:
if i not in dim_list:
backup_state = None
source.reply("§c维度输入错误")
return
backup_list.append(dim_list[i])

source.get_server().broadcast("[RBU] §a备份§f中...请稍等")

Expand Down Expand Up @@ -300,18 +300,21 @@ def rb_dim_make(source: InfoCommandSource, dic: dict):

rename_slot()

if dim in dim_dict:
path = [dim_dict[dim]]
dim_path = []

else:
path = dim_folder
for i in backup_list:
if i in dim_dict:
dim_path.append(dim_dict[i])
else:
for j in dim_folder:
dim_path.append(j)

time.sleep(0.1)

for i in path:
for i in dim_path:
shutil.copytree(os.path.join(world_path, i), os.path.join(backup_path, "slot1", i))

make_info_file(dic["cmt"], backup_dim=dim,
make_info_file(dic["cmt"], backup_dim=",".join(backup_list),
user_=source.get_info().player if source.get_info().player else "from_console",
cmd=source.get_info().content)

Expand Down Expand Up @@ -390,9 +393,10 @@ def rb_back(source: InfoCommandSource, dic: dict):
t = info["time"]
cmt = info["comment"]

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取消"])))
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!!rb abort §f取消"])))
t1 = time.time()
while not back_state:
if time.time() - t1 > 10:
Expand All @@ -415,7 +419,8 @@ def rb_back(source: InfoCommandSource, dic: dict):
source.reply("§a回档已取消")
return
source.get_server().broadcast(Message.get_json_str("\n".join(
[f"§a服务器还有{10 - stop_time}秒关闭,输入#sc=!!rb abort<>st=终止回档#§c!!rb abort§f来停止回档到槽位§6{dic['slot']}"])))
[
f"§a服务器还有{10 - stop_time}秒关闭,输入#sc=!!rb abort<>st=终止回档#§c!!rb abort§f来停止回档到槽位§6{dic['slot']}"])))

back_slot = dic["slot"]
# 停止服务器
Expand All @@ -437,88 +442,84 @@ def on_server_stop(server: PluginServerInterface, server_return_code: int):
try:
if back_slot:
if server_return_code != 0:
back_slot = None
server.logger.error("服务端关闭异常,回档终止")
return

server.logger.error("正在运行文件替换")
server.logger.info("§a正在运行文件替换")

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))]
"overwrite")

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:
path = os.path.join(world_path, dim_dict[dim])

dim_path = []

back_list = dim.split(",")

for i in back_list:
if i not in dim_list.values():
back_slot = None
server.logger.error("请检查info.json里的维度信息是否正确")
return

if i in dim_dict:
dim_path.append(dim_dict[i])

else:
path = world_path
for j in dim_folder:
dim_path.append(j)

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))
if back_slot != "overwrite":
for i in dim_path:
shutil.copytree(os.path.join(world_path, i), os.path.join(overwrite_path, i))
shutil.rmtree(os.path.join(world_path, i))
shutil.copytree(os.path.join(path_, i), os.path.join(world_path, i))
shutil.copy2(os.path.join(path_, "info.json"),
os.path.join(overwrite_path, "info.json"))

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)))
for i in dim_path:
shutil.rmtree(os.path.join(world_path, i))
shutil.copytree(os.path.join(path_, i), os.path.join(world_path, i))

else:

if back_slot != "overwrite":

for i in back_folder:
os.makedirs(overwrite_path + "/" + i)
for i in dim_path:
os.makedirs(overwrite_path + f"/{i}")

for backup_file in back_folder:
for backup_file in dim_path:
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),
shutil.copy2(os.path.join(world_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))
os.path.join(world_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:
for backup_file in dim_path:
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))
os.path.join(world_path, backup_file, i))

back_slot = None

Expand Down Expand Up @@ -812,7 +813,7 @@ def on_load(server: PluginServerInterface, old):
builder.arg("z1", Number)
builder.arg("x2", Number)
builder.arg("z2", Number)
builder.arg("dim", Integer)
builder.arg("dim", Text)
builder.arg("r", Integer)
builder.arg("cmt", GreedyText)
builder.arg("slot", Integer)
Expand Down

0 comments on commit a1d8eec

Please sign in to comment.