feat: vote clean
This commit is contained in:
@@ -11,9 +11,6 @@ bool mSendToast = true;
|
|||||||
|
|
||||||
namespace Cleaner {
|
namespace Cleaner {
|
||||||
|
|
||||||
using namespace ll::schedule;
|
|
||||||
using namespace ll::chrono_literals;
|
|
||||||
|
|
||||||
static std::shared_ptr<ll::schedule::task::Task<ll::chrono::ServerClock>> mAutoCleanTask;
|
static std::shared_ptr<ll::schedule::task::Task<ll::chrono::ServerClock>> mAutoCleanTask;
|
||||||
static std::shared_ptr<ll::schedule::task::Task<ll::chrono::ServerClock>> mCheckCleanTask;
|
static std::shared_ptr<ll::schedule::task::Task<ll::chrono::ServerClock>> mCheckCleanTask;
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,6 @@
|
|||||||
namespace Cleaner {
|
namespace Cleaner {
|
||||||
|
|
||||||
void loadCleaner() {
|
void loadCleaner() {
|
||||||
ListenEvents();
|
|
||||||
RegisterCommands();
|
|
||||||
if (Config->getValue<bool>({"ScheduleClean", "Enabled"}, false)) {
|
if (Config->getValue<bool>({"ScheduleClean", "Enabled"}, false)) {
|
||||||
Cleaner::AutoCleanTask(Config->getValue<int>({"ScheduleClean", "CleanInterval"}, 3000));
|
Cleaner::AutoCleanTask(Config->getValue<int>({"ScheduleClean", "CleanInterval"}, 3000));
|
||||||
}
|
}
|
||||||
@@ -21,15 +19,14 @@ void loadCleaner() {
|
|||||||
ConfigFile::mSendToast = Config->getValue<bool>({"Basic", "SendToast"}, true);
|
ConfigFile::mSendToast = Config->getValue<bool>({"Basic", "SendToast"}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unloadCleaner() {
|
void unloadCleaner() { stopAllTasks(); }
|
||||||
stopAllTasks();
|
|
||||||
delete Config;
|
|
||||||
delete Language;
|
|
||||||
}
|
|
||||||
|
|
||||||
void reloadCleaner() {
|
void reloadCleaner() {
|
||||||
unloadCleaner();
|
unloadCleaner();
|
||||||
initPlugin();
|
Config->init();
|
||||||
|
std::string languageCode = Config->getValue<std::string>({"Basic", "Language"}, "en_US");
|
||||||
|
Language->loadAllLanguages();
|
||||||
|
Language->chooseLanguage(languageCode);
|
||||||
loadCleaner();
|
loadCleaner();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
|
|
||||||
|
using namespace ll::schedule;
|
||||||
|
using namespace ll::chrono_literals;
|
||||||
|
|
||||||
namespace Cleaner {
|
namespace Cleaner {
|
||||||
|
|
||||||
|
extern ServerTimeScheduler scheduler;
|
||||||
|
|
||||||
extern int ExecuteClean();
|
extern int ExecuteClean();
|
||||||
extern int CountEntities();
|
extern int CountEntities();
|
||||||
|
|
||||||
@@ -10,5 +15,15 @@ extern void AutoCleanTask(int seconds);
|
|||||||
extern void CheckCleanTask(int max_entities, float min_tps);
|
extern void CheckCleanTask(int max_entities, float min_tps);
|
||||||
extern void ListenEvents();
|
extern void ListenEvents();
|
||||||
extern void stopAllTasks();
|
extern void stopAllTasks();
|
||||||
|
extern void CleanTask();
|
||||||
|
extern void reloadCleaner();
|
||||||
|
extern void loadCleaner();
|
||||||
|
extern void unloadCleaner();
|
||||||
|
|
||||||
} // namespace Cleaner
|
} // namespace Cleaner
|
||||||
|
|
||||||
|
namespace VoteClean {
|
||||||
|
|
||||||
|
extern void voteCommandExecute(Player* pl);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
#include "Cleaner.h"
|
||||||
|
#include "Global.h"
|
||||||
|
|
||||||
|
namespace VoteClean {
|
||||||
|
|
||||||
|
bool hasVote = false;
|
||||||
|
bool canVote = true;
|
||||||
|
int playerCount = 0;
|
||||||
|
|
||||||
|
std::unordered_map<mce::UUID, bool> voteList;
|
||||||
|
|
||||||
|
static std::shared_ptr<ll::schedule::task::Task<ll::chrono::ServerClock>> mAutoCleanTask;
|
||||||
|
|
||||||
|
int getPlayerCount() {
|
||||||
|
int result = 0;
|
||||||
|
ll::service::getLevel()->forEachPlayer([&](Player& pl) -> bool {
|
||||||
|
if (!pl.isSimulatedPlayer()) {
|
||||||
|
result++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendVoteForm(Player* pl) {
|
||||||
|
auto fm = ll::form::ModalForm(
|
||||||
|
tr("cleaner.vote.title"),
|
||||||
|
tr("cleaner.vote.subtitle", {pl->getRealName()}),
|
||||||
|
tr("cleaner.vote.ok"),
|
||||||
|
tr("cleaner.vote.no")
|
||||||
|
);
|
||||||
|
ll::service::getLevel()->forEachPlayer([&](Player& pl) -> bool {
|
||||||
|
fm.sendTo(pl, [](Player& player, ll::form::ModalForm::SelectedButton button) {
|
||||||
|
switch (button) {
|
||||||
|
case ll::form::ModalForm::SelectedButton::Upper: {
|
||||||
|
voteList[player.getUuid()] = true;
|
||||||
|
player.sendMessage(tr("cleaner.vote.accept"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case ll::form::ModalForm::SelectedButton::Lower: {
|
||||||
|
voteList[player.getUuid()] = false;
|
||||||
|
player.sendMessage(tr("cleaner.vote.deny"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkVote() {
|
||||||
|
float percentage = Config->getValue<float>({"VoteClean", "Percentage"}, 50.0f) / 100.0f;
|
||||||
|
int voteCount = 0;
|
||||||
|
for (auto& key : voteList) {
|
||||||
|
if (key.second == true) {
|
||||||
|
voteCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float result = ((float)voteCount) / ((float)playerCount);
|
||||||
|
if (result >= percentage) {
|
||||||
|
if (ConfigFile::mAnnounce) {
|
||||||
|
Helper::broadcastMessage(tr("cleaner.vote.succeed"));
|
||||||
|
}
|
||||||
|
if (ConfigFile::mSendToast) {
|
||||||
|
Helper::broadcastToast(tr("cleaner.vote.succeed"));
|
||||||
|
}
|
||||||
|
Cleaner::CleanTask();
|
||||||
|
} else {
|
||||||
|
if (ConfigFile::mAnnounce) {
|
||||||
|
Helper::broadcastMessage(tr("cleaner.vote.failed"));
|
||||||
|
}
|
||||||
|
if (ConfigFile::mSendToast) {
|
||||||
|
Helper::broadcastToast(tr("cleaner.vote.failed"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hasVote = false;
|
||||||
|
playerCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void voteClean(Player* pl) {
|
||||||
|
voteList.clear();
|
||||||
|
canVote = false;
|
||||||
|
hasVote = true;
|
||||||
|
playerCount = getPlayerCount();
|
||||||
|
if (ConfigFile::mAnnounce) {
|
||||||
|
Helper::broadcastMessage(tr("cleaner.vote.voteMessage", {pl->getRealName()}));
|
||||||
|
}
|
||||||
|
if (ConfigFile::mSendToast) {
|
||||||
|
Helper::broadcastToast(tr("cleaner.vote.voteMessage", {pl->getRealName()}));
|
||||||
|
}
|
||||||
|
sendVoteForm(pl);
|
||||||
|
auto cooldown = std::chrono::seconds::duration(Config->getValue<int>({"VoteClean", "Cooldown"}, 120));
|
||||||
|
auto waitTime = std::chrono::seconds::duration(Config->getValue<int>({"VoteClean", "CheckDelay"}, 30));
|
||||||
|
Cleaner::scheduler.add<DelayTask>(cooldown, [] { canVote = false; });
|
||||||
|
Cleaner::scheduler.add<DelayTask>(waitTime, [] { checkVote(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void confirmForm(Player* pl) {
|
||||||
|
auto fm = ll::form::ModalForm(
|
||||||
|
tr("cleaner.vote.title"),
|
||||||
|
tr("cleaner.vote.confirmTubtitle"),
|
||||||
|
tr("cleaner.vote.confirmOk"),
|
||||||
|
tr("cleaner.vote.confirmNo")
|
||||||
|
);
|
||||||
|
fm.sendTo(*pl, [](Player& player, ll::form::ModalForm::SelectedButton button) {
|
||||||
|
switch (button) {
|
||||||
|
case ll::form::ModalForm::SelectedButton::Upper: {
|
||||||
|
return voteClean(&player);
|
||||||
|
}
|
||||||
|
case ll::form::ModalForm::SelectedButton::Lower: {
|
||||||
|
return player.sendMessage(tr("cleaner.vote.cancel"));
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void voteCommandExecute(Player* pl) {
|
||||||
|
if (!hasVote) {
|
||||||
|
if (canVote) {
|
||||||
|
confirmForm(pl);
|
||||||
|
} else {
|
||||||
|
pl->sendMessage(tr("cleaner.vote.cooldown"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (voteList.count(pl->getUuid())) {
|
||||||
|
pl->sendMessage(tr("cleaner.vote.voted"));
|
||||||
|
} else {
|
||||||
|
voteList[pl->getUuid()] = true;
|
||||||
|
pl->sendMessage(tr("cleaner.vote.accept"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace VoteClean
|
||||||
@@ -20,13 +20,6 @@ extern bool mAnnounce;
|
|||||||
extern bool mSendToast;
|
extern bool mSendToast;
|
||||||
} // namespace ConfigFile
|
} // namespace ConfigFile
|
||||||
|
|
||||||
namespace Cleaner {
|
|
||||||
extern void CleanTask();
|
|
||||||
extern void reloadCleaner();
|
|
||||||
extern void loadCleaner();
|
|
||||||
extern void unloadCleaner();
|
|
||||||
} // namespace Cleaner
|
|
||||||
|
|
||||||
namespace Helper {
|
namespace Helper {
|
||||||
extern void broadcastMessage(std::string msg);
|
extern void broadcastMessage(std::string msg);
|
||||||
extern void broadcastToast(std::string msg);
|
extern void broadcastToast(std::string msg);
|
||||||
|
|||||||
+11
-7
@@ -28,11 +28,13 @@ std::string defaultLanguage_en_US = R"({
|
|||||||
"cleaner.vote.deny": "You have declined entity cleaning.",
|
"cleaner.vote.deny": "You have declined entity cleaning.",
|
||||||
"cleaner.vote.no": "Deny",
|
"cleaner.vote.no": "Deny",
|
||||||
"cleaner.vote.ok": "Agree",
|
"cleaner.vote.ok": "Agree",
|
||||||
"cleaner.vote.Subtitle": "Do you agree to clean server entities now?",
|
"cleaner.vote.subtitle": "%1$s lunched a clean vote.\n\n Do you agree to clean server entities now?",
|
||||||
"cleaner.vote.Timeout": "Vote has expired!",
|
"cleaner.vote.timeout": "Vote has expired!",
|
||||||
"cleaner.vote.succeed": "Vote cleaning successful!",
|
"cleaner.vote.succeed": "Vote cleaning successful!",
|
||||||
|
"cleaner.vote.failed": "Vote cleaning did not passed!",
|
||||||
"cleaner.vote.title": "Vote Cleaning",
|
"cleaner.vote.title": "Vote Cleaning",
|
||||||
"cleaner.vote.toastNotice": "Notification"
|
"cleaner.vote.voted": "You have been voted!",
|
||||||
|
"cleaner.vote.voteMessage": "%1$s lunched a clean vote. If you agree cleaning entities but did not received a form, please type command /voteclean to vote."
|
||||||
})";
|
})";
|
||||||
|
|
||||||
std::string defaultLanguage_zh_CN = R"({
|
std::string defaultLanguage_zh_CN = R"({
|
||||||
@@ -53,7 +55,7 @@ std::string defaultLanguage_zh_CN = R"({
|
|||||||
"cleaner.output.reload": "已重载Cleaner插件,部分配置可能需要重启服务器才能生效。",
|
"cleaner.output.reload": "已重载Cleaner插件,部分配置可能需要重启服务器才能生效。",
|
||||||
"cleaner.output.triggerAutoCleanCount": "检测到服务器实体过多!!当前服务器存在 %1$s 个可清理实体,已启动自动清理程序。",
|
"cleaner.output.triggerAutoCleanCount": "检测到服务器实体过多!!当前服务器存在 %1$s 个可清理实体,已启动自动清理程序。",
|
||||||
"cleaner.output.triggerAutoCleanTps": "当前服务器TPS过低!!服务器平均TPS %1$s\n系统已启动清理程序。",
|
"cleaner.output.triggerAutoCleanTps": "当前服务器TPS过低!!服务器平均TPS %1$s\n系统已启动清理程序。",
|
||||||
"cleaner.vote.cooldown": "投票清理冷却...",
|
"cleaner.vote.cooldown": "投票清理正在冷却...",
|
||||||
"cleaner.vote.cancel": "投票已取消!",
|
"cleaner.vote.cancel": "投票已取消!",
|
||||||
"cleaner.vote.confirmNo": "我再想想",
|
"cleaner.vote.confirmNo": "我再想想",
|
||||||
"cleaner.vote.confirmOk": "发起投票",
|
"cleaner.vote.confirmOk": "发起投票",
|
||||||
@@ -62,9 +64,11 @@ std::string defaultLanguage_zh_CN = R"({
|
|||||||
"cleaner.vote.deny": "你已拒绝实体清理。",
|
"cleaner.vote.deny": "你已拒绝实体清理。",
|
||||||
"cleaner.vote.no": "拒绝",
|
"cleaner.vote.no": "拒绝",
|
||||||
"cleaner.vote.ok": "同意",
|
"cleaner.vote.ok": "同意",
|
||||||
"cleaner.vote.Subtitle": "你是否同意现在清理服务器实体?",
|
"cleaner.vote.subtitle": "%1$s 发起了服务器实体清理投票!\n\n你是否同意现在清理服务器实体?",
|
||||||
"cleaner.vote.Timeout": "投票已过期!",
|
"cleaner.vote.timeout": "投票已过期!",
|
||||||
"cleaner.vote.succeed": "投票清理成功!",
|
"cleaner.vote.succeed": "投票清理成功!",
|
||||||
|
"cleaner.vote.failed": "投票清理未通过。",
|
||||||
"cleaner.vote.title": "投票清理",
|
"cleaner.vote.title": "投票清理",
|
||||||
"cleaner.vote.toastNotice": "通知"
|
"cleaner.vote.voted": "你已经投过票了!",
|
||||||
|
"cleaner.vote.voteMessage": "%1$s 发起了服务器实体清理投票!如果同意清理但是未收到表单,请输入命令 /voteclean 投票。拒绝清理请忽略此信息。"
|
||||||
})";
|
})";
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "Features/Cleaner.h"
|
||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
|
|
||||||
ll::Logger logger("Cleaner");
|
ll::Logger logger("Cleaner");
|
||||||
@@ -10,6 +11,8 @@ Plugin::Plugin(ll::plugin::NativePlugin& self) : mSelf(self) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Plugin::enable() {
|
bool Plugin::enable() {
|
||||||
|
Cleaner::ListenEvents();
|
||||||
|
RegisterCommands();
|
||||||
Cleaner::loadCleaner();
|
Cleaner::loadCleaner();
|
||||||
logger.info("Cleaner Loaded!");
|
logger.info("Cleaner Loaded!");
|
||||||
logger.info("Author: GroupMountain");
|
logger.info("Author: GroupMountain");
|
||||||
|
|||||||
+19
-15
@@ -1,3 +1,4 @@
|
|||||||
|
#include "Features/Cleaner.h"
|
||||||
#include "Global.h"
|
#include "Global.h"
|
||||||
|
|
||||||
struct CleanerParam {
|
struct CleanerParam {
|
||||||
@@ -70,21 +71,24 @@ void RegCleanerCommand() {
|
|||||||
}>();
|
}>();
|
||||||
};
|
};
|
||||||
|
|
||||||
void RegisterCommands() {
|
void RegVoteCommand() {
|
||||||
RegCleanerCommand();
|
auto& cmd = ll::command::CommandRegistrar::getInstance().getOrCreateCommand(
|
||||||
// RegVoteCommand();
|
Config->getValue<std::string>({"VoteClean", "VoteCleanCommand"}, "voteclean"),
|
||||||
|
tr("cleaner.command.voteclean"),
|
||||||
|
CommandPermissionLevel::Any
|
||||||
|
);
|
||||||
|
cmd.overload().execute<[&](CommandOrigin const& origin, CommandOutput& output) {
|
||||||
|
if (origin.getOriginType() == CommandOriginType::Player) {
|
||||||
|
auto pl = (Player*)origin.getEntity();
|
||||||
|
return VoteClean::voteCommandExecute(pl);
|
||||||
|
}
|
||||||
|
return output.error(tr("cleaner.command.error.playerOnly"));
|
||||||
|
}>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void RegisterCommands() {
|
||||||
void RegVoteCommand() {
|
RegCleanerCommand();
|
||||||
auto command = DynamicCommand::createCommand(registry, "voteclean", "Clean entities", CommandPermissionLevel::Any);
|
if (Config->getValue<bool>({"VoteClean", "Enabled"}, false)) {
|
||||||
command->addOverload();
|
RegVoteCommand();
|
||||||
command->setCallback([](DynamicCommand const& cmd,
|
}
|
||||||
CommandOrigin const& origin,
|
|
||||||
CommandOutput& output,
|
|
||||||
std::unordered_map<std::string, DynamicCommand::Result>& result) {
|
|
||||||
// vote clean command
|
|
||||||
});
|
|
||||||
DynamicCommand::setup(registry, std::move(command));
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
Reference in New Issue
Block a user