Merge pull request #218 from andiabrudan/configurable_vacuum_loot

Add user configurable items to VacuumLoot
This commit is contained in:
Callow 2022-07-07 03:10:01 +03:00 committed by GitHub
commit f644b32e71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 259 additions and 85 deletions

View File

@ -172,6 +172,30 @@ namespace util
return tokens;
}
std::string SplitWords(const std::string& value)
{
std::stringstream outStream;
std::stringstream inStream(value);
char ch;
inStream >> ch;
outStream << ch;
while (inStream >> ch)
{
if (isupper(ch))
outStream << " ";
outStream << ch;
}
return outStream.str();
}
std::string MakeCapital(std::string value)
{
if (islower(value[0]))
value[0] = toupper(value[0]);
return value;
}
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"

View File

@ -37,6 +37,8 @@ namespace util
int64_t GetCurrentTimeMillisec();
std::vector<std::string> StringSplit(const std::string& delimiter, const std::string& content);
std::string SplitWords(const std::string& value);
std::string MakeCapital(std::string value);
std::string to_hex_string(uint8_t* barray, int length);
bool IsLittleEndian();

View File

@ -409,31 +409,7 @@ namespace cheat::feature
return;
}
std::string SplitWords(const std::string& value)
{
std::stringstream outStream;
std::stringstream inStream(value);
char ch;
inStream >> ch;
outStream << ch;
while (inStream >> ch)
{
if (isupper(ch))
outStream << " ";
outStream << ch;
}
return outStream.str();
}
std::string MakeCapital(std::string value)
{
if (islower(value[0]))
value[0] = toupper(value[0]);
return value;
}
#define ADD_FILTER_FIELD(section, name) AddFilter(MakeCapital(#section), SplitWords(#name), &game::filters::##section##::##name##)
#define ADD_FILTER_FIELD(section, name) AddFilter(util::MakeCapital(#section), util::SplitWords(#name), &game::filters::##section##::##name##)
void ESP::InstallFilters()
{
ADD_FILTER_FIELD(collection, Book);

View File

@ -29,6 +29,16 @@ namespace cheat::game::filters
ChestFilter STrap = ChestFilter(game::Chest::ChestState::Trap);
}
namespace equipment
{
SimpleFilter Artifacts = { app::EntityType__Enum_1::DropItem, "_Relic" };
SimpleFilter Bow = { app::EntityType__Enum_1::DropItem, "_Bow" };
SimpleFilter Claymore = { app::EntityType__Enum_1::DropItem, "_Claymore" };
SimpleFilter Catalyst = { app::EntityType__Enum_1::DropItem, "_Catalyst" };
SimpleFilter Pole = { app::EntityType__Enum_1::DropItem, "_Pole" };
SimpleFilter Sword = { app::EntityType__Enum_1::DropItem, "_Sword" };
}
namespace featured
{
SimpleFilter Anemoculus = { app::EntityType__Enum_1::GatherObject, "WindCrystalShell" };
@ -93,12 +103,13 @@ namespace cheat::game::filters
SimpleFilter WeaselThief = { app::EntityType__Enum_1::Monster, "Thoarder_Weasel" };
SimpleFilter Kitsune = { app::EntityType__Enum_1::EnvAnimal, "Vulpes" };
SimpleFilter BakeDanuki = { app::EntityType__Enum_1::Monster, "Inu_Tanuki" };
SimpleFilter Meat = { app::EntityType__Enum_1::GatherObject , std::vector<std::string> { "_Food_BirdMeat", "_Food_Meat", "_Fishmeat" }};
}
namespace mineral
{
SimpleFilter AmethystLump = { app::EntityType__Enum_1::GatherObject, "_Thundercrystal" };
SimpleFilter ArchaicStone = { app::EntityType__Enum_1::GatherObject, "AncientOre" };
SimpleFilter ArchaicStone = { app::EntityType__Enum_1::GatherObject, "_AncientOre" };
SimpleFilter CorLapis = { app::EntityType__Enum_1::GatherObject, "_ElementRock" };
SimpleFilter CrystalChunk = { app::EntityType__Enum_1::GatherObject,
std::vector<std::string> { "_OreCrystal", "_ShiningCrystalOre" } };
@ -112,6 +123,16 @@ namespace cheat::game::filters
SimpleFilter Starsilver = { app::EntityType__Enum_1::GatherObject, "_OreMoonMeteor" };
SimpleFilter WhiteIronChunk = { app::EntityType__Enum_1::GatherObject, "_OreMetal" };
SimpleFilter DunlinsTooth = { app::EntityType__Enum_1::GatherObject, "_DunlinsTooth" };
SimpleFilter AmethystLumpDrop = { app::EntityType__Enum_1::GatherObject, "_Thundercrystaldrop" };
SimpleFilter CrystalChunkDrop = { app::EntityType__Enum_1::GatherObject,"_Drop_Crystal"};
SimpleFilter ElectroCrystalDrop = { app::EntityType__Enum_1::GatherObject, "_Drop_Ore_ElectricRock" };
SimpleFilter IronChunkDrop = { app::EntityType__Enum_1::GatherObject, "_Drop_Stone" };
SimpleFilter NoctilucousJadeDrop = { app::EntityType__Enum_1::GatherObject,"_NightBerth" };
SimpleFilter MagicalCrystalChunkDrop = { app::EntityType__Enum_1::GatherObject, "_DropMagicCrystal" };
SimpleFilter ScarletQuartzDrop = { app::EntityType__Enum_1::GatherObject, "_DropDulinsBlood" };
SimpleFilter StarsilverDrop = { app::EntityType__Enum_1::GatherObject, "_DropMoonMeteor" };
SimpleFilter WhiteIronChunkDrop = { app::EntityType__Enum_1::GatherObject, "_Drop_Metal" };
}
namespace monster
@ -193,6 +214,7 @@ namespace cheat::game::filters
SimpleFilter BambooShoot = { app::EntityType__Enum_1::GatherObject, "_Bambooshoot" };
SimpleFilter Berry = { app::EntityType__Enum_1::GatherObject, "_Raspberry" };
SimpleFilter CallaLily = { app::EntityType__Enum_1::GatherObject, "_Plant_Callas" };
SimpleFilter Cabbage = { app::EntityType__Enum_1::GatherObject, "_Plant_Cabbage" };
SimpleFilter Carrot = { app::EntityType__Enum_1::GatherObject, "_Plant_Carrot" };
SimpleFilter Cecilia = { app::EntityType__Enum_1::GatherObject, "_Cecilia" };
SimpleFilter DandelionSeed = { app::EntityType__Enum_1::GatherObject, "_Plant_Dandelion" };
@ -211,6 +233,7 @@ namespace cheat::game::filters
SimpleFilter NakuWeed = { app::EntityType__Enum_1::GatherObject, "_Howlgrass" };
SimpleFilter PhilanemoMushroom = { app::EntityType__Enum_1::GatherObject, "_WindmilHunter" };
SimpleFilter Pinecone = { app::EntityType__Enum_1::GatherObject, "_Drop_Plant_Pine" };
SimpleFilter Potato = { app::EntityType__Enum_1::GatherObject, "_Plant_Potato" };
SimpleFilter Qingxin = { app::EntityType__Enum_1::GatherObject, "_QingXin" };
SimpleFilter Radish = { app::EntityType__Enum_1::GatherObject, "_Plant_Radish" };
SimpleFilter SakuraBloom = { app::EntityType__Enum_1::GatherObject, "_Cherrypetals" };
@ -224,6 +247,7 @@ namespace cheat::game::filters
SimpleFilter SweetFlower = { app::EntityType__Enum_1::GatherObject, "_Plant_Whiteballet" };
SimpleFilter Valberry = { app::EntityType__Enum_1::GatherObject, "_DropingBerry_Gather" };
SimpleFilter Violetgrass = { app::EntityType__Enum_1::GatherObject, "_GlazedGrass" };
SimpleFilter Wheat = { app::EntityType__Enum_1::GatherObject, "_Plant_Wheat" };
SimpleFilter WindwheelAster = { app::EntityType__Enum_1::GatherObject, "_WindmilDaisy" };
SimpleFilter Wolfhook = { app::EntityType__Enum_1::GatherObject, "_GogoFruit" };
}

View File

@ -32,6 +32,16 @@ namespace cheat::game::filters
extern ChestFilter STrap;
}
namespace equipment
{
extern SimpleFilter Artifacts;
extern SimpleFilter Bow;
extern SimpleFilter Claymore;
extern SimpleFilter Catalyst;
extern SimpleFilter Pole;
extern SimpleFilter Sword;
}
namespace featured
{
extern SimpleFilter Anemoculus;
@ -94,6 +104,7 @@ namespace cheat::game::filters
extern SimpleFilter Weasel;
extern SimpleFilter Kitsune;
extern SimpleFilter BakeDanuki;
extern SimpleFilter Meat;
}
namespace mineral
@ -111,6 +122,16 @@ namespace cheat::game::filters
extern SimpleFilter Starsilver;
extern SimpleFilter WhiteIronChunk;
extern SimpleFilter DunlinsTooth;
extern SimpleFilter AmethystLumpDrop;
extern SimpleFilter CrystalChunkDrop;
extern SimpleFilter ElectroCrystalDrop;
extern SimpleFilter IronChunkDrop;
extern SimpleFilter NoctilucousJadeDrop;
extern SimpleFilter MagicalCrystalChunkDrop;
extern SimpleFilter ScarletQuartzDrop;
extern SimpleFilter StarsilverDrop;
extern SimpleFilter WhiteIronChunkDrop;
}
namespace monster
@ -189,6 +210,7 @@ namespace cheat::game::filters
extern SimpleFilter Apple;
extern SimpleFilter BambooShoot;
extern SimpleFilter Berry;
extern SimpleFilter Cabbage;
extern SimpleFilter CallaLily;
extern SimpleFilter Carrot;
extern SimpleFilter Cecilia;
@ -208,6 +230,7 @@ namespace cheat::game::filters
extern SimpleFilter NakuWeed;
extern SimpleFilter PhilanemoMushroom;
extern SimpleFilter Pinecone;
extern SimpleFilter Potato;
extern SimpleFilter Qingxin;
extern SimpleFilter Radish;
extern SimpleFilter SakuraBloom;
@ -221,6 +244,7 @@ namespace cheat::game::filters
extern SimpleFilter SweetFlower;
extern SimpleFilter Valberry;
extern SimpleFilter Violetgrass;
extern SimpleFilter Wheat;
extern SimpleFilter WindwheelAster;
extern SimpleFilter Wolfhook;
}

View File

@ -9,20 +9,44 @@
namespace cheat::feature
{
VacuumLoot::VacuumLoot() : Feature(),
NF(f_Enabled, "Vacuum Loot", "VacuumLoot", false)
{
events::GameUpdateEvent += MY_METHOD_HANDLER(VacuumLoot::OnGameUpdate);
}
NF(f_Enabled, "Vacuum Loot", "VacuumLoot", false),
NF(f_DelayTime, "Delay time (in ms)", "VacuumLoot", 1000),
NF(f_Distance, "Distance", "VacuumLoot", 1.5f),
NF(f_Radius, "Radius", "VacuumLoot", 20.0f),
nextTime(0)
{
InstallFilters();
events::GameUpdateEvent += MY_METHOD_HANDLER(VacuumLoot::OnGameUpdate);
}
const FeatureGUIInfo& VacuumLoot::GetGUIInfo() const
{
static const FeatureGUIInfo info{ "", "World", true };
return info;
}
void VacuumLoot::DrawMain()
{
ConfigWidget("Vacuum Loot", f_Enabled, "Vacuum Loot drops");
}
void VacuumLoot::DrawMain()
{
if (ImGui::BeginGroupPanel("Vacuum Loot", false))
{
ConfigWidget("Enabled", f_Enabled, "Vacuum Loot drops"); ImGui::SameLine(); ImGui::SetNextItemWidth(100.0f);
ConfigWidget("Delay Time (ms)", f_DelayTime, 1, 0, 1000, "Delay (in ms) between loot vacuum.");
ConfigWidget("Radius (m)", f_Radius, 0.1f, 5.0f, 100.0f, "Radius of loot vacuum.");
ConfigWidget("Distance (m)", f_Distance, 0.1f, 1.0f, 10.0f, "Distance between the player and the loot.\n"
"Values under 1.5 may be too intruding.");
if (ImGui::TreeNode(this, "Loot Types"))
{
for (auto& [section, filters] : m_Sections)
{
ImGui::PushID(section.c_str());
DrawSection(section, filters);
ImGui::PopID();
}
ImGui::TreePop();
}
}
ImGui::EndGroupPanel();
}
bool VacuumLoot::NeedStatusDraw() const
{
@ -31,7 +55,7 @@ namespace cheat::feature
void VacuumLoot::DrawStatus()
{
ImGui::Text ("VacuumLoot");
ImGui::Text("VacuumLoot");
}
VacuumLoot& VacuumLoot::GetInstance()
@ -42,62 +66,151 @@ namespace cheat::feature
bool VacuumLoot::IsEntityForVac(game::Entity* entity)
{
// Go through all sections. For each section, go through all filters.
// If a filter matches the given entity and that filter is enabled, return true.
bool entityValid = std::any_of(m_Sections.begin(), m_Sections.end(),
[entity](std::pair<std::string, Filters> const& section) {
return std::any_of(section.second.begin(), section.second.end(), [entity](const FilterInfo& filterInfo) {
return filterInfo.second->IsValid(entity) && filterInfo.first; });
});
if (!entityValid)return false;
auto& manager = game::EntityManager::instance();
auto distance = manager.avatar()->distance(entity);
float radius = 100.0f;
// TODO: Add more on the filter list in the future
static std::vector<std::string> dropList
{
"SceneObj_DropItem",
"SceneObj_Ore_Drop",
"_DropMagicCrystal",
"_Thundercrystaldrop",
"_Ore_ElectricRock",
"_DropMoonMeteor_",
"_DropMagicCrystal",
"_Potato",
"_Radish02_Clear",
"_Cabbage",
"_Carrot02_Clear",
"_Wheat",
"Wisp",
"Meat",
"Fishmeat",
"Equip_Sword",
"Equip_Pole",
"Equip_Bow",
"Equip_Catalyst",
"Equip_Claymore",
"Eff_Animal"
};
for (auto& dropListNames : dropList)
if (entity->name().find(dropListNames) != std::string::npos)
return distance <= radius;
return false;
return distance <= f_Radius;
}
void VacuumLoot::OnGameUpdate()
{
if (!f_Enabled)
return;
void VacuumLoot::OnGameUpdate()
{
if (!f_Enabled)
return;
auto currentTime = util::GetCurrentTimeMillisec();
if (currentTime < nextTime)
return;
auto& manager = game::EntityManager::instance();
auto& manager = game::EntityManager::instance();
auto avatarEntity = manager.avatar();
for (const auto& entity : manager.entities())
{
if (!IsEntityForVac(entity))
continue;
entity->setRelativePosition(avatarEntity->relativePosition());
}
nextTime = currentTime + 1000;
}
for (const auto& entity : manager.entities())
{
if (!IsEntityForVac(entity))
continue;
entity->setRelativePosition(avatarEntity->relativePosition() + avatarEntity->forward() * f_Distance);
}
nextTime = currentTime + f_DelayTime.value();
}
void VacuumLoot::DrawSection(const std::string& section, const Filters& filters)
{
bool checked = std::all_of(filters.begin(), filters.end(), [](const FilterInfo& filter) { return filter.first; });
bool changed = false;
if (ImGui::BeginSelectableGroupPanel(section.c_str(), checked, changed, true))
{
// TODO : Get Max Container Width and Calculate Max Item Width of Checkbox + Text / or specify same width for all columns
// then divide MaxWidth by ItemWidth/ColumnWidth and asign a floor result >= 1 to columns.
// Though this is also just fine IMO.
int columns = 3;
if (ImGui::BeginTable(section.c_str(), columns == 0 ? 1 : columns )) {
int i = 0;
for (std::pair<config::Field<bool>, game::IEntityFilter*> filter : filters) {
if (i % (columns == 0 ? 1 : columns) == 0)
{
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
}
else
ImGui::TableNextColumn();
ImGui::PushID(&filter);
ConfigWidget(filter.first);
ImGui::PopID();
i++;
}
ImGui::EndTable();
}
}
ImGui::EndSelectableGroupPanel();
if (changed)
{
for (const auto& info : filters)
{
info.first.value() = checked;
info.first.FireChanged();
}
}
}
void VacuumLoot::AddFilter(const std::string& section, const std::string& name, game::IEntityFilter* filter)
{
if (m_Sections.count(section) == 0)
m_Sections[section] = {};
auto& filters = m_Sections[section];
bool newItem(filter);
filters.push_back({ config::CreateField<bool>(name,name,fmt::format("VacuumLoot::Filters::{}", section),false, newItem) , filter });
}
#define ADD_FILTER_FIELD(section, name) AddFilter(util::MakeCapital(#section), util::SplitWords(#name), &game::filters::##section##::##name##)
void VacuumLoot::InstallFilters()
{
// Add more in the future
ADD_FILTER_FIELD(featured, ItemDrops);
// ADD_FILTER_FIELD(mineral, AmethystLump);
// ADD_FILTER_FIELD(mineral, ArchaicStone);
// ADD_FILTER_FIELD(mineral, CorLapis);
// ADD_FILTER_FIELD(mineral, CrystalChunk);
// ADD_FILTER_FIELD(mineral, CrystalMarrow);
// ADD_FILTER_FIELD(mineral, ElectroCrystal);
// ADD_FILTER_FIELD(mineral, IronChunk);
// ADD_FILTER_FIELD(mineral, NoctilucousJade);
// ADD_FILTER_FIELD(mineral, MagicalCrystalChunk);
// ADD_FILTER_FIELD(mineral, ScarletQuartz);
// ADD_FILTER_FIELD(mineral, Starsilver);
// ADD_FILTER_FIELD(mineral, WhiteIronChunk);
// ADD_FILTER_FIELD(mineral, DunlinsTooth);
// Ores that drops as a loot when destroyed
ADD_FILTER_FIELD(mineral, AmethystLumpDrop);
ADD_FILTER_FIELD(mineral, CrystalChunkDrop);
ADD_FILTER_FIELD(mineral, ElectroCrystalDrop);
ADD_FILTER_FIELD(mineral, IronChunkDrop);
ADD_FILTER_FIELD(mineral, NoctilucousJadeDrop);
ADD_FILTER_FIELD(mineral, MagicalCrystalChunkDrop);
ADD_FILTER_FIELD(mineral, ScarletQuartzDrop);
ADD_FILTER_FIELD(mineral, StarsilverDrop);
ADD_FILTER_FIELD(mineral, WhiteIronChunkDrop);
ADD_FILTER_FIELD(plant, Apple);
ADD_FILTER_FIELD(plant, Cabbage);
ADD_FILTER_FIELD(plant, Carrot);
ADD_FILTER_FIELD(plant, Potato);
ADD_FILTER_FIELD(plant, Radish);
ADD_FILTER_FIELD(plant, Sunsettia);
ADD_FILTER_FIELD(plant, Wheat);
ADD_FILTER_FIELD(living, CrystalCore);
ADD_FILTER_FIELD(living, Meat);
ADD_FILTER_FIELD(living, Crab);
ADD_FILTER_FIELD(living, Eel);
ADD_FILTER_FIELD(living, LizardTail);
ADD_FILTER_FIELD(equipment, Artifacts);
ADD_FILTER_FIELD(equipment, Bow);
ADD_FILTER_FIELD(equipment, Catalyst);
ADD_FILTER_FIELD(equipment, Claymore);
ADD_FILTER_FIELD(equipment, Sword);
ADD_FILTER_FIELD(equipment, Pole);
}
#undef ADD_FILTER_FIELD
}

View File

@ -5,14 +5,17 @@
#include <cheat/game/Entity.h>
#include <cheat/game/filters.h>
#include <il2cpp-appdata.h>
#include <cheat-base/thread-safe.h>
namespace cheat::feature
{
class VacuumLoot : public Feature
{
public:
config::Field<config::Toggle<Hotkey>> f_Enabled;
config::Field<float> f_Distance;
config::Field<float> f_Radius;
config::Field<int> f_DelayTime;
static VacuumLoot& GetInstance();
@ -23,11 +26,19 @@ namespace cheat::feature
void DrawStatus() override;
void OnGameUpdate();
private:
std::vector<game::IEntityFilter*> m_Filters;
private:
using FilterInfo = std::pair<config::Field<bool>, game::IEntityFilter*>;
using Filters = std::vector<FilterInfo>;
using Sections = std::map<std::string, Filters>;
Sections m_Sections;
SafeValue<int64_t> nextTime;
VacuumLoot();
int nextTime{};
void DrawSection(const std::string& section, const Filters& filters);
void InstallFilters();
void AddFilter(const std::string& section, const std::string& name, game::IEntityFilter* filter);
bool IsEntityForVac(cheat::game::Entity* entity);
};
}