Add files via upload

This commit is contained in:
Tsubasa6848
2023-03-03 19:34:24 +08:00
committed by GitHub
Unverified
parent bae2a0dcd4
commit 791ed8e408
15 changed files with 1504 additions and 0 deletions
+76
View File
@@ -0,0 +1,76 @@
cmake_minimum_required(VERSION 3.21)
project(Cleaner)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_BUILD_TYPE Release)
file(GLOB_RECURSE SRC_FILES_DIR
${PROJECT_SOURCE_DIR}/src/*.cpp
${PROJECT_SOURCE_DIR}/src/*.h
)
include_directories(
${CMAKE_SOURCE_DIR}/SDK/include
${CMAKE_SOURCE_DIR}/SDK/include/llapi
)
link_directories(
${CMAKE_SOURCE_DIR}/SDK/lib
)
add_definitions(
-D"NDEBUG"
-D"NOMINMAX"
-D"TEMPLATE_EXPORTS"
-D"UNICODE"
-D"WIN32_LEAN_AND_MEAN"
-D"_AMD64_"
-D"_CRT_SECURE_NO_WARNINGS"
-D"_UNICODE"
-D"_USRDLL"
-D"_WINDLL"
-D"_WINDOWS"
)
add_compile_options(
/diagnostics:column
/EHsc
/FC
/GL
/MD
/nologo
/permissive-
/sdl
/utf-8
/Zc:inline
/Zi
)
add_link_options(
/DEBUG
/DELAYLOAD:"bedrock_server.dll"
/DLL
/IGNORE:4199
/INCREMENTAL:NO
/LTCG:INCREMENTAL
/MANIFESTUAC:NO
/MACHINE:X64
/NOLOGO
/OPT:ICF
/OPT:REF
/SUBSYSTEM:CONSOLE
)
add_library(Cleaner SHARED ${SRC_FILES_DIR})
target_link_libraries(Cleaner
"${CMAKE_SOURCE_DIR}/SDK/lib/LiteLoader.lib"
"${CMAKE_SOURCE_DIR}/SDK/lib/bedrock_server_api.lib"
"${CMAKE_SOURCE_DIR}/SDK/lib/bedrock_server_var.lib"
"${CMAKE_SOURCE_DIR}/SDK/lib/SymDBHelper.lib"
)
add_custom_command(TARGET Cleaner PRE_BUILD
COMMAND cmd /c ${PROJECT_SOURCE_DIR}/prepare_libraries.cmd ${PROJECT_SOURCE_DIR}
)
+1
View File
@@ -0,0 +1 @@
https://minecraft.azureedge.net/bin-win/bedrock-server-1.19.63.01.zip
+11
View File
@@ -0,0 +1,11 @@
@echo off
if not exist %1\SDK\Lib\bedrock_server_api.lib goto process
if not exist %1\SDK\Lib\bedrock_server_var.lib goto process
goto end
:process
cd /d %1\SDK\tools\
LibraryBuilder.exe -o ..\lib\
:end
+398
View File
@@ -0,0 +1,398 @@
#include "setting.h"
#include "Global.h"
#include <llapi/mc/HashedString.hpp>
#include <llapi/mc/Mob.hpp>
#include <llapi/mc/ItemStack.hpp>
#include <llapi/mc/Player.hpp>
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <windows.h>
using namespace Settings;
using namespace LanguageSettings;
extern float Tick_per_minute;
bool ifautoclean;
string before = "§l§e[Cleaner]§r ";
void CleanerMain(){
int k = 0;
auto allentities = Level::getAllEntities();
if(allentities.size() >= 1){
for(Actor* en : allentities){
if (en->isPlayer()) {
continue;
}
bool ifignore = false;
for (auto tag : IgnoreTags) {
if (en->hasTag(tag)) {
ifignore = true;
break;
}
}
if (ifignore = true) {
continue;
}
if (en->isItemActor() == true) {
if(enableitem == true){
auto item = (ItemActor*)en;
auto itemtype = item->getItemStack()->getTypeName();
if(!ItemList.count(itemtype)){
if (item->getLatestSpawnTime() >= ExistTicks) {
en->despawn();
k++;
}
}
}
}
else if (en->isAlive()) {
auto tname = en->getTypeName();
if(enableinanimate == true){
if(InanimateList.count(tname)){
en->despawn();
k++;
}
}
if (enablemobs == true) {
auto mobtype = en->getTypeName();
if(!MobList.count(mobtype)){
if (en->hasFamily("monster")) {
if (cleanmonsters == true) {
if (mobblackonly == false) {
if (Exclude == true) {
auto ifa = en->canShowNameTag();
auto ifb = en->isTame();
auto ifc = en->isTrusting();
if(ifa == false && ifb == false && ifc == false){
en->despawn();
k++;
}
}
else{
en->despawn();
k++;
}
}
else{
if(MobBlackList.count(en->getTypeName())){
if(Exclude == true){
auto ifa = en->canShowNameTag();
auto ifb = en->isTame();
auto ifc = en->isTrusting();
if(ifa == false && ifb == false && ifc == false){
en->despawn();
k++;
}
}
else{
en->despawn();
k++;
}
}
}
}
}
else{
if(cleanpeacefulmobs == true){
if(mobblackonly == false){
if(Exclude == true){
auto ifa = en->canShowNameTag();
auto ifb = en->isTame();
auto ifc = en->isTrusting();
if(ifa == false && ifb == false && ifc == false){
en->despawn();
k++;
}
}
else{
en->despawn();
k++;
}
}
else{
if(MobBlackList.count(en->getTypeName())){
if(Exclude == true){
auto ifa = en->canShowNameTag();
auto ifb = en->isTame();
auto ifc = en->isTrusting();
if(ifa == false && ifb == false && ifc == false){
en->despawn();
k++;
}
}
else{
en->despawn();
k++;
}
}
}
}
}
}
}
}
else{
auto tname = en->getTypeName();
if(enableinanimate == true){
if(InanimateList.count(tname)){
en->despawn();
k++;
}
}
}
}
ifautoclean = true;
LoadLanguageFromJson(LanguageFile);
if(Settings::sendbroadcast == true){
Level::broadcastText(before + ReplaceStr(output4,"{0}",std::to_string(k)),TextType::RAW);
}
if(Settings::sendtoast == true){
auto players = Level::getAllPlayers();
if(players.size() >= 1){
for(int tg = 0; tg <= players.size()-1; tg++){
players[tg]->sendToastPacket(notice,before + ReplaceStr(output4,"{0}",std::to_string(k)));
}
}
}
if(Settings::logtoconsole == true){
logger.info(ReplaceStr(output4,"{0}",std::to_string(k)));
}
}
else{
LoadLanguageFromJson(LanguageFile);
if(Settings::sendbroadcast == true){
Level::broadcastText(before + ReplaceStr(output4,"{0}","0"),TextType::RAW);
}
if(Settings::sendtoast == true){
auto players = Level::getAllPlayers();
if(players.size() >= 1){
for(int tg = 0; tg <= players.size()-1; tg++){
players[tg]->sendToastPacket(notice,before + ReplaceStr(output4,"{0}","0"));
}
}
}
if(Settings::logtoconsole == true){
logger.info(ReplaceStr(output4,"{0}","0"));
}
}
}
void Count1(){
if(Settings::sendbroadcast == true){
Level::broadcastText(before + ReplaceStr(output02,"{0}",std::to_string(pre2)),TextType::RAW);
}
if(Settings::logtoconsole == true){
logger.info(ReplaceStr(output02,"{0}",std::to_string(pre2)));
}
if(Settings::sendtoast == true){
auto players = Level::getAllPlayers();
if(players.size() >= 1){
for(int tga = 0; tga <= players.size()-1; tga++){
players[tga]->sendToastPacket(notice,before + ReplaceStr(output02,"{0}",std::to_string(pre2)));
}
}
}
}
void _CleanerMain(){
LoadLanguageFromJson(LanguageFile);
if(Settings::sendbroadcast == true){
Level::broadcastText(before + ReplaceStr(output01,"{0}",std::to_string(pre1)),TextType::RAW);
}
if(Settings::logtoconsole == true){
logger.info(ReplaceStr(output01,"{0}",std::to_string(pre1)));
}
if(Settings::sendtoast == true){
auto players = Level::getAllPlayers();
if(players.size() >= 1){
for(int tg = 0; tg <= players.size()-1; tg++){
players[tg]->sendToastPacket(notice,before + ReplaceStr(output01,"{0}",std::to_string(pre1)));
}
}
}
Schedule::delay([]{
Count1();
},(pre1-pre2)*20);
Schedule::delay([]{
CleanerMain();
},pre1*20);
}
void Cleaner(){
Schedule::repeat([]{
if(Settings::enableschdule == true){
_CleanerMain();
}
},20*CleanInterval);
}
void _AutoClean() {
int j = 0;
auto allentities = Level::getAllEntities();
if(allentities.size() >= 1){
for(Actor* en : allentities){
if (en->isPlayer()) {
continue;
}
bool ifignore = false;
for (auto tag : IgnoreTags) {
if (en->hasTag(tag)) {
ifignore = true;
break;
}
}
if (ifignore = true) {
continue;
}
if (en->isItemActor() == true) {
if(enableitem == true){
auto item = (ItemActor*)en;
auto itemtype = item->getItemStack()->getTypeName();
if(!ItemList.count(itemtype)){
if (item->getLatestSpawnTime() >= ExistTicks) {
j++;
}
}
}
}
else if (en->isAlive()) {
auto tname = en->getTypeName();
if(enableinanimate == true){
if(InanimateList.count(tname)){
j++;
}
}
if (enablemobs == true) {
auto mobtype = en->getTypeName();
if(!MobList.count(mobtype)){
if (en->hasFamily("monster")) {
if (cleanmonsters == true) {
if (mobblackonly == false) {
if (Exclude == true) {
auto ifa = en->canShowNameTag();
auto ifb = en->isTame();
auto ifc = en->isTrusting();
if(ifa == false && ifb == false && ifc == false){
j++;
}
}
else{
j++;
}
}
else{
if(MobBlackList.count(en->getTypeName())){
if(Exclude == true){
auto ifa = en->canShowNameTag();
auto ifb = en->isTame();
auto ifc = en->isTrusting();
if(ifa == false && ifb == false && ifc == false){
j++;
}
}
else{
j++;
}
}
}
}
}
else{
if(cleanpeacefulmobs == true){
if(mobblackonly == false){
if(Exclude == true){
auto ifa = en->canShowNameTag();
auto ifb = en->isTame();
auto ifc = en->isTrusting();
if(ifa == false && ifb == false && ifc == false){
j++;
}
}
else{
j++;
}
}
else{
if(MobBlackList.count(en->getTypeName())){
if(Exclude == true){
auto ifa = en->canShowNameTag();
auto ifb = en->isTame();
auto ifc = en->isTrusting();
if(ifa == false && ifb == false && ifc == false){
j++;
}
}
else{
j++;
}
}
}
}
}
}
}
}
else{
auto tname = en->getTypeName();
if(enableinanimate == true){
if(InanimateList.count(tname)){
j++;
}
}
}
}
if (j >= Settings::triggercount) {
ifautoclean = false;
LoadLanguageFromJson(LanguageFile);
if(Settings::logtoconsole == true){
logger.warn(ReplaceStr(trigger1,"{0}",std::to_string(j)));
}
if(Settings::sendtoast == true){
auto players = Level::getAllPlayers();
for(int tg = 0; tg <= players.size()-1; tg++){
players[tg]->sendToastPacket(notice,before + ReplaceStr(trigger1,"{0}",std::to_string(j)));
}
}
if(Settings::sendbroadcast == true){
Level::broadcastText(before + ReplaceStr(trigger1,"{0}",std::to_string(j)),TextType::RAW);
}
_CleanerMain();
}
}
}
void AutoClean(){
ifautoclean = true;
Schedule::repeat([]{
if(ifautoclean == true && Settings::enableautoclean == true){
_AutoClean();
}
},160);
}
void TPSClean(){
Schedule::repeat([]{
if(enabletpsclean == true && Tick_per_minute <= triggertps){
LoadLanguageFromJson(LanguageFile);
if(Settings::logtoconsole == true){
logger.warn(ReplaceStr(triggertpsclean,"{0}",std::to_string(Tick_per_minute)));
}
if(Settings::sendtoast == true){
auto players = Level::getAllPlayers();
for(int tg = 0; tg <= players.size()-1; tg++){
players[tg]->sendToastPacket(notice,before + ReplaceStr(triggertpsclean,"{0}",std::to_string(Tick_per_minute)));
}
}
if(Settings::sendbroadcast == true){
Level::broadcastText(before + ReplaceStr(triggertpsclean,"{0}",std::to_string(Tick_per_minute)),TextType::RAW);
}
_CleanerMain();
}
},300);
}
+41
View File
@@ -0,0 +1,41 @@
#include "setting.h"
#include "Global.h"
#include <llapi/LoggerAPI.h>
string readme = "《用户最终许可协议(EULA)》/插件使用须知\n欢迎使用本插件。\n插件内一切功能均可以自定义开关!\n未经许可,本插件不接受任何整合、转载和二次开发。\n本插件目前只发布在MineBBS上面。\n如果造成崩溃,请反复排除是否为本插件问题,如果是本插件造成的,请提交崩溃日志。\n使用过程中难免会有漏洞,请在MineBBS插件的讨论区反馈,作者会尽快修复。请分清楚评论区和讨论区。\n对于以上条款有任何异议,请停止使用并卸载本插件。\n如果同意使用本插件,请在../plugins/Cleaner/EULA.txt 里面进行确认。\n把EULA=false改为EULA=true并保存即可。\n\n\nEnd User Licence Agreement(EULA)/Instruction for Plugin Advancements\nWelcome to use this plugin.\nDo NOT integrate, reproduce or secondary develop this plugin without permission.\nThis plugin only released on MineBBS, see www.minebbs.com\nIf a crash is caused, please repeatedly troubleshoot whether the problem is with the plugin, and if it is caused by the plugin, please submit the crash log.\nThere will inevitably be bugs in the process of use, please give feedback in the discussion area of the MineBBS plugin, and the author will fix it as soon as possible. Please distinguish between comment areas and discussion areas.\nIf you have any objections to the above terms, please stop using and uninstall this plugin.\nIf you agree to use this plugin, please confirm it in ../plugins/Cleaner/EULA.txt .\nchange EULA=false to EULA=true and save it.";
void loadConfig() {
if (!std::filesystem::exists("plugins/Cleaner")){
std::filesystem::create_directories("plugins/Cleaner");
}
if (!std::filesystem::exists("./plugins/Cleaner/README.md")){
WriteAllFile("plugins/Cleaner/README.md",readme,false);
if(GetSystemDefaultLangID() == 0x0804){
logger.warn("插件说明 README.md 不存在,已自动创建!");
}
else{
logger.warn("README.md does not exist, created automatically.");
}
}
if (!std::filesystem::exists("./plugins/Cleaner/EULA.txt")){
WriteAllFile("plugins/Cleaner/EULA.txt","EULA=false",false);
if(GetSystemDefaultLangID() == 0x0804){
logger.warn("插件 EULA 协议不存在,已自动创建!");
}
else{
logger.warn("EULA does not exist, created automatically.");
}
}
if (std::filesystem::exists(ConfigFile)) {
Settings::LoadConfigFromJson(ConfigFile);
}
else {
if(GetSystemDefaultLangID() == 0x0804){
logger.warn("配置文件不存在,已自动创建!");
}
else{
logger.warn("Config file does not exist, created automatically.");
}
Settings::WriteDefaultConfig(ConfigFile);
}
}
+75
View File
@@ -0,0 +1,75 @@
#include "Global.h"
#include <llapi/FormUI.h>
#include "setting.h"
#include <llapi/mc/Player.hpp>
#include <llapi/mc/Level.hpp>
using namespace LanguageSettings;
using namespace Form;
string finished;
extern bool checkcanvote;
extern bool checktimeout;
extern int ac_count;
extern string before;
extern void _CleanerMain();
void ConfirmForm(Player* player){
ModalForm form(guitit, reask, reok, reno);
form.sendTo(player, [](Player* player, bool isConfirm){
if(isConfirm){
if(checktimeout = true){
ac_count++;
player->sendText(reac);
}
else{
player->sendText(reout);
}
}
else{
if(checktimeout = true){
player->sendText(rede);
}
else{
player->sendText(reout);
}
}
});
}
void VoteForm(Player* player){
ModalForm form(guitit, guiqus, sendok, sendno);
form.sendTo(player, [](Player* player, bool isConfirm){
if(isConfirm){
int t;
auto players = Global<Level>->getAllPlayers();
for(t = 0; t <= players.size()-1; t++){
ConfirmForm(players[t]);
}
ac_count = 0;
checktimeout = true;
checkcanvote = false;
Schedule::delay([]{
checkcanvote = true;
},20*Settings::cd);
Schedule::delay([]{
auto all = Global<Level>->getAllPlayers().size();
int caculate = 100*ac_count/all;
checktimeout = false;
if(caculate >= Settings::percentage){
Global<Level>->broadcastText(before + votesuccess,TextType::RAW);
_CleanerMain();
}
else{
Global<Level>->broadcastText(before + votefail,TextType::RAW);
}
},20*Settings::votedelay);
}
else{
player->sendText(sendcancel);
}
});
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include "version.h"
#define ConfigFile "plugins/Cleaner/config.json"
#define LanguageFile "plugins/Cleaner/language.json"
#include <iostream>
#include <llapi/LoggerAPI.h>
#include <llapi/Global.h>
#include <llapi/ScheduleAPI.h>
#include <llapi/mc/Actor.hpp>
#include <llapi/mc/ItemActor.hpp>
#include <llapi/mc/Level.hpp>
#include <stdio.h>
#include <WinNls.h>
#include <windows.h>
#include <cstdio>
using namespace std;
extern Logger logger;
+200
View File
@@ -0,0 +1,200 @@
#include <llapi/utils/FileHelper.h>
#include <Nlohmann/json.hpp>
#include "Global.h"
#include "setting.h"
#define TRJ(key1,key2,val) \
if (json.find(key1) != json.end()) { \
if (json.at(key1).find(key2) != json.at(key1).end()) {\
const nlohmann::json& out2 = json.at(key1).at(key2); \
out2.get_to(val);}} \
void loadLanguage() {
if (std::filesystem::exists(LanguageFile)) {
try {
LanguageSettings::LoadLanguageFromJson(LanguageFile);
}
catch (std::exception& e) {
if(GetSystemDefaultLangID() == 0x0804){
logger.error("未知错误: {}\n正在删除语言文件...", e.what());
}
else{
logger.error("Unknown Error: {}\nRemoving language file...", e.what());
}
remove(LanguageFile);
exit(1);
}
catch (...) {
if(GetSystemDefaultLangID() == 0x0804){
logger.error("语言文件异常!正在删除语言文件...");
}
else{
logger.error("Invalid Language file! Removing language file...");
}
remove(LanguageFile);
exit(1);
}
}
else {
if(GetSystemDefaultLangID() == 0x0804){
logger.warn("语言文件不存在,已自动创建!");
}
else{
logger.warn("Language file does not exist, created automatically.");
}
LanguageSettings::WriteDefaultLanguage(LanguageFile);
}
}
namespace LanguageSettings {
string cmdplonly = "该命令只能由玩家执行!";
string output01 = "系统将在 {0} 秒后自动清理服务器实体!";
string output02 = "请注意!系统将在 {0} 秒后自动清理服务器实体!";
string output4 = "清理完成!本次总共清理了 {0} 个实体。";
string cmdvote = "发起实体清理投票。";
string cmdclean = "清理服务器实体。";
string opclean = "管理员启用了服务器服务器实体清理。";
string cooling = "投票清理冷却...";
string votesuccess = "投票清理成功!";
string votefail = "投票清理失败!玩家同意比例未达标!";
string guitit = "投票清理";
string guiqus = "你是否要发起投票清理?";
string sendok = "发起投票";
string sendno = "我再想想";
string sendcancel = "投票已取消!";
string reask = "你是否同意现在清理服务器实体?";
string reok = "同意";
string reno = "拒绝";
string reout = "投票已过期!";
string reac = "你已同意实体清理。";
string rede = "你已拒绝实体清理。";
string notice = "通知";
string trigger1 = "检测到服务器实体过多!!当前服务器存在 {0} 个可清理实体,已启动自动清理程序。";
string reloadcmd = "热重载Cleaner插件";
string reloadsuccess = "已重载Cleaner插件,部分配置可能需要重启服务器才能生效。";
string tpscmd = "查询服务器TPS";
string tpscmdout = "当前服务器实时TPS {1} §r,平均TPS {2}";
string triggertpsclean = "当前服务器TPS过低!!服务器平均TPS {0}\n系统已启动清理程序。";
string cmddespawn = "通过Despawn清除实体";
string notarget = "没有与选择器匹配的目标";
string despawnsuccess = "已成功通过Despawn清除了 {0} 个实体";
nlohmann::json globaljson() {
nlohmann::json json;
json["Language"]["command.error.player_only"] = cmdplonly;
json["Language"]["output.count1"] = output01;
json["Language"]["output.count2"] = output02;
json["Language"]["output.finish"] = output4;
json["Language"]["command.voteclean"] = cmdvote;
json["Language"]["command.clean"] = cmdclean;
json["Language"]["command.reload"] = reloadcmd;
json["Language"]["command.despawn"] = cmddespawn;
json["Language"]["command.error.notarget"] = notarget;
json["Language"]["command.despawn.success"] = despawnsuccess;
json["Language"]["output.reload"] = reloadsuccess;
json["Language"]["output.opclean"] = opclean;
json["Language"]["vote.cd"] = cooling;
json["Language"]["vote.succeed"] = votesuccess;
json["Language"]["vote.title"] = guitit;
json["Language"]["vote.confirm.subtitle"] = guiqus;
json["Language"]["vote.confirm.ok"] = sendok;
json["Language"]["vote.confirm.no"] = sendno;
json["Language"]["vote.confirm.cancel"] = sendcancel;
json["Language"]["vote.gui.subtitle"] = reask;
json["Language"]["vote.gui.ok"] = reok;
json["Language"]["vote.gui.no"] = reno;
json["Language"]["vote.gui.timeout"] = reout;
json["Language"]["vote.gui.accept"] = reac;
json["Language"]["vote.gui.deny"] = rede;
json["Language"]["vote.toast.notice"] = notice;
json["Language"]["output.triggerautoclean"] = trigger1;
json["Language"]["command.tps"] = tpscmd;
json["Language"]["command.tps.output"] = tpscmdout;
json["Language"]["output.triggerautocleantps"] = triggertpsclean;
return json;
}
void initjson(nlohmann::json json) {
TRJ("Language","command.error.player_only",cmdplonly);
TRJ("Language","output.count1",output01);
TRJ("Language","output.count2",output02);
TRJ("Language","output.finish",output4);
TRJ("Language","command.voteclean",cmdvote);
TRJ("Language","command.clean",cmdclean);
TRJ("Language","command.reload",reloadcmd);
TRJ("Language","output.reload",reloadsuccess);
TRJ("Language","output.opclean",opclean);
TRJ("Language","vote.cd",cooling);
TRJ("Language","vote.succeed",votesuccess);
TRJ("Language","vote.fail",votefail);
TRJ("Language","vote.title",guitit);
TRJ("Language","vote.confirm.subtitle",guiqus);
TRJ("Language","vote.confirm.ok",sendok);
TRJ("Language","vote.confirm.no",sendno);
TRJ("Language","vote.confirm.cancel",sendcancel);
TRJ("Language","vote.gui.subtitle",reask);
TRJ("Language","vote.gui.ok",reok);
TRJ("Language","vote.gui.no",reno);
TRJ("Language","vote.gui.timeout",reout);
TRJ("Language","vote.gui.accept",reac);
TRJ("Language","vote.gui.deny",rede);
TRJ("Language","vote.toast.notice",notice);
TRJ("Language","output.triggerautoclean",trigger1);
TRJ("Language","command.tps",tpscmd);
TRJ("Language","command.tps.output",tpscmdout);
TRJ("Language","output.triggerautocleantps",triggertpsclean);
TRJ("Language","command.despawn",cmddespawn);
TRJ("Language","command.error.notarget",notarget);
TRJ("Language","command.despawn.success",despawnsuccess);
}
void WriteDefaultLanguage(const std::string& fileName) {
std::ofstream file(fileName);
if (!file.is_open()) {
if(GetSystemDefaultLangID() == 0x0804){
logger.warn("无法打开语言文件!");
}
else{
logger.warn("Fail to open language file!");
}
return;
}
auto json = globaljson();
file << json.dump(4);
file.close();
}
void LoadLanguageFromJson(const std::string& fileName) {
std::ifstream file(fileName);
if (!file.is_open()) {
if(GetSystemDefaultLangID() == 0x0804){
logger.warn("无法打开语言文件!");
}
else{
logger.warn("Fail to open language file!");
}
return;
}
nlohmann::json json;
file >> json;
file.close();
initjson(json);
WriteDefaultLanguage(fileName);
}
void reloadJson(const std::string& fileName) {
std::ofstream file(fileName);
if (file){
file << globaljson().dump(4);
}
else{
if(GetSystemDefaultLangID() == 0x0804){
logger.warn("无法重载语言文件!");
}
else{
logger.warn("Fail to reload language file!");
}
}
file.close();
}
}
+90
View File
@@ -0,0 +1,90 @@
#include "version.h"
#include <llapi/EventAPI.h>
#include <llapi/LoggerAPI.h>
#include <llapi/ServerAPI.h>
#include "Global.h"
#include "setting.h"
#include <llapi/RemoteCallAPI.h>
using namespace std;
extern Logger logger;
extern void Cleaner();
extern void AutoClean();
extern void RegVoteCommand();
extern void RegCleanCommand();
extern void RegReloadCommand();
extern void ReloadCleaner();
extern void _CleanerMain();
extern void CleanerMain();
extern void CaculateTPS();
extern void RegTPSCommand();
extern void TPSClean();
extern void RegDespawnCommand();
extern unsigned short Tick_per_second;
extern float Tick_per_minute;
void Despawn(Actor* entity){
entity->despawn();
}
void PluginInit(){
cout << R"( )" << endl;
cout << R"( ________ _ )" << endl;
cout << R"( / ____ \| | )" << endl;
cout << R"( | | |_|| | )" << endl;
cout << R"( | | | | ____ ______ ____ ____ _____ )" << endl;
cout << R"( | | _ | | / __ \ / __ // __ \ / __ \ / ___/ )" << endl;
cout << R"( | |____| || |/ /___// /_/ // / / // /___// / )" << endl;
cout << R"( \________/|_|\____/ \____//_/ /_/ \____//_/ )" << endl;
cout << R"( )" << endl;
cout << R"( -------- A Powerful Entity Cleanup Plugin -------- )" << endl;
cout << R"( )" << endl;
cout << R"( )" << endl;
if(GetSystemDefaultLangID() == 0x0804){
logger.info("当前版本 {}.{}.{} ,支持 BDS - 1.19.6x ,版本协议 {}",PLUGIN_VERSION_MAJOR,PLUGIN_VERSION_MINOR,PLUGIN_VERSION_REVISION,TARGET_BDS_PROTOCOL_VERSION);
logger.info("插件作者 Tsubasa6848");
logger.info("正在加载 Cleaner ...");
logger.info("这个插件是免费的,如果你花钱了,请立即差评并要求RNM退钱。");
}
else{
logger.info("Current Version: {}.{}.{} , support BDS - 1.19.6x , protocal version {}",PLUGIN_VERSION_MAJOR,PLUGIN_VERSION_MINOR,PLUGIN_VERSION_REVISION,TARGET_BDS_PROTOCOL_VERSION);
logger.info("Plugin Author: Tsubasa6848");
logger.info("Loading Cleaner ...");
logger.info("This plugin is free, and if you paid for it, you must have been scammed.");
}
Event::ServerStartedEvent::subscribe([](const Event::ServerStartedEvent) {
CaculateTPS();
RegCleanCommand();
Cleaner();
if(Settings::enablevote == true){
RegVoteCommand();
}
if(Settings::regtpscmd == true){
RegTPSCommand();
}
if(Settings::regdespawncmd == true){
RegDespawnCommand();
}
if(Settings::enableautoclean == true){
AutoClean();
}
if(Settings::enabletpsclean == true){
TPSClean();
}
RegReloadCommand();
return true;
});
RemoteCall::exportAs("Cleaner", "ReloadCleaner", []() -> void { return ReloadCleaner(); });
RemoteCall::exportAs("Cleaner", "Clean", []() -> void { return _CleanerMain(); });
RemoteCall::exportAs("Cleaner", "CleanMain", []() -> void { return CleanerMain(); });
RemoteCall::exportAs("Cleaner", "GetCurrentTPS", []() -> unsigned short { return Tick_per_second; });
RemoteCall::exportAs("Cleaner", "GetAverageTPS", []() -> float { return Tick_per_minute; });
RemoteCall::exportAs("Cleaner", "Despawn", [](Actor* entity) -> void { return Despawn(entity); });
}
+100
View File
@@ -0,0 +1,100 @@
#include <llapi/RegCommandAPI.h>
#include <llapi/DynamicCommandAPI.h>
#include "Global.h"
#include "setting.h"
#include <llapi/mc/Level.hpp>
using namespace RegisterCommandHelper;
using namespace LanguageSettings;
extern void VoteForm(Player* player);
extern void _CleanerMain();
string endstr = " §b§l---- Cleaner";
int ac_count = 0;
bool checktimeout = false;
bool checkcanvote = true;
extern string before;
void RegVoteCommand(){
using ParamType = DynamicCommand::ParameterType;
auto command = DynamicCommand::createCommand(Settings::command, cmdvote + endstr, CommandPermissionLevel::Any, { (CommandFlagValue)0x80 }, { (CommandFlagValue)1 });
command->addOverload();
command->setCallback([](DynamicCommand const& command, CommandOrigin const& origin, CommandOutput& output, std::unordered_map<std::string, DynamicCommand::Result>& results) {
auto pl = origin.getPlayer();
if(checkcanvote == false){
return output.error(cooling);
}
else{
if(pl->isPlayer() == true){
auto player = (Player*)pl;
VoteForm(player);
return;
}
else{
output.error(cmdplonly);
return;
}
}
});
DynamicCommand::setup(std::move(command));
}
void RegCleanCommand(){
using ParamType = DynamicCommand::ParameterType;
auto command = DynamicCommand::createCommand(Settings::cleancommand, cmdclean + endstr, CommandPermissionLevel::GameMasters, { (CommandFlagValue)0x80 }, { (CommandFlagValue)1 });
command->addOverload();
command->setCallback([](DynamicCommand const& command, CommandOrigin const& origin, CommandOutput& output, std::unordered_map<std::string, DynamicCommand::Result>& results) {
if(Settings::sendbroadcast == true){
Global<Level>->broadcastText(before + opclean,TextType::RAW);
}
if(Settings::sendtoast == true){
auto players = Global<Level>->getAllPlayers();
if(players.size() >= 1){
for(int tg = 0; tg <= players.size()-1; tg++){
players[tg]->sendToastPacket(notice,before + opclean);
}
}
}
_CleanerMain();
});
DynamicCommand::setup(std::move(command));
}
void ReloadCleaner(){
Settings::LoadConfigFromJson(ConfigFile);
LanguageSettings::LoadLanguageFromJson(LanguageFile);
}
void RegReloadCommand(){
using ParamType = DynamicCommand::ParameterType;
auto command = DynamicCommand::createCommand("reloadcleaner", reloadcmd + endstr, CommandPermissionLevel::GameMasters, { (CommandFlagValue)0x80 }, { (CommandFlagValue)1 });
command->addOverload();
command->setCallback([](DynamicCommand const& command, CommandOrigin const& origin, CommandOutput& output, std::unordered_map<std::string, DynamicCommand::Result>& results) {
ReloadCleaner();
return output.success(reloadsuccess);
});
DynamicCommand::setup(std::move(command));
}
void RegDespawnCommand(){
using ParamType = DynamicCommand::ParameterType;
auto command = DynamicCommand::createCommand(Settings::despawncmd, cmddespawn + endstr, CommandPermissionLevel::GameMasters, { (CommandFlagValue)0x80 }, { (CommandFlagValue)1 });
command->mandatory("target",ParamType::Actor);
command->addOverload({"target"});
command->setCallback([](DynamicCommand const& command, CommandOrigin const& origin, CommandOutput& output, std::unordered_map<std::string, DynamicCommand::Result>& results) {
auto ens = results["target"].get<std::vector<Actor*>>();
if(ens.size() >= 1){
for(int i = 0; i <= ens.size()-1 ; i++){
ens[i]->despawn();
}
LoadLanguageFromJson(LanguageFile);
return output.success(ReplaceStr(despawnsuccess,"{0}",std::to_string(ens.size())));
}
else return output.error(notarget);
});
DynamicCommand::setup(std::move(command));
}
+72
View File
@@ -0,0 +1,72 @@
#include <llapi/LoggerAPI.h>
#include <llapi/EventAPI.h>
#include <llapi/mc/Actor.hpp>
#include <llapi/mc/Player.hpp>
#include <llapi/ScheduleAPI.h>
#include <llapi/RegCommandAPI.h>
#include <llapi/DynamicCommandAPI.h>
#include "setting.h"
#include "version.h"
#include "Global.h"
#include <llapi/RemoteCallAPI.h>
extern Logger logger;
extern string endstr;
unsigned short ticks = 0;
unsigned short Tick_per_second;
float Tick_per_minute;
std::list<unsigned short> ticks_per_minute;
std::string TpsColor1(unsigned short tps) {
if (tps < 15) return "§6" + std::to_string(tps);
if (tps <= 10) return "§c" + std::to_string(tps);
return "§a" + std::to_string(tps);
}
std::string TpsColor2(float tps) {
auto pre1 = std::to_string(tps);
auto pre2 = pre1.replace(pre1.end()-4,pre1.end(),"");
if (tps < 15) return "§6" + pre2;
if (tps <= 10) return "§c" + pre2;
return "§a" + pre2;
}
void CaculateTPS() {
Schedule::repeat([]() {
ticks++;
}, 1);
std::thread([] {
while (true) {
std::this_thread::sleep_for(std::chrono::seconds(1));
if (ticks > 20) {
ticks = 20;
}
Tick_per_second = ticks;
ticks_per_minute.push_back(ticks);
ticks = 0;
if (ticks_per_minute.size() >= 60) {
ticks_per_minute.clear();
continue;
}
unsigned short ticks_minute = 0;
for (unsigned short i : ticks_per_minute) {
ticks_minute = ticks_minute + i;
}
Tick_per_minute = (float)ticks_minute / (float)ticks_per_minute.size();
}
})
.detach();
}
void RegTPSCommand() {
using ParamType = DynamicCommand::ParameterType;
auto command = DynamicCommand::createCommand("tps", LanguageSettings::tpscmd + endstr, CommandPermissionLevel::Any, { (CommandFlagValue)0x80 }, { (CommandFlagValue)1 });
command->addOverload();
command->setCallback([](DynamicCommand const& command, CommandOrigin const& origin, CommandOutput& output, std::unordered_map<std::string, DynamicCommand::Result>& results) {
LanguageSettings::LoadLanguageFromJson(LanguageFile);
auto pr1 = ReplaceStr(LanguageSettings::tpscmdout,"{1}",TpsColor1(Tick_per_second));
output.success(ReplaceStr(pr1,"{2}",TpsColor2(Tick_per_minute)));
});
DynamicCommand::setup(std::move(command));
}
+101
View File
@@ -0,0 +1,101 @@
#include <llapi/LoggerAPI.h>
#include <llapi/ServerAPI.h>
#include "Global.h"
#include "version.h"
#include <stdio.h>
#include <WinNls.h>
extern void loadConfig();
extern void loadLanguage();
void PluginInit();
Logger logger(PLUGIN_NAME);
void CheckEULA(){
auto readEULA = ReadAllFile("plugins/Cleaner/EULA.txt");
auto EULA = ReplaceStr(readEULA.value()," ","");
if(EULA == "EULA=true"){
PluginInit();
}
else{
if(GetSystemDefaultLangID() == 0x0804){
if(MessageBox(NULL,TEXT("使用Cleaner插件将视为你同意本插件使用协议(EULA)\n\n你是否同意使用Cleaner插件?"),TEXT("Cleaner"),MB_DEFBUTTON2 | MB_ICONQUESTION | MB_YESNOCANCEL) == 6){
WriteAllFile("plugins/Cleaner/EULA.txt","EULA=true");
PluginInit();
}
else{
Logger().fatal("无法加载插件 Cleaner\n 未同意插件 EULA 协议或插件 EULA 协议配置异常。\n 请同意插件 EULA 协议后再重启服务器,具体请参见插件 README.md\n 如果无法接受插件 EULA 协议,请卸载本插件!");
}
}
else{
if(MessageBox(NULL,TEXT("By using the plugin Cleaner, you must agree plugin EULA.\n\nDo you agree to use Cleaner?"),TEXT("Cleaner"),MB_YESNOCANCEL | MB_DEFBUTTON2 | MB_ICONQUESTION) == 6){
WriteAllFile("plugins/Cleaner/EULA.txt","EULA=true");
PluginInit();
}
else{
Logger().fatal("Fail to Load Cleaner!\n Please accept the EULA or check the EULA settings.\n Restart the server after you accepted the EULA. Pleade read README.md\n If you can`t accept the EULA, please uninstall the plugin.");
}
}
}
}
void CheckProtocolVersion()
{
#ifdef TARGET_BDS_PROTOCOL_VERSION
auto current_protocol = ll::getServerProtocolVersion();
if (TARGET_BDS_PROTOCOL_VERSION != current_protocol)
{
if(GetSystemDefaultLangID() == 0x0804){
logger.error(" 不兼容的BDS版本!插件兼容 BDS-1.19.6x ,版本协议: {}。\n 强制加载可能导致服务器崩溃和发生未知错误,请更换适配的插件版本或使用适配的BDS版本。",TARGET_BDS_PROTOCOL_VERSION);
MessageBox(NULL,TEXT("不兼容的BDS版本!\n\n请更换适配的插件版本或使用适配的BDS版本。"),TEXT("Cleaner"),MB_ICONERROR | MB_OK);
}
else{
logger.error("Incompatible BDS version! Plugin Cleaner is compatible with BDS-1.19.6x, protocal version: {}。\n To avoid crash, please update this plugin or use a compatible BDS version!",TARGET_BDS_PROTOCOL_VERSION);
MessageBox(NULL,TEXT("Incompatible BDS version!\n\nPlease update this plugin or use a compatible BDS version."),TEXT("Cleaner"),MB_ICONERROR | MB_OK);
}
}
else{
loadConfig();
loadLanguage();
CheckEULA();
}
#endif
}
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
ll::registerPlugin(
PLUGIN_NAME,
PLUGIN_INTRODUCTION,
ll::Version(PLUGIN_VERSION_MAJOR, PLUGIN_VERSION_MINOR, PLUGIN_VERSION_REVISION, PLUGIN_LLVERSION_STATUS),
std::map<std::string, std::string>{
{"Author", PLUGIN_AUTHOR},
});
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C"
{
_declspec(dllexport) void onPostInit()
{
std::ios::sync_with_stdio(false);
CheckProtocolVersion();
}
}
+200
View File
@@ -0,0 +1,200 @@
#include <llapi/utils/FileHelper.h>
#include <Nlohmann/json.hpp>
#include "Global.h"
#define TRJ(key1, key2, val) \
if (json.find(key1) != json.end()) \
{ \
if (json.at(key1).find(key2) != json.at(key1).end()) \
{ \
const nlohmann::json &out2 = json.at(key1).at(key2); \
out2.get_to(val); \
} \
}
namespace Settings
{
int CleanInterval = 300;
int cd = 120;
int votedelay = 30;
bool sendtoast = true;
bool logtoconsole = true;
bool enableitem = true;
bool enablevote = true;
bool enablemobs = true;
bool cleanpeacefulmobs = false;
bool cleanmonsters = true;
bool Exclude = true;
bool enableinanimate = true;
bool enableautoclean = true;
bool enableschdule = true;
bool sendbroadcast = true;
int triggercount = 500;
int percentage = 50;
int pre1 = 20;
int pre2 = 5;
bool enabletpsclean = false;
bool regtpscmd = false;
bool regdespawncmd = false;
int triggertps = 5;
bool mobblackonly = false;
int ExistTicks = 0;
string despawncmd = "despawn";
string tpscmd = "tps";
string command = "voteclean";
string cleancommand = "clean";
std::unordered_set<string> MobList = {
"minecraft:ender_dragon",
"minecraft:shulker",
"minecraft:elder_guardian",
"minecraft:piglin_brute"
};
std::unordered_set<string> MobBlackList = {
"minecraft:guardian",
"minecraft:zombie_pigman"
};
std::unordered_set<string> ItemList = {
"minecraft:netherite_helmet",
"minecraft:netherite_chestplate",
"minecraft:netherite_leggings",
"minecraft:netherite_boots",
"minecraft:netherite_sword",
"minecraft:shulker_box",
"minecraft:undyed_shulker_box",
"minecraft:elytra",
"minecraft:dragon_egg",
"minecraft:nether_star"};
std::unordered_set<string> InanimateList = {
"minecraft:xp_orb",
"minecraft:arrow",
"minecraft:fireball",
"minecraft:small_fireball",
"minecraft:wither_skull",
"minecraft:wither_skull_dangerous",
"minecraft:dragon_fireball"
};
std::unordered_set<string> IgnoreTags = {
"ignore",
"不清理"
};
nlohmann::json globaljson()
{
nlohmann::json json;
json["Basic"]["SendBroadcast"] = sendbroadcast;
json["Basic"]["ConsoleLog"] = logtoconsole;
json["Basic"]["CleanCommand"] = cleancommand;
json["Basic"]["SendToast"] = sendtoast;
json["Basic"]["RegisterTPSCommand"] = regtpscmd;
json["Basic"]["TPSCommand"] = tpscmd;
json["Basic"]["RegisterDespawnCommand"] = regdespawncmd;
json["Basic"]["DespawnCommand"] = despawncmd;
json["ScheduleClean"]["CleanInterval"] = CleanInterval;
json["ScheduleClean"]["Enabled"] = enableschdule;
json["VoteClean"]["Enabled"] = enablevote;
json["VoteClean"]["VoteCleanCommand"] = command;
json["VoteClean"]["Percentage"] = percentage;
json["VoteClean"]["CD"] = cd;
json["VoteClean"]["Delay"] = votedelay;
json["CleanItem"]["Enabled"] = enableitem;
json["CleanItem"]["Whitelist"] = ItemList;
json["CleanItem"]["ExistTicks"] = ExistTicks;
json["CleanMobs"]["Enabled"] = enablemobs;
json["CleanMobs"]["CleanPeacefulMobs"] = cleanpeacefulmobs;
json["CleanMobs"]["CleanMonstors"] = cleanmonsters;
json["CleanMobs"]["EnableAutoExclude"] = Exclude;
json["CleanMobs"]["Whitelist"] = MobList;
json["CleanMobs"]["BlackListOnly"] = mobblackonly;
json["CleanMobs"]["BlackList"] = MobBlackList;
json["CleanMobs"]["IgnoreTags"] = IgnoreTags;
json["CleanInanimate"]["Enabled"] = enableinanimate;
json["CleanInanimate"]["Blacklist"] = InanimateList;
json["AutoCleanCount"]["Enabled"] = enableautoclean;
json["AutoCleanCount"]["TriggerCount"] = triggercount;
json["AutoCleanTPS"]["TriggerTPS"] = triggertps;
json["AutoCleanTPS"]["Enabled"] = enabletpsclean;
json["Basic"]["Notice1"] = pre1;
json["Basic"]["Notice2"] = pre2;
return json;
}
void initjson(nlohmann::json json)
{
TRJ("Basic","SendBroadcast",sendbroadcast);
TRJ("Basic", "ConsoleLog", logtoconsole);
TRJ("Basic", "CleanCommand", cleancommand);
TRJ("Basic", "SendToast", sendtoast);
TRJ("Basic","RegisterTPSCommand",regtpscmd);
TRJ("Basic","TPSCommand",tpscmd);
TRJ("ScheduleClean", "CleanInterval", CleanInterval);
TRJ("ScheduleClean", "Enabled", enableschdule);
TRJ("VoteClean", "Enabled", enablevote);
TRJ("VoteClean", "Command", command);
TRJ("VoteClean", "Percentage", percentage);
TRJ("VoteClean", "CD", cd);
TRJ("VoteClean", "Delay", votedelay);
TRJ("CleanItem", "Enabled", enableitem);
TRJ("CleanItem", "Whitelist", ItemList);
TRJ("CleanItem","ExistTicks", ExistTicks);
TRJ("CleanMobs", "Enabled", enablemobs);
TRJ("CleanMobs", "CleanPeacefulMobs", cleanpeacefulmobs);
TRJ("CleanMobs", "CleanMonstors", cleanmonsters);
TRJ("CleanMobs", "EnableAutoExclude", Exclude);
TRJ("CleanMobs", "Whitelist", MobList);
TRJ("CleanMobs","BlackListOnly",mobblackonly);
TRJ("CleanMobs","BlackList",MobBlackList);
TRJ("CleanInanimate", "Enabled", enableinanimate);
TRJ("CleanInanimate", "Blacklist", InanimateList);
TRJ("AutoCleanCount", "Enabled", enableautoclean);
TRJ("AutoCleanCount", "TriggerCount", triggercount);
TRJ("AutoCleanTPS", "Enabled", enabletpsclean);
TRJ("AutoCleanTPS", "TriggerTPS", triggertps);
TRJ("Basic","Notice1",pre1);
TRJ("Basic","Notice2",pre2);
TRJ("Basic","RegisterDespawnCommand",regdespawncmd);
TRJ("Basic","DespawnCommand",despawncmd);
TRJ("CleanMobs","IgnoreTags", IgnoreTags);
}
void WriteDefaultConfig(const std::string &fileName)
{
std::ofstream file(fileName);
if (!file.is_open())
{
logger.error("无法打开配置文件");
return;
}
auto json = globaljson();
file << json.dump(4);
file.close();
}
void LoadConfigFromJson(const std::string &fileName)
{
std::ifstream file(fileName);
if (!file.is_open())
{
logger.error("无法打开配置文件");
return;
}
nlohmann::json json;
file >> json;
file.close();
initjson(json);
WriteDefaultConfig(fileName);
}
void reloadJson(const std::string &fileName)
{
std::ofstream file(fileName);
if (file)
{
file << globaljson().dump(4);
}
else
{
logger.error("配置文件异常!");
}
file.close();
}
}
+87
View File
@@ -0,0 +1,87 @@
#pragma once
#include <llapi/utils/FileHelper.h>
#include <Nlohmann/json.hpp>
namespace Settings {
extern int CleanInterval;
extern bool logtoconsole;
extern bool enableitem;
extern bool enablevote;
extern bool sendtoast;
extern int cd;
extern int votedelay;
extern bool enablemobs;
extern bool cleanpeacefulmobs;
extern bool cleanmonsters;
extern bool Exclude;
extern bool enableinanimate;
extern int percentage;
extern int triggercount;
extern bool enableautoclean;
extern bool enableschdule;
extern bool sendbroadcast;
extern int percentage;
extern int pre1;
extern int pre2;
extern bool enabletpsclean;
extern bool regtpscmd;
extern int triggertps;
extern int ExistTicks;
extern bool regdespawncmd;
extern string despawncmd;
extern string tpscmd;
extern string command;
extern string cleancommand;
extern std::unordered_set<string> MobBlackList;
extern bool mobblackonly;
extern std::unordered_set<string> MobList;
extern std::unordered_set<string> ItemList;
extern std::unordered_set<string> InanimateList;
extern std::unordered_set<string> IgnoreTags;
extern nlohmann::json globaljson();
void initjson(nlohmann::json json);
void WriteDefaultConfig(const std::string& fileName);
void LoadConfigFromJson(const std::string& fileName);
void reloadJson(const std::string& fileName);
}
namespace LanguageSettings {
extern string cmdplonly;
extern string output01;
extern string output02;
extern string output4;
extern string cmdvote;
extern string cmdclean;
extern string opclean;
extern string cooling;
extern string votesuccess;
extern string votefail;
extern string guitit;
extern string guiqus;
extern string sendok;
extern string sendno;
extern string sendcancel;
extern string reask;
extern string reok;
extern string reno;
extern string reout;
extern string reac;
extern string rede;
extern string notice;
extern string trigger1;
extern string reloadcmd;
extern string reloadsuccess;
extern string tpscmd;
extern string tpscmdout;
extern string triggertpsclean;
extern string cmddespawn;
extern string notarget;
extern string despawnsuccess;
extern nlohmann::json globaljson();
void initjson(nlohmann::json json);
void WriteDefaultLanguage(const std::string& fileName);
void LoadLanguageFromJson(const std::string& fileName);
void reloadJson(const std::string& fileName);
}
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#define PLUGIN_VERSION_DEV 0
#define PLUGIN_VERSION_BETA 1
#define PLUGIN_VERSION_RELEASE 2
#define PLUGIN_NAME "Cleaner"
#define PLUGIN_INTRODUCTION "自定义清理"
#define PLUGIN_AUTHOR "Tsubasa6848"
#define PLUGIN_VERSION_MAJOR 1
#define PLUGIN_VERSION_MINOR 6
#define PLUGIN_VERSION_REVISION 0
#define PLUGIN_VERSION_BUILD 0
#define TARGET_BDS_PROTOCOL_VERSION 567
#define __TO_VERSION_STRING(ver) #ver
#define TO_VERSION_STRING(ver) __TO_VERSION_STRING(ver)
#define PLUGIN_LLVERSION_STATUS ll::Version::Release
#define PLUGIN_FILE_VERSION_STRING TO_VERSION_STRING(PLUGIN_VERSION_MAJOR.PLUGIN_VERSION_MINOR.PLUGIN_VERSION_REVISION.PLUGIN_VERSION_ACTIONS)
#define FILE_VERSION_BLOCK_HEADER 0x04004B0L
#define FILE_VERSION_COMPANY_NAME PLUGIN_AUTHOR
#define FILE_VERSION_LEGAL_COPYRIGHT "Copyright (C) 2022"
#define FILE_VERSION_FILE_DESCRIPTION PLUGIN_INTRODUCTION
#define FILE_VERSION_FILE_VERSION_STRING PLUGIN_FILE_VERSION_STRING
#define FILE_VERSION_INTERNAL_NAME PLUGIN_NAME
#define FILE_VERSION_ORIGINAL_FILENAME PLUGIN_NAME ".dll"
#define FILE_VERSION_PRODUCT_NAME FILE_VERSION_INTERNAL_NAME
#define FILE_VERSION_PRODUCT_VERSION_STRING PLUGIN_FILE_VERSION_STRING
#define FILE_VERSION_FILE_VERSION PLUGIN_VERSION_MAJOR, PLUGIN_VERSION_MINOR, PLUGIN_VERSION_REVISION, PLUGIN_VERSION_BUILD
#define FILE_VERSION_PRODUCT_VERSION FILE_VERSION_FILE_VERSION