#include "ScriptMgr.h" #include "Player.h" #include "GameObject.h" #include "ObjectAccessor.h" #include "GridNotifiers.h" #include "CellImpl.h" #include "Config.h" namespace { std::vector sBobberEntries; bool sEnabled = true; uint32 sTickMs = 200; float sScanRange = 30.0f; std::vector ParseEntryList(std::string const& csv) { std::vector out; std::stringstream ss(csv); std::string item; while (std::getline(ss, item, ',')) { auto trim = [](std::string& s) { s.erase(0, s.find_first_not_of(" \t\r\n")); s.erase(s.find_last_not_of(" \t\r\n") + 1); }; trim(item); if (!item.empty()) out.push_back(static_cast(std::stoul(item))); } return out; } void TryAutoLootNearbyBobber(Player* plr) { if (!plr || !plr->IsInWorld()) return; std::list goList; Acore::AllGameObjectsMatchingOneEntryInRange check(plr, sBobberEntries, sScanRange); Acore::GameObjectListSearcher searcher(plr, goList, check); Cell::VisitObjects(plr, searcher, sScanRange); for (GameObject* go : goList) { if (!go) continue; if (go->GetOwnerGUID() != plr->GetGUID()) continue; if (go->getLootState() == GO_READY) { plr->SendLoot(go->GetGUID(), LOOT_FISHING); return; } } } } class AutoFish_WorldUpdate : public WorldScript { public: AutoFish_WorldUpdate() : WorldScript("AutoFish_WorldUpdate") {} void OnAfterConfigLoad(bool) override { sEnabled = sConfigMgr->GetOption("AutoFish.Enabled", true); sTickMs = sConfigMgr->GetOption("AutoFish.TickMs", 200u); sScanRange = sConfigMgr->GetOption("AutoFish.ScanRange", 30.0f); sBobberEntries = ParseEntryList(sConfigMgr->GetOption("AutoFish.BobberEntries", "35591")); } void OnUpdate(uint32 diff) override { if (!sEnabled) return; static uint32 acc = 0; acc += diff; if (acc < sTickMs) return; acc = 0; auto const& players = ObjectAccessor::GetPlayers(); for (auto const& kv : players) { Player* plr = kv.second; if (!plr || !plr->IsInWorld() || plr->IsGameMaster()) continue; TryAutoLootNearbyBobber(plr); } } }; void AddSC_autofish_world() { new AutoFish_WorldUpdate(); }