diff --git a/.clangd b/.clangd index 40ad7a5..4785d56 100644 --- a/.clangd +++ b/.clangd @@ -1,5 +1,23 @@ Diagnostics: - Suppress: ["-Wmicrosoft-enum-forward-reference", "-Wc++11-narrowing", "-Wc++2b-extensions", "-Wmicrosoft-cast"] + Suppress: + - "-Wmicrosoft-enum-forward-reference" + - "-Wc++11-narrowing" + - "-Wc++2b-extensions" + - "-Wmicrosoft-cast" + - "-Wcxx20_deducing_this" + - "-Wundefined_internal_type" + - "-Wincomplete_member_access" + - "-Wsizeof_alignof_incomplete_or_sizeless_type" + - "-Wexplicit_spec_non_template" + - "-Wovl_no_viable_function_in_init" CompileFlags: - Add: ["-ferror-limit=0", "-D__FUNCTION__=\"dummy\"", "-D_CRT_USE_BUILTIN_OFFSETOF", "-std=c++23"] - Remove: ["/Yu_HeaderOutputPredefine.h", "/FI_HeaderOutputPredefine.h"] + Add: + - "-Xclang" + - "-triple=x86_64-windows-msvc" + - "-ferror-limit=0" + - '-D__FUNCTION__="dummy"' + - "-Dnsel_CONFIG_SELECT_EXPECTED=nsel_EXPECTED_NONSTD" + - "-Xclang" + - "-std=c++23" + Remove: + - "-std" \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index af8e62f..f9e905a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,8 @@ jobs: - uses: xmake-io/github-action-setup-xmake@v1 with: - xmake-version: latest + xmake-version: 3.0.0 + - run: | xmake repo -u diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7647da6..77174c9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,8 @@ jobs: - uses: xmake-io/github-action-setup-xmake@v1 with: - xmake-version: latest + xmake-version: 3.0.0 + - run: | xmake repo -u diff --git a/README.md b/README.md index 5866098..f04148c 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,13 @@ "Cooldown": 120, // 投票冷却时间 单位:秒 "CheckDelay": 30, // 投票时长 单位:秒 "Percentage": 50 // 投票百分比(大于此值则清理) + }, + "UnloadActorClean": { // 离线实体清理 + "Enabled": false, // 是否启用 + "CleanList": [ // 清理实体列表 + "minecraft:iron_golem", // 铁傀儡 + "minecraft:zombie_pigman" // 僵尸猪灵 + ] } } ``` diff --git a/manifest.json b/manifest.json index ab0097b..d5f3f73 100644 --- a/manifest.json +++ b/manifest.json @@ -2,12 +2,20 @@ "name": "${modName}", "entry": "${modFile}", "type": "native", - "version": "0.13.3", + "version": "0.16.1", "author": "GroupMountain", "description": "Clean Entities", "dependencies": [ { "name": "GMLIB" + }, + { + "name": "iListenAttentively" + } + ], + "optionalDependencies": [ + { + "name": "ModAPI" } ] -} +} \ No newline at end of file diff --git a/src/Config.h b/src/Config.h index 5507bd8..a7abf3d 100644 --- a/src/Config.h +++ b/src/Config.h @@ -91,5 +91,10 @@ struct Config { int CheckDelay = 30; int Percentage = 50; } VoteClean; + + struct Unload_Actor_Clean { + bool Enabled = false; + std::vector CleanList = {"minecraft:iron_golem", "minecraft:zombie_pigman"}; + } UnloadActorClean; }; } // namespace Cleaner \ No newline at end of file diff --git a/src/Features/Clean.cpp b/src/Features/Clean.cpp index 43485fb..f90f014 100644 --- a/src/Features/Clean.cpp +++ b/src/Features/Clean.cpp @@ -1,5 +1,6 @@ #include "Cleaner.h" - +#include "mc/world/actor/provider/SynchedActorDataAccess.h" +#include "gmlib/mc/world/actor/Actor.h" namespace Cleaner { bool isMatch(std::string& A, std::string& B) { @@ -15,9 +16,11 @@ bool isMatch(std::string& A, std::string& B) { return (A == B); } -bool shouldIgnore(GMLIB_Actor* ac) { - if (ac->isMob() || ac->isItemActor()) { - if (ac->isTame() || ac->isTrusting() || ac->getNameTag() != "" || ac->hasTag("cleaner:ignore")) { +bool isTrust(Actor* ac) { return SynchedActorDataAccess::getActorFlag(ac->getEntityContext(), ::ActorFlags::Trusting); } + +bool shouldIgnore(gmlib::GMActor* ac) { + if (ac->hasCategory(::ActorCategory::Mob) || ac->hasCategory(::ActorCategory::Item)) { + if (ac->isTame() || isTrust(ac) || ac->getNameTag() != "" || ac->hasTag("cleaner:ignore")) { return true; } } @@ -27,7 +30,7 @@ bool shouldIgnore(GMLIB_Actor* ac) { bool ShouldClean(Actor* actor) { // Players auto& config = Cleaner::Entry::getInstance().getConfig(); - auto en = (GMLIB_Actor*)actor; + auto en = (gmlib::GMActor*)actor; if (en->isPlayer() || shouldIgnore(en)) { return false; } @@ -38,7 +41,7 @@ bool ShouldClean(Actor* actor) { } } // Items - if (en->isItemActor()) { + if (en->hasCategory(::ActorCategory::Item)) { if (config.CleanItem.Enabled) { auto itac = (ItemActor*)en; if (itac->age() <= config.CleanItem.ExistTicks) { @@ -56,7 +59,7 @@ bool ShouldClean(Actor* actor) { return false; } // Mobs - else if (en->isMob()) { + else if (en->hasCategory(::ActorCategory::Mob)) { if (config.CleanMobs.Enabled) { auto blacklist = config.CleanMobs.BlackList; for (auto& key : blacklist) { @@ -94,8 +97,9 @@ bool ShouldClean(Actor* actor) { } int ExecuteClean() { + auto level = ll::service::getLevel(); int clean_count = 0; - auto all_entities = GMLIB_Level::getLevel()->getRuntimeActorList(); + auto all_entities = level->getRuntimeActorList(); for (auto entity : all_entities) { if (ShouldClean(entity)) { entity->despawn(); @@ -106,8 +110,9 @@ int ExecuteClean() { } int CountEntities() { + auto level = ll::service::getLevel(); int clean_count = 0; - auto all_entities = GMLIB_Level::getLevel()->getRuntimeActorList(); + auto all_entities = level->getRuntimeActorList(); for (auto* entity : all_entities) { if (ShouldClean(entity)) { clean_count++; diff --git a/src/Features/CleanTask.cpp b/src/Features/CleanTask.cpp index 9972055..bf7a2ee 100644 --- a/src/Features/CleanTask.cpp +++ b/src/Features/CleanTask.cpp @@ -1,6 +1,7 @@ #include "Cleaner.h" #include - +#include "gmlib/mc/world/Level.h" +#include "gmlib/gm/data/TpsStatus.h" namespace Cleaner { static std::shared_ptr mAutoCleanTask = std::make_shared(false); @@ -10,11 +11,11 @@ static std::shared_ptr mCleanTaskTPS = std::make_shared(false); bool auto_clean_triggerred = false; void CleanTask() { - auto& config = Cleaner::Entry::getInstance().getConfig(); - auto time = config.Basic.Notice1; - auto announce_time = config.Basic.Notice2; - auto time_1 = std::chrono::seconds::duration(time); - auto time_2 = std::chrono::seconds::duration(time - announce_time); + auto& config = Cleaner::Entry::getInstance().getConfig(); + auto time = config.Basic.Notice1; + auto announce_time = config.Basic.Notice2; + std::chrono::seconds time_1(time); + std::chrono::seconds time_2(time - announce_time); if (config.Basic.ConsoleLog) { ll::io::LoggerRegistry::getInstance().getOrCreate("Cleaner")->info( tr("cleaner.output.count1", {S(time_1.count())}) @@ -59,7 +60,7 @@ void CleanTask() { } void AutoCleanTask(int seconds) { - auto time = std::chrono::seconds::duration(seconds); + std::chrono::seconds time(seconds); *mAutoCleanTask = true; ll::coro::keepThis([time]() -> ll::coro::CoroTask<> { while (true) { @@ -72,7 +73,7 @@ void AutoCleanTask(int seconds) { } void CleanTaskCount(int max_entities) { - auto& config = Cleaner::Entry::getInstance().getConfig(); + auto& config = Cleaner::Entry::getInstance().getConfig(); *mCleanTaskCount = true; ll::coro::keepThis([max_entities, &config]() -> ll::coro::CoroTask<> { while (true) { @@ -83,7 +84,9 @@ void CleanTaskCount(int max_entities) { if (count >= max_entities) { auto_clean_triggerred = true; if (config.Basic.ConsoleLog) { - ll::io::LoggerRegistry::getInstance().getOrCreate("Cleaner")->warn(tr("cleaner.output.triggerAutoCleanCount", {S(count)})); + ll::io::LoggerRegistry::getInstance().getOrCreate("Cleaner")->warn( + tr("cleaner.output.triggerAutoCleanCount", {S(count)}) + ); } if (config.Basic.SendBroadcast) { Helper::broadcastMessage(tr("cleaner.output.triggerAutoCleanCount", {S(count)})); @@ -100,16 +103,16 @@ void CleanTaskCount(int max_entities) { } void CleanTaskTPS(float min_tps) { - auto& config = Cleaner::Entry::getInstance().getConfig(); + auto& config = Cleaner::Entry::getInstance().getConfig(); *mCleanTaskTPS = true; ll::coro::keepThis([min_tps, &config]() -> ll::coro::CoroTask<> { while (true) { co_await 10s; if (*mCleanTaskTPS == false) co_return; if (auto_clean_triggerred == false) { - if (GMLIB_Level::getLevel()->getServerAverageTps() <= min_tps) { + if (gmlib::TpsStatus::getInstance().getLevelAverageTps() <= min_tps) { auto_clean_triggerred = true; - auto mspt = S(GMLIB_Level::getLevel()->getServerAverageTps()); + auto mspt = S(gmlib::TpsStatus::getInstance().getLevelAverageTps()); if (config.Basic.ConsoleLog) { ll::io::LoggerRegistry::getInstance().getOrCreate("Cleaner")->warn( tr("cleaner.output.triggerAutoCleanTps", {mspt}) diff --git a/src/Features/Cleaner.cpp b/src/Features/Cleaner.cpp index 2b4782d..e23caf6 100644 --- a/src/Features/Cleaner.cpp +++ b/src/Features/Cleaner.cpp @@ -4,6 +4,9 @@ namespace Cleaner { void loadCleaner() { auto& config = Cleaner::Entry::getInstance().getConfig(); + if(config.UnloadActorClean.Enabled){ + UnloadActorClean::cleanUnloadActor(); + } if (config.ScheduleClean.Enabled) { Cleaner::AutoCleanTask(config.ScheduleClean.CleanInterval); } diff --git a/src/Features/Cleaner.h b/src/Features/Cleaner.h index ea13f4d..a8f52ee 100644 --- a/src/Features/Cleaner.h +++ b/src/Features/Cleaner.h @@ -26,4 +26,10 @@ namespace VoteClean { extern void voteCommandExecute(Player* pl); +} + +namespace UnloadActorClean { + +extern void cleanUnloadActor(); + } \ No newline at end of file diff --git a/src/Features/Events.cpp b/src/Features/Events.cpp index 74db49f..2849b92 100644 --- a/src/Features/Events.cpp +++ b/src/Features/Events.cpp @@ -1,44 +1,40 @@ #include "Cleaner.h" - +#include "gmlib/mc/world/Level.h" +#include "gmlib/mc/world/actor/Player.h" namespace Cleaner { - -void setShouldIgnore(GMLIB_Actor* ac) { ac->addTag("cleaner:ignore"); } +void setShouldIgnore(gmlib::GMActor* ac) { ac->addTag("cleaner:ignore"); } void ListenEvents() { auto& eventBus = ll::event::EventBus::getInstance(); auto& config = Cleaner::Entry::getInstance().getConfig(); // ItemSpawnEvent - eventBus.emplaceListener( - [&config](GMLIB::Event::EntityEvent::ItemActorSpawnAfterEvent& event) { - auto& item = event.getItemActor(); - if (event.getSpawner().has_value()) { - auto pl = (GMLIB_Player*)event.getSpawner().as_ptr(); - if (pl->isPlayer() && !pl->isAlive()) { // Death Drop - auto ac = (GMLIB_Actor*)&item; - setShouldIgnore(ac); + eventBus.emplaceListener([&config](ila::mc::SpawnItemActorAfterEvent& event) { + auto& item = event.itemActor(); + if (event.spawner()) { + auto pl = (gmlib::GMPlayer*)event.spawner(); + if (pl->isPlayer() && !pl->isAlive()) { // Death Drop + auto ac = (gmlib::GMActor*)&item; + setShouldIgnore(ac); + return; + } + } + if (config.ItemDespawn.Enabled) { + // item.lifeTime() = config.ItemDespawn.DespawnTime; + auto list = config.ItemDespawn.WhiteList; + auto type = item.item().getTypeName(); + for (auto& key : list) { + if (isMatch(type, key)) { return; } } - if (config.ItemDespawn.Enabled) { - item.lifeTime() = config.ItemDespawn.DespawnTime; - auto list = config.ItemDespawn.WhiteList; - auto type = item.item().getTypeName(); - for (auto& key : list) { - if (isMatch(type, key)) { - return; - } - } - item.lifeTime() = config.ItemDespawn.DespawnTime; - } + item.lifeTime() = config.ItemDespawn.DespawnTime; } - ); + }); // MobTakeItemEvent - eventBus.emplaceListener( - [](GMLIB::Event::EntityEvent::MobPickupItemAfterEvent& event) { - auto mob = (GMLIB_Actor*)&event.self(); - setShouldIgnore(mob); - } - ); + eventBus.emplaceListener([](ila::mc::ActorPickupItemAfterEvent& event) { + auto mob = (gmlib::GMActor*)&event.self(); + setShouldIgnore(mob); + }); } } // namespace Cleaner \ No newline at end of file diff --git a/src/Features/Helper.cpp b/src/Features/Helper.cpp index 8805e3a..5703ea8 100644 --- a/src/Features/Helper.cpp +++ b/src/Features/Helper.cpp @@ -1,13 +1,13 @@ #include "Global.h" - +#include "gmlib/mc/world/Level.h" namespace Helper { void broadcastMessage(std::string_view msg) { - GMLIB_Level::getInstance()->broadcast(tr("cleaner.info.prefix") + std::string(msg)); + gmlib::GMLevel::getInstance()->broadcast(tr("cleaner.info.prefix") + std::string(msg)); } void broadcastToast(std::string_view msg) { - GMLIB_Level::getInstance()->broadcastToast(tr("cleaner.info.prefix"), msg); + gmlib::GMLevel::getInstance()->broadcastToast(tr("cleaner.info.prefix"), msg); } } // namespace Helper \ No newline at end of file diff --git a/src/Features/UnloadActorClean.cpp b/src/Features/UnloadActorClean.cpp new file mode 100644 index 0000000..895a486 --- /dev/null +++ b/src/Features/UnloadActorClean.cpp @@ -0,0 +1,19 @@ +#include "Cleaner.h" +#include "Global.h" +#include "gmlib/mc/world/actor/UnloadedActor.h" + +namespace UnloadActorClean { +void cleanUnloadActor() { + auto& config = Cleaner::Entry::getInstance().getConfig(); + gmlib::UnloadedActor::foreachUnloadedActor( + [config](gmlib::UnloadedActor& actor) -> bool { + for (auto& actorname : config.UnloadActorClean.CleanList) { + if (actor.getTypeName() == actorname) { + actor.remove(); + } + } + return true; + } + ); +} +} // namespace UnloadActorClean \ No newline at end of file diff --git a/src/Features/VoteClean.cpp b/src/Features/VoteClean.cpp index 3447a16..4117ed8 100644 --- a/src/Features/VoteClean.cpp +++ b/src/Features/VoteClean.cpp @@ -94,12 +94,12 @@ void voteClean(Player* pl) { } sendVoteForm(pl); ll::coro::keepThis([&config]() -> ll::coro::CoroTask<> { - co_await std::chrono::seconds::duration(config.VoteClean.Cooldown); + co_await std::chrono::seconds(config.VoteClean.Cooldown); canVote = true; co_return; }).launch(ll::thread::ServerThreadExecutor::getDefault()); ll::coro::keepThis([&config]() -> ll::coro::CoroTask<> { - co_await std::chrono::seconds::duration(config.VoteClean.CheckDelay); + co_await std::chrono::seconds(config.VoteClean.CheckDelay); checkVote(); co_return; }).launch(ll::thread::ServerThreadExecutor::getDefault()); diff --git a/src/Global.h b/src/Global.h index 6a89157..0f330f0 100644 --- a/src/Global.h +++ b/src/Global.h @@ -1,7 +1,11 @@ #pragma once +// IWYU pragma: begin_exports #include "Mod.h" -#include + +#include "gmlib/include_ll.h" +#include "ila/include_all.h" #include +// IWYU pragma: end_exports #define S(x) std::to_string(x) diff --git a/src/Language.h b/src/Language.h index d419f27..0dbd265 100644 --- a/src/Language.h +++ b/src/Language.h @@ -44,7 +44,7 @@ std::string zh_CN = R"( cleaner.command.error.noTarget=没有与选择器匹配的目标 cleaner.command.error.playerOnly=该命令只能由玩家执行! cleaner.command.tps.output=当前服务器实时TPS %1$s §r,平均TPS %2$s - cleaner.command.mspt.output=当前服务器实MSPT %1$s + cleaner.command.mspt.output=当前服务器实时MSPT %1$s cleaner.command.clean.output=已成功启动清理任务! cleaner.command.voteclean=发起实体清理投票。 cleaner.command.despawntime=已成功将物品消失时间设置为 %1$s 游戏刻 diff --git a/src/Mod.cpp b/src/Mod.cpp index f6e0e15..17f2d72 100644 --- a/src/Mod.cpp +++ b/src/Mod.cpp @@ -2,6 +2,9 @@ #include "Features/Cleaner.h" #include "Global.h" #include "Language.h" +#include "ll/api/utils/ErrorUtils.h" +#include "gmlib/mc/locale/I18nAPI.h" +#include "gmlib/gm/data/TpsStatus.h" namespace Cleaner { @@ -13,12 +16,17 @@ Entry& Entry::getInstance() { bool Entry::load() { return true; } bool Entry::enable() { + (void)gmlib::TpsStatus::getInstance(); mConfig.emplace(); - ll::config::loadConfig(*mConfig, getSelf().getConfigDir() / "config.json"); + try { + ll::config::loadConfig(*mConfig, getSelf().getConfigDir() / "config.json"); + } catch (...) { + ll::error_utils::printCurrentException(getSelf().getLogger()); + } saveConfig(); - I18nAPI::updateOrCreateLanguageFile(getSelf().getLangDir(), "en_US", en_US); - I18nAPI::updateOrCreateLanguageFile(getSelf().getLangDir(), "zh_CN", zh_CN); - I18nAPI::loadLanguagesFromDirectory(getSelf().getLangDir()); + gmlib::I18nAPI::updateOrCreateLanguageFile(getSelf().getLangDir(), "en_US", en_US); + gmlib::I18nAPI::updateOrCreateLanguageFile(getSelf().getLangDir(), "zh_CN", zh_CN); + gmlib::I18nAPI::loadLanguagesFromDirectory(getSelf().getLangDir()); Cleaner::ListenEvents(); RegisterCommands(); Cleaner::loadCleaner(); @@ -43,5 +51,5 @@ void Entry::saveConfig() { ll::config::saveConfig(*mConfig, getSelf().getConfigD LL_REGISTER_MOD(Cleaner::Entry, Cleaner::Entry::getInstance()); std::string tr(std::string const& key, std::vector const& params) { - return I18nAPI::get(key, params, Cleaner::Entry::getInstance().getConfig().language); + return gmlib::I18nAPI::get(key, params); } diff --git a/src/RegisterCommand.cpp b/src/RegisterCommand.cpp index ebd7eb1..a69f4f3 100644 --- a/src/RegisterCommand.cpp +++ b/src/RegisterCommand.cpp @@ -1,5 +1,7 @@ #include "Features/Cleaner.h" - +#include "gmlib/mc/world/Level.h" +#include "gmlib/gm/data/TpsStatus.h" +#include "mc/server/commands/CommandOutput.h" struct CleanerParam { enum class Despawn { despawn } despawn; enum class Action { tps, clean, reload, mspt } action; @@ -10,15 +12,13 @@ struct CleanerParam { void RegCleanerCommand() { auto& config = Cleaner::Entry::getInstance().getConfig(); - auto& cmd = ll::command::CommandRegistrar::getInstance().getOrCreateCommand( + auto& cmd = ll::command::CommandRegistrar::getInstance(false).getOrCreateCommand( config.Basic.Command, tr("cleaner.command.cleaner"), CommandPermissionLevel::GameDirectors ); - cmd.overload() - .required("despawn") - .required("entity") - .execute([&](CommandOrigin const& origin, CommandOutput& output, CleanerParam const& param) { + cmd.overload().required("despawn").required("entity").execute( + [&](CommandOrigin const& origin, CommandOutput& output, CleanerParam const& param) { auto ens = param.entity.results(origin); if (ens.empty()) { return output.error(tr("cleaner.command.error.noTarget")); @@ -27,10 +27,10 @@ void RegCleanerCommand() { en->despawn(); } return output.success(tr("cleaner.command.despawnSuccess", {S(ens.size())})); - }); - cmd.overload() - .required("action") - .execute([&](CommandOrigin const& origin, CommandOutput& output, CleanerParam const& param) { + } + ); + cmd.overload().required("action").execute( + [&](CommandOrigin const& origin, CommandOutput& output, CleanerParam const& param) { switch (param.action) { case CleanerParam::Action::clean: { Cleaner::CleanTask(); @@ -46,15 +46,15 @@ void RegCleanerCommand() { return output.success(tr("cleaner.command.clean.output")); } case CleanerParam::Action::tps: { - return output.success(tr( - "cleaner.command.tps.output", - {S(GMLIB_Level::getLevel()->getServerCurrentTps()), - S(GMLIB_Level::getLevel()->getServerAverageTps())} - )); + return output.success( + tr("cleaner.command.tps.output", + {S(gmlib::GMLevel::getInstance()->getServerCurrentTps()), + S(gmlib::TpsStatus::getInstance().getLevelAverageTps())}) + ); } case CleanerParam::Action::mspt: { return output.success( - tr("cleaner.command.mspt.output", {S(GMLIB_Level::getLevel()->getServerMspt())}) + tr("cleaner.command.mspt.output", {S(gmlib::GMLevel::getInstance()->getServerMspt())}) ); } case CleanerParam::Action::reload: { @@ -62,7 +62,8 @@ void RegCleanerCommand() { return output.success(tr("cleaner.output.reload")); } } - }); + } + ); cmd.overload() .required("despawntime") .required("ticks") @@ -74,7 +75,7 @@ void RegCleanerCommand() { }; void RegVoteCommand() { - auto& cmd = ll::command::CommandRegistrar::getInstance().getOrCreateCommand( + auto& cmd = ll::command::CommandRegistrar::getInstance(false).getOrCreateCommand( Cleaner::Entry::getInstance().getConfig().VoteClean.VoteCleanCommand, tr("cleaner.command.voteclean"), CommandPermissionLevel::Any diff --git a/tooth.json b/tooth.json index cd0e3cb..165a0d4 100644 --- a/tooth.json +++ b/tooth.json @@ -1,28 +1,54 @@ { - "format_version": 2, - "tooth": "github.com/GroupMountain/Cleaner", - "version": "0.13.3", - "info": { - "name": "Cleaner", - "description": "A Powerful Entities Cleaning up Mod for BDS", - "author": "GroupMountain", - "source": "github.com/GroupMountain/Cleaner", - "tags": [ - "levilamina", - "cleaner", - "gmlib" - ] - }, - "asset_url": "https://github.com/GroupMountain/Cleaner/releases/download/v0.13.3/Cleaner-windows-x64.zip", - "dependencies": { - "github.com/GroupMountain/GMLIB": ">=0.13.10" - }, - "files": { - "place": [ + "format_version": 3, + "format_uuid": "289f771f-2c9a-4d73-9f3f-8492495a924d", + "tooth": "github.com/GroupMountain/Cleaner", + "version": "0.16.1", + "info": { + "name": "Cleaner", + "description": "A Powerful Entities Cleaning up Mod for BDS", + "tags": [ + "levilamina", + "cleaner", + "gmlib" + ], + "avatar_url": "" + }, + "variants": [ + { + "label": "", + "platform": "win-x64", + "dependencies": { + "github.com/GroupMountain/GMLIB-Release": ">=1.9.0", + "github.com/GroupMountain/ModAPI-Release": ">=0.4.0", + "github.com/MiracleForest/iListenAttentively-Release": ">=0.11.0" + }, + "assets": [ + { + "type": "zip", + "urls": [ + "https://github.com/GroupMountain/Cleaner/releases/download/v{{version}}/Cleaner-windows-x64.zip" + ], + "placements": [ { - "src": "Cleaner/*", - "dest": "mods/Cleaner" + "type": "dir", + "src": "Cleaner/", + "dest": "plugins/Cleaner" } - ] + ] + } + ], + "preserve_files": [], + "remove_files": [], + "scripts": { + "pre_install": [], + "install": [], + "post_install": [], + "pre_pack": [], + "post_pack": [], + "pre_uninstall": [], + "uninstall": [], + "post_uninstall": [] + } } -} + ] +} \ No newline at end of file diff --git a/xmake.lua b/xmake.lua index 3c28635..ff6483c 100644 --- a/xmake.lua +++ b/xmake.lua @@ -2,15 +2,17 @@ add_rules("mode.debug", "mode.release", "mode.releasedbg") add_repositories("liteldev-repo https://github.com/LiteLDev/xmake-repo.git") add_repositories("groupmountain-repo https://github.com/GroupMountain/xmake-repo.git") +add_repositories("miracleforest https://github.com/MiracleForest/xmake-repo") if not has_config("vs_runtime") then set_runtimes("MD") end -- Option 1: Use the latest version of LeviLamina released on GitHub. -add_requires("levilamina") -add_requires("levibuildscript") -add_requires("gmlib") +add_requires("levilamina 1.9.5", {configs = {target_type = "server"}}) +add_requires("levibuildscript 0.6.0") +add_requires("gmlib 1.9.1") +add_requires("ilistenattentively 0.11.0") target("Cleaner") -- Change this to your mod name. add_cxflags( @@ -25,19 +27,20 @@ target("Cleaner") -- Change this to your mod name. ) add_packages( "levilamina", - "gmlib" + "gmlib", + "ilistenattentively" ) add_defines( "NOMINMAX", - "UNICODE", - "_HAS_CXX17", - "_HAS_CXX20", - "_HAS_CXX23" + "UNICODE", + "_HAS_CXX23=1" ) + add_defines("LL_PLAT_S") --TODO: check client compatibility add_rules("@levibuildscript/linkrule") set_exceptions("none") set_kind("shared") - set_languages("cxx23") + set_languages("cxx20") + set_symbols("debug") after_build(function (target) local mod_packer = import("scripts.after_build")