diff --git a/CHANGELOG.md b/CHANGELOG.md index 58ad2d9..da5944b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.4.0] - 2026-2.9 + +### Added + ++ Adapt to 1.21.132 + +### Fixed + ++ Fixed more compatibility issues with the SAPI + ## [3.3.1] - 2025-12.25 ### Fixed diff --git a/CHANGELOG_ZH.md b/CHANGELOG_ZH.md index 10b89e3..450373a 100644 --- a/CHANGELOG_ZH.md +++ b/CHANGELOG_ZH.md @@ -5,11 +5,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [3.4.0] - 2026-2.9 + +### Added + ++ 适配1.21.132 + +### Fixed + ++ 解决了更多的与sapi之间的兼容性问题 + ## [3.3.1] - 2025-12.25 ### Fixed -+ Resolved known compatibility issues with the SAPI. ++ 解决了已知的与sapi之间的兼容性问题 ## [3.3.0] - 2025-11.14 diff --git a/src/cfsp/core/fix/CFSPFixManager.h b/src/cfsp/core/fix/CFSPFixManager.h index 178768d..55aebea 100644 --- a/src/cfsp/core/fix/CFSPFixManager.h +++ b/src/cfsp/core/fix/CFSPFixManager.h @@ -1,7 +1,17 @@ #pragma once +#include "mc/world/level/Tick.h" +#include +#include + namespace coral_fans::cfsp::fix { +class CFSPRemovingListRecorder { +public: + std::unordered_set mRemovingSpList; + Tick mLastTick; +}; + class CFSPFixManager { public: bool createSpMutex = false; @@ -17,6 +27,9 @@ class CFSPFixManager { void handItemFix(); void sapiFix(); +public: + CFSPRemovingListRecorder mRemovingRecord; + public: void cfspBugFixHook(); }; diff --git a/src/cfsp/core/fix/SapiFix.cpp b/src/cfsp/core/fix/SapiFix.cpp index 551b5b4..c5587b6 100644 --- a/src/cfsp/core/fix/SapiFix.cpp +++ b/src/cfsp/core/fix/SapiFix.cpp @@ -4,8 +4,11 @@ #include "mc/deps/ecs./WeakEntityRef.h" #include "mc/scripting/modules/minecraft/actor/ScriptActor.h" #include "mc/scripting/modules/minecraft/events/ScriptActorEventListener.h" -#include "mc/scripting/modules/minecraft/events/ScriptLevelEventListener.h" +#include "mc/scripting/modules/minecraft/events/ScriptActorGlobalEventListener.h" +#include "mc/scripting/modules/minecraft/events/ScriptBlockGlobalEventListener.h" +#include "mc/scripting/modules/minecraft/events/ScriptLevelGlobalEventListener.h" #include "mc/world/actor/Actor.h" +#include "mc/world/actor/player/Player.h" #include "mc/world/events/ActorAttackEvent.h" #include "mc/world/events/ActorDiedEvent.h" #include "mc/world/events/ActorHealthChangedEvent.h" @@ -13,10 +16,9 @@ #include "mc/world/events/ActorRemovedEvent.h" #include "mc/world/events/EventResult.h" #include "mc/world/events/ProjectileHitEvent.h" -#include + namespace coral_fans::cfsp::fix { -std::unordered_multiset mRemovingSpSet; LL_TYPE_INSTANCE_HOOK( CFSPSapiFixHook1, @@ -29,7 +31,6 @@ LL_TYPE_INSTANCE_HOOK( if (auto entityContext = actorRemovedEvent.mEntity->lock()) { auto actor = Actor::tryGetFromEntity(*entityContext, false); if (actor && manager::CFSPManager::getInstance().tryGetCFSP(actor).has_value()) { - mRemovingSpSet.insert(static_cast(actor)->mName); return EventResult::KeepGoing; } } @@ -56,8 +57,8 @@ LL_TYPE_INSTANCE_HOOK( LL_TYPE_INSTANCE_HOOK( CFSPSapiFixHook3, ll::memory::HookPriority::Normal, - ScriptModuleMinecraft::ScriptActorEventListener, - &ScriptModuleMinecraft::ScriptActorEventListener::$onEvent, + ScriptModuleMinecraft::ScriptActorGlobalEventListener, + &ScriptModuleMinecraft::ScriptActorGlobalEventListener::$onEvent, EventResult, ::ActorHurtEvent const& actorHurtEvent ) { @@ -90,8 +91,8 @@ LL_TYPE_INSTANCE_HOOK( LL_TYPE_INSTANCE_HOOK( CFSPSapiFixHook5, ll::memory::HookPriority::Normal, - ScriptModuleMinecraft::ScriptActorEventListener, - &ScriptModuleMinecraft::ScriptActorEventListener::$onEvent, + ScriptModuleMinecraft::ScriptActorGlobalEventListener, + &ScriptModuleMinecraft::ScriptActorGlobalEventListener::$onEvent, EventResult, ::ActorDiedEvent const& actorDiedEvent ) { @@ -122,18 +123,102 @@ LL_TYPE_INSTANCE_HOOK( LL_TYPE_INSTANCE_HOOK( CFSPSapiFixHook7, ll::memory::HookPriority::Normal, - ScriptModuleMinecraft::ScriptLevelEventListener, - &ScriptModuleMinecraft::ScriptLevelEventListener::$onLevelRemovedPlayer, + ScriptModuleMinecraft::ScriptLevelGlobalEventListener, + &ScriptModuleMinecraft::ScriptLevelGlobalEventListener::$onLevelRemovedPlayer, EventResult, ::Player& player ) { - if (auto it = mRemovingSpSet.find(player.mName); it != mRemovingSpSet.end()) { - mRemovingSpSet.erase(it); + auto& removingList = fix::CFSPFixManager::getInstance().mRemovingRecord.mRemovingSpList; + if (auto it = removingList.find(player.mName); it != removingList.end()) { + return EventResult::KeepGoing; + } + return origin(player); +} + +LL_TYPE_INSTANCE_HOOK( + CFSPSapiFixHook8, + ll::memory::HookPriority::Normal, + ScriptModuleMinecraft::ScriptLevelGlobalEventListener, + &ScriptModuleMinecraft::ScriptLevelGlobalEventListener::$onLevelAddedPlayer, + EventResult, + Player& player +) { + if (fix::CFSPFixManager::getInstance().createSpMutex + || manager::CFSPManager::getInstance().tryGetCFSP(&player).has_value()) { return EventResult::KeepGoing; } return origin(player); } +LL_TYPE_INSTANCE_HOOK( + CFSPSapiFixHook9, + ll::memory::HookPriority::Normal, + ScriptModuleMinecraft::ScriptLevelGlobalEventListener, + &ScriptModuleMinecraft::ScriptLevelGlobalEventListener::$onLevelRemovedActor, + EventResult, + Actor& actor +) { + if (actor.isSimulatedPlayer()) { + auto& removingList = fix::CFSPFixManager::getInstance().mRemovingRecord.mRemovingSpList; + if (auto it = removingList.find(static_cast(&actor)->mName); it != removingList.end()) { + return EventResult::KeepGoing; + } + } + return origin(actor); +} + +LL_TYPE_INSTANCE_HOOK( + CFSPSapiFixHook10, + ll::memory::HookPriority::Normal, + ScriptModuleMinecraft::ScriptBlockGlobalEventListener, + &ScriptModuleMinecraft::ScriptBlockGlobalEventListener::$onBlockPlacedByPlayer, + EventResult, + ::Player& player, + ::Block const& placedBlock, + ::BlockPos const& pos, + bool isUnderwater +) { + if (manager::CFSPManager::getInstance().tryGetCFSP(&player).has_value()) { + return EventResult::KeepGoing; + } + return origin(player, placedBlock, pos, isUnderwater); +} + +LL_TYPE_INSTANCE_HOOK( + CFSPSapiFixHook11, + ll::memory::HookPriority::Normal, + ScriptModuleMinecraft::ScriptBlockGlobalEventListener, + &ScriptModuleMinecraft::ScriptBlockGlobalEventListener::$onBlockDestroyedByPlayer, + EventResult, + ::Player& player, + ::Block const& destroyedBlock, + ::BlockPos const& pos, + ::ItemStackBase const& currentItem, + ::ItemStackBase const& itemBeforeBlockBreak +) { + if (manager::CFSPManager::getInstance().tryGetCFSP(&player).has_value()) { + return EventResult::KeepGoing; + } + return origin(player, destroyedBlock, pos, currentItem, itemBeforeBlockBreak); +} + +LL_TYPE_INSTANCE_HOOK( + CFSPSapiFixHook12, + ll::memory::HookPriority::Normal, + ScriptModuleMinecraft::ScriptBlockGlobalEventListener, + &ScriptModuleMinecraft::ScriptBlockGlobalEventListener::$onBlockDestructionStarted, + EventResult, + ::Player& player, + ::BlockPos const& pos, + ::Block const& hitBlock, + uchar const face +) { + if (manager::CFSPManager::getInstance().tryGetCFSP(&player).has_value()) { + return EventResult::KeepGoing; + } + return origin(player, pos, hitBlock, face); +} + void CFSPFixManager::sapiFix() { CFSPSapiFixHook1::hook(); CFSPSapiFixHook2::hook(); @@ -142,5 +227,10 @@ void CFSPFixManager::sapiFix() { CFSPSapiFixHook5::hook(); CFSPSapiFixHook6::hook(); CFSPSapiFixHook7::hook(); + CFSPSapiFixHook8::hook(); + CFSPSapiFixHook9::hook(); + CFSPSapiFixHook10::hook(); + CFSPSapiFixHook11::hook(); + CFSPSapiFixHook12::hook(); } } // namespace coral_fans::cfsp::fix \ No newline at end of file diff --git a/src/cfsp/core/helper/CFSPAutoFuncHelper.cpp b/src/cfsp/core/helper/CFSPAutoFuncHelper.cpp index 00bb43c..ec20f17 100644 --- a/src/cfsp/core/helper/CFSPAutoFuncHelper.cpp +++ b/src/cfsp/core/helper/CFSPAutoFuncHelper.cpp @@ -46,12 +46,15 @@ LL_TYPE_INSTANCE_HOOK( auto cfsp = manager::CFSPManager::getInstance().tryGetCFSP(this); if (cfsp.has_value()) { cfsp.value()->stop(); - ll::command::CommandRegistrar::getInstance().addSoftEnumValues("cfspDeadSp", {cfsp.value()->mSaveData.name}); + ll::command::CommandRegistrar::getInstance(false).addSoftEnumValues( + "cfspDeadSp", + {cfsp.value()->mSaveData.name} + ); if (manager::CFSPManager::getInstance().getAutoRespawn()) { cfsp.value()->mTaskid = base::Schedule::getInstance().getSchedule()->add(20, [cfsp = cfsp.value()](unsigned long long) { if (!cfsp->respawn()) return false; - ll::command::CommandRegistrar::getInstance().removeSoftEnumValues( + ll::command::CommandRegistrar::getInstance(false).removeSoftEnumValues( "cfspDeadSp", {cfsp->mSaveData.name} ); diff --git a/src/cfsp/core/manager/CFSPGroupManager.cpp b/src/cfsp/core/manager/CFSPGroupManager.cpp index 3876f6b..8b1eef0 100644 --- a/src/cfsp/core/manager/CFSPGroupManager.cpp +++ b/src/cfsp/core/manager/CFSPGroupManager.cpp @@ -46,7 +46,7 @@ base::OperateResult CFSPManager::groupCreate(Player* player, std::string const& group->save(); this->mGroupMap.emplace(gname, group); - ll::command::CommandRegistrar::getInstance().addSoftEnumValues("cfspGroup", {gname}); + ll::command::CommandRegistrar::getInstance(false).addSoftEnumValues("cfspGroup", {gname}); return base::OperateResult::success("manager.success.create"_tr()); } @@ -82,7 +82,7 @@ base::OperateResult CFSPManager::groupDelete(Player* player, std::string const& if (checkResult.mType != base::OperateResult::Type::Success && !it->second->hasPermission(player, group::GroupPermission::Delete)) return base::OperateResult::error("manager.fail.permissionDenied"_tr()); - ll::command::CommandRegistrar::getInstance().removeSoftEnumValues("cfspGroup", {gname}); + ll::command::CommandRegistrar::getInstance(false).removeSoftEnumValues("cfspGroup", {gname}); this->mGroupMap.erase(it); try { std::filesystem::remove_all( @@ -199,6 +199,7 @@ GROUP_FUNC_FROM_SP(Destroy, Destroy(player, spname, _long, times, interval, true GROUP_FUNC_FROM_SP(Chat, Chat(player, spname, message, true), std::string const& message) GROUP_FUNC_FROM_SP(RunCmd, RunCmd(player, spname, message, true), std::string const& message) GROUP_FUNC_FROM_SP(LookAt, LookAt(player, spname, pos, true), Vec3 const& pos) +GROUP_FUNC_FROM_SP(LookAt, LookAt(player, spname, direction, true), simulated_player::SimPlayer::Direction direction) GROUP_FUNC_FROM_SP(MoveTo, MoveTo(player, spname, pos, speed, true), Vec3 const& pos, float speed) GROUP_FUNC_FROM_SP(NavTo, NavTo(player, spname, pos, speed, true), Vec3 const& pos, float speed) GROUP_FUNC_FROM_SP(Tp, Tp(player, spname, pos, dimId, true), Vec3 pos, std::optional dimId) diff --git a/src/cfsp/core/manager/CFSPManager.cpp b/src/cfsp/core/manager/CFSPManager.cpp index 9529141..9632fcb 100644 --- a/src/cfsp/core/manager/CFSPManager.cpp +++ b/src/cfsp/core/manager/CFSPManager.cpp @@ -93,10 +93,10 @@ void CFSPManager::loadSpSaveData() { } } } - ll::command::CommandRegistrar::getInstance().tryRegisterSoftEnum("cfspOfflineSp", splist); - ll::command::CommandRegistrar::getInstance().tryRegisterSoftEnum("cfspSplist", splist); - ll::command::CommandRegistrar::getInstance().tryRegisterSoftEnum("cfspOnlineSp", {}); - ll::command::CommandRegistrar::getInstance().tryRegisterSoftEnum("cfspDeadSp", {}); + ll::command::CommandRegistrar::getInstance(false).tryRegisterSoftEnum("cfspOfflineSp", splist); + ll::command::CommandRegistrar::getInstance(false).tryRegisterSoftEnum("cfspSplist", splist); + ll::command::CommandRegistrar::getInstance(false).tryRegisterSoftEnum("cfspOnlineSp", {}); + ll::command::CommandRegistrar::getInstance(false).tryRegisterSoftEnum("cfspDeadSp", {}); } void CFSPManager::loadGroupData() { @@ -123,7 +123,7 @@ void CFSPManager::loadGroupData() { } } } - ll::command::CommandRegistrar::getInstance().tryRegisterSoftEnum("cfspGroup", cfspGrouplist); + ll::command::CommandRegistrar::getInstance(false).tryRegisterSoftEnum("cfspGroup", cfspGrouplist); } bool CFSPManager::init() { diff --git a/src/cfsp/core/manager/CFSPManager.h b/src/cfsp/core/manager/CFSPManager.h index 5311a86..3804ab8 100644 --- a/src/cfsp/core/manager/CFSPManager.h +++ b/src/cfsp/core/manager/CFSPManager.h @@ -100,6 +100,8 @@ class CFSPManager { base::OperateResult spStop(Player* player, std::string const& spname, bool nocheck = false); base::OperateResult spInfo(Player* player, std::string const& spname, bool nocheck = false); base::OperateResult spLookAt(Player* player, std::string const& spname, Vec3 const& pos, bool nocheck = false); + base::OperateResult + spLookAt(Player* player, std::string const& spname, simulated_player::SimPlayer::Direction direction, bool nocheck = false); base::OperateResult spInvInfo(Player* player, std::string const& spname, bool nocheck = false); base::OperateResult @@ -222,6 +224,8 @@ class CFSPManager { std::vector groupRunCmd(Player* player, std::string const& gname, std::string const& message); std::vector groupLookAt(Player* player, std::string const& gname, Vec3 const& pos); + std::vector + groupLookAt(Player* player, std::string const& gname, simulated_player::SimPlayer::Direction direction); std::vector groupMoveTo(Player* player, std::string const& gname, Vec3 const& pos, float speed = 4.3f); diff --git a/src/cfsp/core/manager/CFSPSpManager.cpp b/src/cfsp/core/manager/CFSPSpManager.cpp index 76f28fd..22bb0b6 100644 --- a/src/cfsp/core/manager/CFSPSpManager.cpp +++ b/src/cfsp/core/manager/CFSPSpManager.cpp @@ -21,11 +21,9 @@ namespace coral_fans::cfsp::manager { bool nocheck \ ) { \ using ll::i18n_literals::operator""_tr; \ - if (!nocheck) { \ - if (auto checkResult = this->baseCheck(player, this->mPermissionConfig.sp##FUNC); !checkResult) \ - return checkResult; \ - else if (checkResult.mType == base::OperateResult::Type::Success) nocheck = true; \ - } \ + if (auto checkResult = this->baseCheck(player, this->mPermissionConfig.sp##FUNC); !checkResult) \ + return checkResult; \ + else if (checkResult.mType == base::OperateResult::Type::Success) nocheck = true; \ auto it = this->mOnlineSpMap.find(spname); \ if (it == this->mOnlineSpMap.end()) { \ if (this->mOfflineSpMap.find(spname) != this->mOfflineSpMap.end()) \ @@ -117,18 +115,16 @@ CFSPManager::spCreate(Player* player, std::string const& name, Vec3 const& pos, return base::OperateResult::error("manager.error.failedtocreate"_tr()); this->mOnlineSpMap[spname] = simplayer; - ll::command::CommandRegistrar::getInstance().addSoftEnumValues("cfspOnlineSp", {spname}); - ll::command::CommandRegistrar::getInstance().addSoftEnumValues("cfspSplist", {spname}); + ll::command::CommandRegistrar::getInstance(false).addSoftEnumValues("cfspOnlineSp", {spname}); + ll::command::CommandRegistrar::getInstance(false).addSoftEnumValues("cfspSplist", {spname}); return base::OperateResult::success("manager.success.create"_tr()); } base::OperateResult CFSPManager::spSpawn(Player* player, std::string const& spname, bool nocheck) { using ll::i18n_literals::operator""_tr; - if (!nocheck) { - if (auto checkResult = this->canSpawnPlayer(player); !checkResult) return checkResult; - else if (checkResult.mType == base::OperateResult::Type::Success) nocheck = true; - } + if (auto checkResult = this->canSpawnPlayer(player); !checkResult) return checkResult; + else if (checkResult.mType == base::OperateResult::Type::Success) nocheck = true; // check: exist auto it = this->mOfflineSpMap.find(spname); if (it == this->mOfflineSpMap.end()) { @@ -144,10 +140,10 @@ base::OperateResult CFSPManager::spSpawn(Player* player, std::string const& spna if (!res) [[unlikely]] return res; - ll::command::CommandRegistrar::getInstance().addSoftEnumValues("cfspOnlineSp", {spname}); - ll::command::CommandRegistrar::getInstance().removeSoftEnumValues("cfspOfflineSp", {spname}); + ll::command::CommandRegistrar::getInstance(false).addSoftEnumValues("cfspOnlineSp", {spname}); + ll::command::CommandRegistrar::getInstance(false).removeSoftEnumValues("cfspOfflineSp", {spname}); if (it->second->mSimPlayer->isDead()) - ll::command::CommandRegistrar::getInstance().addSoftEnumValues("cfspDeadSp", {it->first}); + ll::command::CommandRegistrar::getInstance(false).addSoftEnumValues("cfspDeadSp", {it->first}); if (auto node = mOfflineSpMap.extract(it)) { mOnlineSpMap.insert(std::move(node)); @@ -170,18 +166,15 @@ void CFSPManager::autoJoin() { } it++; } - ll::command::CommandRegistrar::getInstance().addSoftEnumValues("cfspOnlineSp", spawnlist); - ll::command::CommandRegistrar::getInstance().removeSoftEnumValues("cfspOfflineSp", spawnlist); - ll::command::CommandRegistrar::getInstance().addSoftEnumValues("cfspDeadSp", spawnDeadlist); + ll::command::CommandRegistrar::getInstance(false).addSoftEnumValues("cfspOnlineSp", spawnlist); + ll::command::CommandRegistrar::getInstance(false).removeSoftEnumValues("cfspOfflineSp", spawnlist); + ll::command::CommandRegistrar::getInstance(false).addSoftEnumValues("cfspDeadSp", spawnDeadlist); } base::OperateResult CFSPManager::spDespawn(Player* player, std::string const& spname, bool nocheck) { using ll::i18n_literals::operator""_tr; - if (!nocheck) { - if (auto checkResult = this->baseCheck(player, this->mPermissionConfig.spDespawn); !checkResult) - return checkResult; - else if (checkResult.mType == base::OperateResult::Type::Success) nocheck = true; - } + if (auto checkResult = this->baseCheck(player, this->mPermissionConfig.spDespawn); !checkResult) return checkResult; + else if (checkResult.mType == base::OperateResult::Type::Success) nocheck = true; // check: exist auto it = this->mOnlineSpMap.find(spname); if (it == this->mOnlineSpMap.end()) { @@ -199,10 +192,13 @@ base::OperateResult CFSPManager::spDespawn(Player* player, std::string const& sp TextPacket::createRawMessage("manager.success.spOffline"_tr(spname)).sendToClients(); - ll::command::CommandRegistrar::getInstance().addSoftEnumValues("cfspOfflineSp", {spname}); - ll::command::CommandRegistrar::getInstance().removeSoftEnumValues("cfspOnlineSp", {spname}); + ll::command::CommandRegistrar::getInstance(false).addSoftEnumValues("cfspOfflineSp", {spname}); + ll::command::CommandRegistrar::getInstance(false).removeSoftEnumValues("cfspOnlineSp", {spname}); if (isDead) - ll::command::CommandRegistrar::getInstance().removeSoftEnumValues("cfspDeadSp", {it->second->mSaveData.name}); + ll::command::CommandRegistrar::getInstance(false).removeSoftEnumValues( + "cfspDeadSp", + {it->second->mSaveData.name} + ); if (auto node = mOnlineSpMap.extract(it)) mOfflineSpMap.insert(std::move(node)); return res; @@ -214,19 +210,16 @@ void CFSPManager::autoDespawn(std::shared_ptr cfsp) cfsp->despawn(); auto spname = cfsp->mSaveData.name; TextPacket::createRawMessage("manager.success.autoDespawn"_tr(spname)).sendToClients(); - ll::command::CommandRegistrar::getInstance().addSoftEnumValues("cfspOfflineSp", {spname}); - ll::command::CommandRegistrar::getInstance().removeSoftEnumValues("cfspOnlineSp", {spname}); + ll::command::CommandRegistrar::getInstance(false).addSoftEnumValues("cfspOfflineSp", {spname}); + ll::command::CommandRegistrar::getInstance(false).removeSoftEnumValues("cfspOnlineSp", {spname}); if (auto node = mOnlineSpMap.extract(spname)) mOfflineSpMap.insert(std::move(node)); } base::OperateResult CFSPManager::spRespawn(Player* player, std::string const& spname, bool nocheck) { using ll::i18n_literals::operator""_tr; - if (!nocheck) { - if (auto checkResult = this->baseCheck(player, this->mPermissionConfig.spRespawn); !checkResult) - return checkResult; - else if (checkResult.mType == base::OperateResult::Type::Success) nocheck = true; - } + if (auto checkResult = this->baseCheck(player, this->mPermissionConfig.spRespawn); !checkResult) return checkResult; + else if (checkResult.mType == base::OperateResult::Type::Success) nocheck = true; // check: exist auto it = this->mOnlineSpMap.find(spname); if (it == this->mOnlineSpMap.end()) { @@ -240,27 +233,24 @@ base::OperateResult CFSPManager::spRespawn(Player* player, std::string const& sp auto res = it->second->respawn(); if (!res) [[unlikely]] return res; - ll::command::CommandRegistrar::getInstance().removeSoftEnumValues("cfspDeadSp", {it->second->mSaveData.name}); + ll::command::CommandRegistrar::getInstance(false).removeSoftEnumValues("cfspDeadSp", {it->second->mSaveData.name}); return res; } base::OperateResult CFSPManager::spDelete(Player* player, std::string const& spname, bool force, bool nocheck) { using ll::i18n_literals::operator""_tr; - if (!nocheck) { - if (auto checkResult = this->baseCheck(player, this->mPermissionConfig.spDelete); !checkResult) - return checkResult; - else if (checkResult.mType == base::OperateResult::Type::Success) nocheck = true; - } + if (auto checkResult = this->baseCheck(player, this->mPermissionConfig.spDelete); !checkResult) return checkResult; + else if (checkResult.mType == base::OperateResult::Type::Success) nocheck = true; bool deleteFail = false; if (auto it = this->mOnlineSpMap.find(spname); it != this->mOnlineSpMap.end()) { // check:permission if (!nocheck && !it->second->hasPermission(player, simulated_player::SimPlayerPermission::Delete)) return base::OperateResult::error("manager.fail.permissionDenied"_tr()); if (!force && !it->second->isEmptyInv()) return base::OperateResult::swing("manager.fail.notEmpty"_tr(spname)); - ll::command::CommandRegistrar::getInstance().removeSoftEnumValues("cfspSplist", {spname}); - ll::command::CommandRegistrar::getInstance().removeSoftEnumValues("cfspOnlineSp", {spname}); + ll::command::CommandRegistrar::getInstance(false).removeSoftEnumValues("cfspSplist", {spname}); + ll::command::CommandRegistrar::getInstance(false).removeSoftEnumValues("cfspOnlineSp", {spname}); if (!it->second->mSimPlayer || it->second->mSimPlayer->isDead()) - ll::command::CommandRegistrar::getInstance().removeSoftEnumValues( + ll::command::CommandRegistrar::getInstance(false).removeSoftEnumValues( "cfspDeadSp", {it->second->mSaveData.name} ); @@ -285,8 +275,8 @@ base::OperateResult CFSPManager::spDelete(Player* player, std::string const& spn return base::OperateResult::error("manager.fail.permissionDenied"_tr()); if (!force && !it->second->checkInvEmptyForOfflineCFSP()) return base::OperateResult::swing("manager.fail.notEmpty"_tr(spname)); - ll::command::CommandRegistrar::getInstance().removeSoftEnumValues("cfspSplist", {spname}); - ll::command::CommandRegistrar::getInstance().removeSoftEnumValues("cfspOfflineSp", {spname}); + ll::command::CommandRegistrar::getInstance(false).removeSoftEnumValues("cfspSplist", {spname}); + ll::command::CommandRegistrar::getInstance(false).removeSoftEnumValues("cfspOfflineSp", {spname}); try { std::filesystem::remove_all( CFSP::getInstance().getSelf().getDataDir() / "simplayer" @@ -309,10 +299,8 @@ base::OperateResult CFSPManager::spDelete(Player* player, std::string const& spn base::OperateResult CFSPManager::spInfo(Player* player, std::string const& spname, bool nocheck) { using ll::i18n_literals::operator""_tr; - if (!nocheck) { - if (!isAllowed(player)) return base::OperateResult::error("manager.fail.permissionDenied"_tr()); - if (isManager(player)) nocheck = true; - } + if (!isAllowed(player)) return base::OperateResult::error("manager.fail.permissionDenied"_tr()); + if (isManager(player)) nocheck = true; auto it = this->mOnlineSpMap.find(spname); if (it == this->mOnlineSpMap.end()) { it = this->mOfflineSpMap.find(spname); @@ -325,10 +313,8 @@ base::OperateResult CFSPManager::spInfo(Player* player, std::string const& spnam base::OperateResult CFSPManager::spInvInfo(Player* player, std::string const& spname, bool nocheck) { using ll::i18n_literals::operator""_tr; - if (!nocheck) { - if (!isAllowed(player)) return base::OperateResult::error("manager.fail.permissionDenied"_tr()); - if (isManager(player)) nocheck = true; - } + if (!isAllowed(player)) return base::OperateResult::error("manager.fail.permissionDenied"_tr()); + if (isManager(player)) nocheck = true; auto it = this->mOnlineSpMap.find(spname); if (it == this->mOnlineSpMap.end()) { if (this->mOfflineSpMap.find(spname) != this->mOfflineSpMap.end()) @@ -342,6 +328,7 @@ base::OperateResult CFSPManager::spInvInfo(Player* player, std::string const& sp SP_ONLINE_FUNC_DEF(Stop, stop()) SP_ONLINE_FUNC_DEF(LookAt, lookAt(pos), Vec3 const& pos) +SP_ONLINE_FUNC_DEF(LookAt, lookAt(direction), simulated_player::SimPlayer::Direction direction) SP_ONLINE_FUNC_DEF(Drop, drop(times, interval), int times, int interval) SP_ONLINE_FUNC_DEF(DropInv, dropInv(times, interval), int times, int interval) diff --git a/src/cfsp/core/simPlayer/SimPlayer.cpp b/src/cfsp/core/simPlayer/SimPlayer.cpp index f177c8f..d1013ff 100644 --- a/src/cfsp/core/simPlayer/SimPlayer.cpp +++ b/src/cfsp/core/simPlayer/SimPlayer.cpp @@ -5,11 +5,14 @@ #include "cfsp/core/fix/CFSPFixManager.h" #include "ll/api/i18n/I18n.h" #include "ll/api/service/Bedrock.h" +#include "mc/deps/core/math/Vec3.h" #include "mc/server/SimulatedPlayer.h" #include "mc/server/sim/ContinuousLookAtPositionIntent.h" #include "mc/server/sim/sim.h" #include "mc/world/Minecraft.h" -#include "mc/world/actor/provider/ActorAttribute.h" +#include "mc/world/level/Level.h" + +// #include "mc/world/actor/provider/ActorAttribute.h" #include @@ -123,10 +126,18 @@ base::OperateResult SimPlayer::despawn() { this->mSaveData.isOnline = false; this->mShouldSave = true; this->save(); + + auto& removingRecord = fix::CFSPFixManager::getInstance().mRemovingRecord; + auto currentTick = this->mSimPlayer->getLevel().getCurrentTick(); + if (currentTick.tickID - removingRecord.mLastTick.tickID > 2) { + removingRecord.mRemovingSpList.clear(); + } + removingRecord.mLastTick = currentTick; + removingRecord.mRemovingSpList.emplace(this->mSimPlayer->mName); + + this->mSimPlayer->disconnect(); - // try { this->mSimPlayer->remove(); - // } catch (...) {} this->mSimPlayer->setGameTestHelper(nullptr); this->mSimPlayer = nullptr; return base::OperateResult::success("manager.success.operate"_tr()); @@ -161,8 +172,7 @@ base::OperateResult SimPlayer::info() { + this->mSimPlayer->mPlayerRespawnPoint->mPlayerPosition->toString() + "\n "; res += "manager.info.spGamemode"_tr() + base::utils::getGameModeStr((int)this->mSimPlayer->getPlayerGameType()) + "\n "; - res += "manager.info.spHealth"_tr() - + std::to_string(ActorAttribute::getHealth(this->mSimPlayer->getEntityContext())) + " / " + res += "manager.info.spHealth"_tr() + std::to_string(mSimPlayer->getHealth()) + " / " + std::to_string(this->mSimPlayer->getMaxHealth()) + "\n "; res += "manager.info.spIsFree"_tr() + (this->isFree() ? "base.yesOrNo.yes"_tr() : "base.yesOrNo.no"_tr()); } @@ -182,4 +192,44 @@ base::OperateResult SimPlayer::lookAt(Vec3 const& pos) { this->mSimPlayer->mLookAtIntent->mType = sim::ContinuousLookAtPositionIntent(glm::vec3(pos.x, pos.y, pos.z), false); return base::OperateResult::success("manager.success.operate"_tr()); } + +base::OperateResult SimPlayer::lookAt(Direction direction) { + using ll::i18n_literals::operator""_tr; + if (!this->mSimPlayer) [[unlikely]] + return base::OperateResult::error("manager.error.loseSimplayer"_tr()); + if (this->mSimPlayer->isDead()) [[unlikely]] + return base::OperateResult::error("manager.fail.spIsDead"_tr()); + + Vec3 offSet; + switch (direction) { + case Direction::North: + offSet = {0, 0, -1}; + break; + case Direction::South: + offSet = {0, 0, 1}; + break; + case Direction::West: + offSet = {-1, 0, 0}; + break; + case Direction::East: + offSet = {1, 0, 0}; + break; + case Direction::Up: + offSet = {0, 1, 0}; + break; + case Direction::Down: + offSet = {0, -1, 0}; + break; + default: + return base::OperateResult::error("manager.fail.invalidDirection"_tr()); + } + + this->mSaveData.lookAtOffSet = offSet; + this->mSimPlayer->simulateSetBodyRotation( + (float)(atan2(this->mSaveData.lookAtOffSet.z, this->mSaveData.lookAtOffSet.x) * 57.295776) - 90.0f + ); + Vec3 pos = this->mSimPlayer->getEyePos() + offSet; + this->mSimPlayer->mLookAtIntent->mType = sim::ContinuousLookAtPositionIntent(glm::vec3(pos.x, pos.y, pos.z), false); + return base::OperateResult::success("manager.success.operate"_tr()); +} } // namespace coral_fans::cfsp::simulated_player \ No newline at end of file diff --git a/src/cfsp/core/simPlayer/SimPlayer.h b/src/cfsp/core/simPlayer/SimPlayer.h index ddf4240..c4db5ff 100644 --- a/src/cfsp/core/simPlayer/SimPlayer.h +++ b/src/cfsp/core/simPlayer/SimPlayer.h @@ -38,6 +38,9 @@ class SimPlayer { uint getPermission(Player*); base::OperateResult setPermission(Player*, SimPlayerPermission); +public: + enum class Direction : int { North, South, West, East, Up, Down }; + public: CFSP_API void cancelTask(); CFSP_API void cancelScript(); @@ -48,6 +51,7 @@ class SimPlayer { CFSP_API base::OperateResult despawn(); CFSP_API base::OperateResult respawn(); CFSP_API base::OperateResult lookAt(Vec3 const& pos); + CFSP_API base::OperateResult lookAt(Direction direction); CFSP_API base::OperateResult info(); public: diff --git a/src/cfsp/core/simPlayer/SimPlayerMessage.cpp b/src/cfsp/core/simPlayer/SimPlayerMessage.cpp index 35437dc..eca5cb1 100644 --- a/src/cfsp/core/simPlayer/SimPlayerMessage.cpp +++ b/src/cfsp/core/simPlayer/SimPlayerMessage.cpp @@ -24,7 +24,9 @@ base::OperateResult SimPlayer::runcmd(std::string const& cmd) { return base::OperateResult::error("manager.error.loseSimplayer"_tr()); CommandContext ctx( cmd, - std::make_unique(PlayerCommandOrigin(*this->mSimPlayer)), + std::make_unique( + PlayerCommandOrigin(this->mSimPlayer->getLevel(), this->mSimPlayer->getOrCreateUniqueID()) + ), CommandVersion::CurrentVersion() ); auto mc = ll::service::getMinecraft(); diff --git a/src/cfsp/core/simPlayer/SimPlayerStatus.cpp b/src/cfsp/core/simPlayer/SimPlayerStatus.cpp index fc90ed7..a3d9833 100644 --- a/src/cfsp/core/simPlayer/SimPlayerStatus.cpp +++ b/src/cfsp/core/simPlayer/SimPlayerStatus.cpp @@ -44,7 +44,7 @@ base::OperateResult SimPlayer::flying(std::optional enable) { )) return base::OperateResult::success("manager.success.operate"_tr()); } - return base::OperateResult::error("manager.error.faileToSetFlying"_tr()); + return base::OperateResult::error("manager.fail.faileToSetFlying"_tr()); } base::OperateResult SimPlayer::sprinting(std::optional enable) { diff --git a/src/cfsp/entrance/command/ComandManager.cpp b/src/cfsp/entrance/command/ComandManager.cpp index 54876b0..9ce05c7 100644 --- a/src/cfsp/entrance/command/ComandManager.cpp +++ b/src/cfsp/entrance/command/ComandManager.cpp @@ -31,13 +31,13 @@ void ComandManager::registerCommand(CommandPermissionLevel permission) { using ll::i18n_literals::operator""_tr; // reg cmd - this->command = &ll::command::CommandRegistrar::getInstance() + this->command = &ll::command::CommandRegistrar::getInstance(false) .getOrCreateCommand("sp", "command.sp.description"_tr(), permission); // sp version this->command->overload().text("version").execute([](CommandOrigin const&, CommandOutput& output) { -#ifdef VERSION - output.success(VERSION); +#ifdef CF_VERSION + output.success(CF_VERSION); #endif #ifdef COMMITID output.success("Commit ID: {}", COMMITID); @@ -45,7 +45,7 @@ void ComandManager::registerCommand(CommandPermissionLevel permission) { }); // sp c - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspSettingType", { {"autojoin", 0}, @@ -76,7 +76,7 @@ void ComandManager::registerCommand(CommandPermissionLevel permission) { }); // sp - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspManagerSettingType", { {"addmanager", 0}, diff --git a/src/cfsp/entrance/command/GroupCommand.cpp b/src/cfsp/entrance/command/GroupCommand.cpp index 636b3e8..fc02016 100644 --- a/src/cfsp/entrance/command/GroupCommand.cpp +++ b/src/cfsp/entrance/command/GroupCommand.cpp @@ -131,7 +131,7 @@ void ComandManager::registerGroupComand() { }); // sp g - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspGroupOperate1", { {"addsp", 0}, @@ -167,7 +167,7 @@ void ComandManager::registerGroupComand() { }); // sp g - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspGroupOperate2", { {"delete", 0}, @@ -259,7 +259,7 @@ void ComandManager::registerGroupComand() { }); // sp g [enabled: bool] - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspGroupOperate3", { {"sneaking", 0}, @@ -291,7 +291,7 @@ void ComandManager::registerGroupComand() { }); // sp g [times: int] [interval: int] - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspGroupOperate4", { {"attack", 0}, @@ -330,7 +330,7 @@ void ComandManager::registerGroupComand() { }); // sp g [long: int] [times: int] [interval: int] - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspGroupOperate5", { {"use", 0}, @@ -358,7 +358,7 @@ void ComandManager::registerGroupComand() { }); // sp g - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspGroupOperate6", { {"chat", 0}, @@ -430,8 +430,37 @@ void ComandManager::registerGroupComand() { for (auto perRes : res) perRes.output(output); }); + // sp g lookat + ll ::command ::CommandRegistrar ::getInstance(false).tryRegisterRuntimeEnum( + "cfspFacing", + { + {"north", 0}, + {"south", 1}, + {"west", 2}, + {"east", 3}, + {"up", 4}, + {"down", 5} + } + ); + this->command->runtimeOverload() + .text("g") + .text("lookat") + .required("gname", ll::command::ParamKind::SoftEnum, "cfspGroup") + .required("facing", ll::command::ParamKind::Enum, "cfspFacing") + .execute([this](CommandOrigin const& origin, CommandOutput& output, ll::command::RuntimeCommand const& self) { + auto player = this->tryGetPlayer(origin); + if (!player.has_value()) return output.error("command.fail.illegalOrigin"_tr()); + std::vector res; + res = manager::CFSPManager::getInstance().groupLookAt( + player.value(), + self["gname"].get(), + static_cast(self["facing"].get().index) + ); + for (auto perRes : res) perRes.output(output); + }); + // sp g [pos: Vec3] [speed: float] - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspGroupOperate7", { {"moveto", 0}, @@ -533,7 +562,7 @@ void ComandManager::registerGroupComand() { for (auto perRes : res) perRes.output(output); }); - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspGroupPermType", { {"all", -1}, diff --git a/src/cfsp/entrance/command/SpCommand.cpp b/src/cfsp/entrance/command/SpCommand.cpp index 196ecaf..b7a5d8d 100644 --- a/src/cfsp/entrance/command/SpCommand.cpp +++ b/src/cfsp/entrance/command/SpCommand.cpp @@ -131,7 +131,7 @@ void ComandManager::registerSpComand() { using ll::i18n_literals::operator""_tr; // sp list p [online|offline] - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspOnlineType", { {"online", 0}, @@ -247,7 +247,7 @@ void ComandManager::registerSpComand() { }); // sp p - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspOnlineSpOperate1", { {"despawn", 0}, @@ -315,7 +315,7 @@ void ComandManager::registerSpComand() { }); // sp p [enabled: bool] - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspOnlineSpOperate2", { {"sneaking", 0}, @@ -346,7 +346,7 @@ void ComandManager::registerSpComand() { }); // sp p [times: int] [interval: int] - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspOnlineSpOperate3", { {"attack", 0}, @@ -383,7 +383,7 @@ void ComandManager::registerSpComand() { }); // sp p [long: int] [times: int] [interval: int] - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspOnlineSpOperate4", { {"use", 0}, @@ -409,7 +409,7 @@ void ComandManager::registerSpComand() { }); // sp p - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspOnlineSpOperate5", { {"chat", 0}, @@ -468,8 +468,37 @@ void ComandManager::registerSpComand() { .output(output); }); + // sp p lookat + ll ::command ::CommandRegistrar ::getInstance(false).tryRegisterRuntimeEnum( + "cfspFacing", + { + {"north", 0}, + {"south", 1}, + {"west", 2}, + {"east", 3}, + {"up", 4}, + {"down", 5} + } + ); + this->command->runtimeOverload() + .text("p") + .text("lookat") + .required("spname", ll ::command ::ParamKind ::SoftEnum, "cfspOnlineSp") + .required("facing", ll ::command ::ParamKind ::Enum, "cfspFacing") + .execute([this](CommandOrigin const& origin, CommandOutput& output, ll ::command ::RuntimeCommand const& self) { + auto player = this->tryGetPlayer(origin); + if (!player.has_value()) return output.error("command.fail.illegalOrigin"_tr()); + return manager ::CFSPManager ::getInstance() + .spLookAt( + player.value(), + self["spname"].get(), + static_cast(self["facing"].get().index) + ) + .output(output); + }); + // sp p [pos: Vec3] [speed: float] - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspOnlineSpOperate6", { {"moveto", 0}, @@ -578,7 +607,7 @@ void ComandManager::registerSpComand() { }); // sp p perm - ll::command::CommandRegistrar::getInstance().tryRegisterRuntimeEnum( + ll::command::CommandRegistrar::getInstance(false).tryRegisterRuntimeEnum( "cfspSpPermType", { {"all", -1}, diff --git a/src/lang/en_US.json b/src/lang/en_US.json index f86744b..96a700f 100644 --- a/src/lang/en_US.json +++ b/src/lang/en_US.json @@ -62,7 +62,8 @@ "targetNotHavePerm": "Target does not have this permission", "targetIsSp": "Target object is a SimulatedPlayer", "targetIsManager": "Target object is already a manager", - "targetNotManager": "Target object is not a manager" + "targetNotManager": "Target object is not a manager", + "invalidDirection": "Invalid direction" }, "error": { "failedtocreate": "Error: Failed to create SimulatedPlayer", diff --git a/src/lang/zh_CN.json b/src/lang/zh_CN.json index b7cb57c..5c04a16 100644 --- a/src/lang/zh_CN.json +++ b/src/lang/zh_CN.json @@ -62,7 +62,8 @@ "targetNotHavePerm": "目标没有该权限", "targetIsSp": "目标对象为假人", "targetIsManager": " 目标对象已为管理员", - "targetNotManager": " 目标对象不是管理员" + "targetNotManager": " 目标对象不是管理员", + "invalidDirection": "无效的方向" }, "error": { "failedtocreate": "Error: 创建假人失败", diff --git a/tooth.json b/tooth.json index 1341441..dfc9013 100644 --- a/tooth.json +++ b/tooth.json @@ -1,7 +1,7 @@ { "format_version": 2, "tooth": "github.com/CoralFans-Dev/CFSP", - "version": "3.3.1", + "version": "3.4.0", "info": { "name": "CFSP", "description": "CoralFans SimulatedPlayer", @@ -13,7 +13,7 @@ }, "asset_url": "https://github.com/CoralFans-Dev/CFSP/releases/download/v$(version)/CFSP-windows-x64.zip", "prerequisites": { - "github.com/LiteLDev/LeviLamina": ">=1.7.0 <1.8.0" + "github.com/LiteLDev/LeviLamina": ">=1.9.0 <1.10.0" }, "files": { "place": [ diff --git a/xmake.lua b/xmake.lua index 4d2b8f7..435f176 100644 --- a/xmake.lua +++ b/xmake.lua @@ -3,20 +3,28 @@ add_rules("mode.debug", "mode.release") add_repositories("liteldev-repo https://github.com/LiteLDev/xmake-repo.git") add_repositories("coralfansdev-repo https://github.com/CoralFans-Dev/xmake-repo.git") --- add_requires("levilamina x.x.x") for a specific version --- add_requires("levilamina develop") to use develop version --- please note that you should add bdslibrary yourself if using dev version +if is_config("target_type", "server") then + add_requires("levilamina", {configs = {target_type = "server"}}) +else + add_requires("levilamina", {configs = {target_type = "client"}}) +end + add_requires( - "levilamina 1.7.3", "levibuildscript", - "timewheel" + "timewheel", + "boost", {configs = {all = true}} ) -add_requires("boost", {configs = {all = true}}) if not has_config("vs_runtime") then set_runtimes("MD") end +option("target_type") + set_default("server") + set_showmenu(true) + set_values("server", "client") +option_end() + target("CFSP") -- Change this to your mod name. add_rules("@levibuildscript/linkrule") add_cxflags( @@ -31,7 +39,7 @@ target("CFSP") -- Change this to your mod name. "/w45204" ) add_defines("NOMINMAX", "UNICODE", "CFSPEXP") - add_defines("VERSION=\"$(shell git describe --tags --abbrev=0 --always)\"") + add_defines("CF_VERSION=\"$(shell git describe --tags --abbrev=0 --always)\"") add_defines("COMMITID=\"$(shell git rev-parse HEAD)\"") add_files("src/**.cpp") add_headerfiles("src/(cfsp/**.h)") @@ -48,6 +56,15 @@ target("CFSP") -- Change this to your mod name. set_kind("shared") set_languages("c++20") set_symbols("debug") + if is_config("target_type", "server") then + add_defines("LL_PLAT_S") + -- add_includedirs("src-server") + -- add_files("src-server/**.cpp") + else + add_defines("LL_PLAT_C") + -- add_includedirs("src-client") + -- add_files("src-client/**.cpp") + end after_build(function (target) local mod_packer = import("scripts.after_build")