This commit is contained in:
张宇衡 2023-06-12 21:03:11 +08:00
parent d123f33c1d
commit ed6d879a19
2 changed files with 336 additions and 0 deletions

View File

@ -1,2 +1,41 @@
# MinecraftRegionPurge
清理无用区域以便于新版本生成
## 这是什么
对于已经生成的区块来说,这些新地形将不会生成。对于一些已经运行相当久的服务器来说,玩家只有不停向外探索从未生成的区域才能体验到新地形。
最好的解决方案就是将没有玩家使用的区块全部删除游戏会在下次有玩家经过时生成新的区块。但是这对于地图相当大的服务器来说仍是一个不可接受的任务因为地图太大了玩家居住的又相当分散服主很难根据mca文件判断哪些应该删除哪些不应该。
💡这个脚本的诞生就是为了解决这样的苦恼!💡
脚本会根据玩家的领地自动计算出哪些mca文件是有效的哪些是无效的。同时还可以根据计算得出的结果自动删除那些无效的区域文件。
## 功能
1. 提取有领地的mca文件列表
2. 导出mca列表
3. 生成dynmap用的标记便于可视化区域
4. 清理没有领地的废弃区域;
5. 自动识别不同的世界以及存档位置;
## 前置条件
1. Linux系统的服务器
2. 安装有领地插件;
## 使用方法
```
chmod +x RegionPurge.sh
./RegionPurge <你的服务端根目录>
```

297
RegionPurge.sh Normal file
View File

@ -0,0 +1,297 @@
#!/bin/bash
server_root_path=""
residence_save_path=""
world_name=""
world_save_path=""
mca_list="" # (r.x.z.mca r.x.z.mca ...)
cord_list="" # (x1 y1 z1 x2 y2 z2 x1 y1 z1 x2 y2 z2 ...)
# Find Residence plugin save path
# return: residence save path
function get_residence_save_path() {
residence_save_path=$server_root_path/plugins/Residence/Save/Worlds
if [ -d "$residence_save_path" ]; then
printf "找到 Residence 插件存档路径 %s\n" "$residence_save_path"
else
printf "错误 - Residence 插件存档路径不存在"
exit 1
fi
}
# Find world save path
# return: world save path
function get_world_save_path() {
# 如果是 world 则路径为 world/
# 否则路径为 $world_name/DIM-1/
if [ "$world_name" == "world" ]; then
world_save_path=$server_root_path/world
else
world_save_path=$server_root_path/$world_name/DIM-1
fi
if [ -d "$world_save_path" ]; then
printf "找到世界存档路径 %s\n" "$world_save_path"
else
printf "错误 - 世界存档路径不存在"
exit 1
fi
}
# Select world
function select_world() {
local world_list
world_list=$(ls -1 "${residence_save_path}/" | grep '\.yml$' | tr '\n' ' ')
local world_list_array
IFS=' ' read -r -a world_list_array <<<"$world_list"
local world_list_length=${#world_list_array[@]}
printf "找到 %s 个世界\n" "$world_list_length"
for ((i = 0; i < world_list_length; i++)); do
world_list_array[i]=${world_list_array[i]%.yml}
world_list_array[i]=${world_list_array[i]#res_}
printf "%s. %s\n" "$i" "${world_list_array[i]}"
done
while true; do
printf "请输入要操作的世界序号 (0 ~ %d) 或 q 退出\n" "$((world_list_length - 1))"
printf "> "
read -r world_index
if [ "$world_index" -ge 0 ] && [ "$world_index" -lt "$world_list_length" ]; then
world_name=${world_list_array[world_index]}
break
elif [ "$world_index" == "q" ]; then
printf "退出\n"
exit 0
else
printf "输入错误,请重新输入\n"
continue
fi
done
}
# Write mca file list to csv file with format 'filename, x, z, x, z, \n'
function export_mca_list_to_csv() {
local mca_list_array
IFS=' ' read -r -a mca_list_array <<<"$mca_list"
local mca_list_length=${#mca_list_array[@]}
echo "file_name,mca_x,mca_z,x1,x2,x3,x4,z1,z2,z3,z4,">mca_list.csv
for ((i = 0; i < mca_list_length; i++)); do
local mca_file_name=${mca_list_array[i]}
local mca_file_name_array
IFS='.' read -r -a mca_file_name_array <<<"$mca_file_name"
local x=${mca_file_name_array[1]}
local z=${mca_file_name_array[2]}
local x1=$((x * 512))
local x2=$((x * 512 + 511))
local x3=$((x * 512))
local x4=$((x * 512 + 511))
local z1=$((z * 512))
local z2=$((z * 512))
local z3=$((z * 512 + 511))
local z4=$((z * 512 + 511))
echo "$mca_file_name,$x,$z,$x1,$x2,$x3,$x4,$z1,$z2,$z3,$z4,">>mca_list.csv
done
printf "共 %s 个mca 已导出 mca 文件列表到 mca_list.csv\n" "$mca_list_length"
}
# Generate dynmap areas.yml file
function generate_dynmap_areas() {
local mca_list_array
IFS=' ' read -r -a mca_list_array <<<"$mca_list"
local mca_list_length=${#mca_list_array[@]}
echo "areas:" >areas.yml
for ((i = 0; i < mca_list_length; i++)); do
local mca_file_name=${mca_list_array[i]}
local mca_file_name_array
IFS='.' read -r -a mca_file_name_array <<<"$mca_file_name"
local x=${mca_file_name_array[1]}
local z=${mca_file_name_array[2]}
local x1=$((x * 512))
local x2=$(((x + 1) * 512))
local x3=$(((x + 1) * 512))
local x4=$((x * 512))
local z1=$((z * 512))
local z2=$((z * 512))
local z3=$(((z + 1) * 512))
local z4=$(((z + 1) * 512))
echo " area_100$i:" >>areas.yml
echo " fillColor: 8421504 # 0x808080" >>areas.yml
echo " world: $world_name" >>areas.yml
echo " markup: false" >>areas.yml
echo " ytop: 64.0" >>areas.yml
echo " fillOpacity: 0.3" >>areas.yml
echo " x:" >>areas.yml
echo " - $x1.0" >>areas.yml
echo " - $x2.0" >>areas.yml
echo " - $x3.0" >>areas.yml
echo " - $x4.0" >>areas.yml
echo " strokeWeight: 1" >>areas.yml
echo " z:" >>areas.yml
echo " - $z1.0" >>areas.yml
echo " - $z2.0" >>areas.yml
echo " - $z3.0" >>areas.yml
echo " - $z4.0" >>areas.yml
echo " label: $mca_file_name" >>areas.yml
echo " ybottom: 64.0" >>areas.yml
echo " strokeColor: 8421504" >>areas.yml
echo " strokeOpacity: 1.0" >>areas.yml
done
printf "共 %s 个mca 已生成 dynmap areas 到 areas.yml\n" "$mca_list_length"
}
# Delete mca files not in mca_list
function purge_mca_files() {
local mca_list_array
IFS=' ' read -r -a mca_list_array <<<"$mca_list"
local mca_list_length=${#mca_list_array[@]}
local region_path=$world_save_path/region
local entitits_path=$world_save_path/entities
local all_region_mca_files
all_region_mca_files=$(ls "$region_path" | grep '\.mca$' | tr '\n' ' ')
local all_entities_mca_files
all_entities_mca_files=$(ls "$entitits_path" | grep '\.mca$' | tr '\n' ' ')
local all_region_mca_files_array
IFS=' ' read -r -a all_region_mca_files_array <<<"$all_region_mca_files"
local all_region_mca_files_length=${#all_region_mca_files_array[@]}
printf "找到 %s 个 mca 文件\n" "$all_region_mca_files_length"
for ((i = 0; i < all_region_mca_files_length; i++)); do
if [[ ! " ${mca_list_array[*]} " =~ ${all_region_mca_files_array[i]} ]]; then
printf "删除 mca 文件 %s\n" "${all_region_mca_files_array[i]}"
rm "$region_path/${all_region_mca_files_array[i]}"
fi
done
local all_entities_mca_files_array
IFS=' ' read -r -a all_entities_mca_files_array <<<"$all_entities_mca_files"
local all_entities_mca_files_length=${#all_entities_mca_files_array[@]}
printf "找到 %s 个 mca 文件\n" "$all_entities_mca_files_length"
for ((i = 0; i < all_entities_mca_files_length; i++)); do
if [[ ! " ${mca_list_array[*]} " =~ ${all_entities_mca_files_array[i]} ]]; then
printf "删除 mca 文件 %s\n" "${all_entities_mca_files_array[i]}"
rm "$entitits_path/${all_entities_mca_files_array[i]}"
fi
done
}
# Select operate
function select_operate() {
local mca_list_array
IFS=' ' read -r -a mca_list_array <<<"$mca_list"
local mca_list_length=${#mca_list_array[@]}
while true; do
printf "请输入要操作的类型\n"
printf "1. 导出 mca 文件列表到 csv\n"
printf "2. 删除不在 mca 文件列表中的 mca 文件\n"
printf "3. 导出dynmap areas 到 areas.yml\n"
printf "> "
read -r operate_type
if [ "$operate_type" == "1" ]; then
export_mca_list_to_csv
break
elif [ "$operate_type" == "2" ]; then
printf "确认操作 y/n\n"
printf "> "
read -r confirm
if [ "$confirm" == "y" ]; then
get_world_save_path
purge_mca_files
break
else
printf "取消操作\n"
break
fi
elif [ "$operate_type" == "3" ]; then
generate_dynmap_areas
break
else
printf "输入错误,请重新输入\n"
continue
fi
done
}
# Parse all 'main: 1575:-64:-2452:2045:319:-1872' in file to '1575 -64 -2452 2045 319 -1872'
# to format 'x1 y1 z1 x2 y2 z2 x1 y1 z1 x2 y2 z2 ...''
function parse_residence_list() {
local world_save_file_path=$residence_save_path/res_$world_name.yml
local residence_list
residence_list=$(grep -oP "main: \K.*" "$world_save_file_path" | tr '\n' ' ')
local residence_list_array
IFS=' ' read -r -a residence_list_array <<<"$residence_list"
local residence_list_length=${#residence_list_array[@]}
for ((i = 0; i < residence_list_length; i++)); do
local residence_cord
residence_cord=$(echo "${residence_list_array[i]}" | tr ':' ' ')
cord_list="$cord_list $residence_cord"
done
}
# Cast cordination to mca file name
function cast_cord_to_mca() {
local cord_list_array
IFS=' ' read -r -a cord_list_array <<<"$cord_list"
local cord_list_length=${#cord_list_array[@]}
for ((i = 0; i < cord_list_length; i += 6)); do
local x1=${cord_list_array[i]}
local z1=${cord_list_array[i + 2]}
local x2=${cord_list_array[i + 3]}
local z2=${cord_list_array[i + 5]}
local x1_mca=$((x1 / 512))
local z1_mca=$((z1 / 512))
local x2_mca=$((x2 / 512))
local z2_mca=$((z2 / 512))
# expand 1 field to each side
for ((x = x1_mca - 2; x <= x2_mca + 2; x++)); do
for ((z = z1_mca - 2; z <= z2_mca + 2; z++)); do
file_name="r.$x.$z.mca"
# if file not exist in mca_list_result then add it
if [[ "$mca_list" != *"$file_name"* ]]; then
mca_list="$mca_list $file_name"
fi
done
done
done
}
# Main function
function main() {
server_root_path=$1
# Check if server root path is empty
if [ -z "$server_root_path" ]; then
echo "Usage: PurgeMca.sh <server_root_path>"
exit 1
fi
# Check if server root path exists
if [ ! -d "$server_root_path" ]; then
echo "Server root path does not exist"
exit 1
fi
get_residence_save_path
while true; do
select_world
parse_residence_list
cast_cord_to_mca
select_operate
printf "任务完成 继续或退出 c/q\n"
printf "> "
read -r continue_or_quit
if [ "$continue_or_quit" == "c" ]; then
clear
continue
elif [ "$continue_or_quit" == "q" ]; then
break
else
printf "输入错误,退出\n"
break
fi
done
}
# Call main function
main "$1"