#include "Config.h" #include "Global.h" #include #include #include #include GMLIB::Files::JsonConfig* Config = nullptr; nlohmann::json Language; using namespace ll::schedule; using namespace ll::chrono_literals; int item_despawn_time = 3000; // ServerTimeAsyncScheduler scheduler; bool auto_clean_triggerred = false; namespace Cleaner { bool isMatch(std::string& A, std::string& B) { // 如果B是正则表达式 if (B.find_first_of(".*+?()[]{}|^$") != std::string::npos) { try { std::regex regex(B); return std::regex_match(A, regex); } catch (...) { return false; } } return (A == B); } bool shouldIgnore(GMLIB_Actor* ac) { if (ac->isMob() || ac->isItemActor()) { if (ac->isTame() || ac->isTrusting() || ac->getNameTag() != "") { return true; } auto nbt = ac->getNbt(); if (nbt->getByte("ShowBottom") == 1) { // End Crystal Used Only, if has this tag 1b, it is modified by cleaner. return true; } } return false; } bool ShouldClean(Actor* actor) { // Players auto en = (GMLIB_Actor*)actor; if (en->isPlayer() || shouldIgnore(en)) { return false; } auto type = en->getTypeName(); // Items if (en->isItemActor()) { if (Config->getValue({"CleanItem", "Enabled"}, false)) { auto itac = (ItemActor*)en; if (itac->age() <= Config->getValue({"CleanItem", "ExistTicks"}, 0)) { return false; } auto itemType = itac->item().getTypeName(); auto whitelist = Config->getValue>({"CleanItem", "Whitelist"}, {}); for (auto& key : whitelist) { if (isMatch(itemType, key)) { return false; } } return true; } return false; } // Mobs else if (en->isMob()) { if (Config->getValue({"CleanMobs", "Enabled"}, false)) { auto blacklist = Config->getValue>({"CleanMobs", "Blacklist"}, {}); for (auto& key : blacklist) { if (isMatch(type, key)) { return true; } } auto whitelist = Config->getValue>({"CleanMobs", "Whitelist"}, {}); for (auto& key : whitelist) { if (isMatch(type, key)) { return false; } } if (Config->getValue({"CleanMobs", "CleanMonstors"}, false) && en->hasCategory(ActorCategory::Monster)) { return true; } if (Config->getValue({"CleanMobs", "CleanPeacefulMobs"}, false)) { return true; } } return false; } // Others else { if (Config->getValue({"CleanInanimate", "Enabled"}, false)) { auto blacklist = Config->getValue>({"CleanInanimate", "Blacklist"}, {}); for (auto& key : blacklist) { if (isMatch(type, key)) { return true; } } } return false; } } int ExecuteClean() { int clean_count = 0; auto all_entities = GMLIB_Level::getLevel()->getAllEntities(); for (auto entity : all_entities) { if (ShouldClean(entity)) { entity->despawn(); clean_count++; } } return clean_count; } int CountEntities() { int clean_count = 0; auto all_entities = GMLIB_Level::getLevel()->getAllEntities(); for (auto entity : all_entities) { if (ShouldClean(entity)) { clean_count++; } } return clean_count; } void CleanTask(int time, int announce_time) { auto time_1 = std::chrono::seconds::duration(time); auto time_2 = std::chrono::seconds::duration(time - announce_time); logger.info(tr("cleaner.output.count1", {S(time_1.count())})); // scheduler.add(time_2, [announce_time] { logger.info(tr("cleaner.output.count2", {S(announce_time)})); //}); // scheduler.add(time_1, [] { auto count = ExecuteClean(); logger.info(tr("cleaner.output.finish", {S(count)})); auto_clean_triggerred = false; //}); } void AutoCleanTask(int seconds) { auto time = std::chrono::seconds::duration(seconds); // mAutoCleanTask = scheduler.add(time, [] { CleanTask(Config->getValue({"Basic", "Notice1"}, 20), Config->getValue({"Basic", "Notice2"}, 15)); //}); } void CheckCleanTask(int max_entities, float min_tps) { // mCheckCleanTask = scheduler.add(10s, [max_entities, min_tps] { auto count = CountEntities(); if (auto_clean_triggerred == false) { if (count >= max_entities) { auto_clean_triggerred = true; logger.warn(tr("cleaner.output.triggerAutoCleanCount", {S(count)})); CleanTask(Config->getValue({"Basic", "Notice1"}, 20), Config->getValue({"Basic", "Notice2"}, 15)); } else if (GMLIB_Level::getLevel()->getServerAverageTps() <= min_tps) { auto_clean_triggerred = true; logger.warn(tr("cleaner.output.triggerAutoCleanCount", {S(GMLIB_Level::getLevel()->getServerAverageTps())}) ); CleanTask(Config->getValue({"Basic", "Notice1"}, 20), Config->getValue({"Basic", "Notice2"}, 15)); } } //}); } void setShouldIgnore(GMLIB_Actor* ac) { auto nbt = ac->getNbt(); nbt->put("ShowBottom", ByteTag(1)); ac->setNbt(*nbt); } void ListenEvents() { auto eventBus = &ll::event::EventBus::getInstance(); // ItemSpawnEvent eventBus->emplaceListener( [](GMLIB::Event::EntityEvent::ItemActorSpawnAfterEvent& event) { auto& item = event.getItemActor(); auto pl = (GMLIB_Player*)event.getSpawner(); if (pl) { if (pl->isPlayer() && !pl->isAlive()) { // Death Drop auto ac = (GMLIB_Actor*)&item; setShouldIgnore(ac); return; } } item.lifeTime() = item_despawn_time; } ); // MobTakeItemEvent eventBus->emplaceListener( [](GMLIB::Event::EntityEvent::MobPickupItemAfterEvent& event) { // auto item = event.getItemActor().item().getTypeName(); auto mob = (GMLIB_Actor*)&event.self(); setShouldIgnore(mob); } ); } void reloadCleaner() { unloadCleaner(); loadCleaner(); } void loadConfig() { Config = new GMLIB::Files::JsonConfig("./plugins/Cleaner/config/config.json", defaultConfig); Config->initConfig(); Language = GMLIB::Files::JsonLanguage::initLanguage("./plugins/Cleaner/config/language.json", defaultLanguage); } void loadCleaner() { ListenEvents(); RegisterCommands(); if (Config->getValue({"ScheduleClean", "Enabled"}, false)) { Cleaner::AutoCleanTask(Config->getValue({"ScheduleClean", "CleanInterval"}, 3000)); } if (Config->getValue({"AutoCleanCount", "Enabled"}, false) || Config->getValue({"AutoCleanTPS", "Enabled"}, false)) { Cleaner::CheckCleanTask( Config->getValue({"AutoCleanCount", "TriggerCount"}, 900), Config->getValue({"AutoCleanTPS", "TriggerTPS"}, 15) ); } } void unloadCleaner() { mAutoCleanTask->cancel(); mCheckCleanTask->cancel(); // UnregisterCommands(); delete Config; } } // namespace Cleaner std::string tr(std::string key, std::vector data) { return GMLIB::Files::JsonLanguage::translate(Language, key, data); }