Skip to content

Commit

Permalink
Script Function Return Value and Enhancements (#191)
Browse files Browse the repository at this point in the history
Return value support for script function.
Move herb giver to different group.
Add "Trader Goods" to recovery options.
Add "TP to player's camp" to player options
Improved Moonshine Shack Teleport
  • Loading branch information
tuyilmaz authored Aug 4, 2024
1 parent 28520d9 commit c615522
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 39 deletions.
47 changes: 47 additions & 0 deletions src/game/features/players/teleport/TpToPlayerCamp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "game/backend/Players.hpp"
#include "game/backend/Self.hpp"
#include "game/commands/PlayerCommand.hpp"
#include "game/features/Features.hpp"
#include "game/rdr/Natives.hpp"
#include "game/rdr/ScriptGlobal.hpp"
#include "util/teleport.hpp"

namespace YimMenu::Features
{
class TpToPlayerCamp: public PlayerCommand
{
using PlayerCommand::PlayerCommand;
static constexpr auto PlayerList = ScriptGlobal(1141332);

virtual void OnCall(Player player) override
{
if (!PlayerList.CanAccess())
return;

for (int i = 0; i < 32; i++)
{
if (*PlayerList.At(i, 27).At(9).As<int*>() == player.GetId())
{
auto Camp = ScriptGlobal(1141332).At(i, 27).At(20);

if (!Camp.CanAccess())
return;

Vector3 CampCoords = *Camp.As<Vector3*>();
if (CampCoords != Vector3(0.f, 0.f, 0.f))
{
if(YimMenu::Teleport::TeleportEntity(Self::GetPed().GetHandle(), CampCoords + Vector3(1, 0, 0), true))
g_Spectating = false;
}
else
{
Notifications::Show("Camp", "Unable to find player's camp", NotificationType::Error);
}
break;
}
}
}
};

static TpToPlayerCamp _TpToPlayerCamp{"tptoplayercamp", "Teleport To Player's Camp", "Teleport to the player's camp"};
}
19 changes: 13 additions & 6 deletions src/game/features/self/TpToMoonshineShack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,24 @@ namespace YimMenu::Features
class TpToMoonshineShack : public Command
{
using Command::Command;
static constexpr auto ShackBlip = ScriptGlobal(1297441).At(128);
static constexpr auto MoonshineShack = ScriptGlobal(1297441).At(128).At(1);

virtual void OnCall() override
{
if (ShackBlip.CanAccess())
if (MoonshineShack.CanAccess())
{
Blip Shack = *ShackBlip.As<Blip*>();
if (MAP::DOES_BLIP_EXIST(Shack))
Vector3 ShackCoords;
switch (*MoonshineShack.As<int*>())
{
Vector3 ShackCoords = MAP::GET_BLIP_COORDS(Shack);
YimMenu::Teleport::TeleportEntity(Self::GetPed().GetHandle(), ShackCoords, true);
case 0: ShackCoords = Vector3(1785.3f, -813.4f, 43.f); break;
case 1: ShackCoords = Vector3(-1088.43f, 706.8f, 104.5f); break;
case 2: ShackCoords = Vector3(-2777.04, -3051.f, 11.581f); break;
case 3: ShackCoords = Vector3(1627.f, 821.f, 145.f); break;
case 4: ShackCoords = Vector3(-1859.7f, -1730.3f, 109.5f); break;
}
if (ShackCoords != Vector3(0.f, 0.f, 0.f))
{
YimMenu::Teleport::TeleportEntity(Self::GetPed().GetHandle(), ShackCoords, false);
}
else
{
Expand Down
1 change: 1 addition & 0 deletions src/game/frontend/submenus/Players.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,7 @@ namespace YimMenu::Submenus
}));

teleportGroup->AddItem(std::make_shared<PlayerCommandItem>("tptoplayer"_J));
teleportGroup->AddItem(std::make_shared<PlayerCommandItem>("tptoplayercamp"_J));
teleportGroup->AddItem(std::make_shared<PlayerCommandItem>("tpbehindplayer"_J));
teleportGroup->AddItem(std::make_shared<PlayerCommandItem>("tpintovehicle"_J));
teleportGroup->AddItem(std::make_shared<PlayerCommandItem>("bring"_J));
Expand Down
44 changes: 41 additions & 3 deletions src/game/frontend/submenus/Recovery.cpp
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
#include "Recovery.hpp"

#include "core/commands/BoolCommand.hpp"
#include "core/commands/Commands.hpp"
#include "game/backend/FiberPool.hpp"
#include "game/frontend/items/Items.hpp"
#include "core/commands/Commands.hpp"
#include "core/commands/BoolCommand.hpp"
#include "game/rdr/ScriptFunction.hpp"
#include "game/rdr/Scripts.hpp"
#include "util/Rewards.hpp"

namespace YimMenu::Submenus
{

Recovery::Recovery() :
Submenu::Submenu("Recovery")
{
auto recovery = std::make_shared<Category>("Recovery");
auto spawnCollectiblesGroup = std::make_shared<Group>("Spawn Collectibles");
auto spawnHerbsGroup = std::make_shared<Group>("Spawn Herbs");
auto recoveryOptions = std::make_shared<Group>("Options");

static auto recoveryCommand = Commands::GetCommand<BoolCommand>("recoveryenabled"_J);
Expand All @@ -35,7 +40,6 @@ namespace YimMenu::Submenus
{Rewards::eRewardType::TAROTCARDS_WANDS, "Tarot Cards - Wands"},
{Rewards::eRewardType::FOSSILS, "Fossils"},
{Rewards::eRewardType::EGGS, "Eggs"},
{Rewards::eRewardType::HERBS, "Herbs"},
{Rewards::eRewardType::TREASURE, "Treasure Reward"},
{Rewards::eRewardType::CAPITALE, "Capitale"},
{Rewards::eRewardType::XP, "25K XP"},
Expand All @@ -44,6 +48,7 @@ namespace YimMenu::Submenus
{Rewards::eRewardType::COLLECTORXP, "200 Collector XP"},
{Rewards::eRewardType::NATURALISTXP, "300 Naturalist XP"},
{Rewards::eRewardType::BOUNTYHUNTERXP, "200 Bounty Hunter XP"},
{Rewards::eRewardType::TRADERGOODS, "Max Trader Goods"},
};

if (ImGui::BeginCombo("Rewards", reward_translations[selected].c_str()))
Expand Down Expand Up @@ -81,9 +86,42 @@ namespace YimMenu::Submenus
}
}
}));
spawnHerbsGroup->AddItem(std::make_shared<ImGuiItem>([=] {
if (recoveryCommand->GetState())
{
static joaat_t selectedHerb;
std::map<joaat_t, std::string> herb_translations = {{"HERB_LOOT_ALASKAN_GINSENG"_J, "Alaskan Ginseng"},{"HERB_LOOT_AMERICAN_GINSENG"_J, "American Ginseng"},{"HERB_LOOT_BAY_BOLETE"_J, "Bay Bolete"},{"HERB_LOOT_BLACK_BERRY"_J, "Black Berry"},{"HERB_LOOT_BLACK_CURRANT"_J, "Black Currant"},{"HERB_LOOT_BURDOCK_ROOT"_J, "Burdock Root"},{"HERB_LOOT_CHANTERELLES"_J, "Chanterelles"},{"HERB_LOOT_COMMON_BULRUSH"_J, "Common Bulrush"},{"HERB_LOOT_CREEPING_THYME"_J, "Creeping Thyme"},{"HERB_LOOT_DESERT_SAGE"_J, "Desert Sage"},{"HERB_LOOT_ENGLISH_MACE"_J, "English Mace"},{"HERB_LOOT_EVERGREEN_HUCKLEBERRY"_J, "Evergreen Huckleberry"},{"HERB_LOOT_GOLDEN_CURRANT"_J, "Golden Currant"},{"HERB_LOOT_HUMMINGBIRD_SAGE"_J, "Hummingbird Sage"},{"HERB_LOOT_INDIAN_TOBACCO"_J, "Indian Tobacco"},{"HERB_LOOT_MILKWEED"_J, "Milkweed"},{"HERB_LOOT_OLEANDER_SAGE"_J, "Oleander Sage"},{"HERB_LOOT_OREGANO"_J, "Oregano"},{"HERB_LOOT_PARASOL_MUSHROOM"_J, "Parasol Mushroom"},{"HERB_LOOT_PRAIRIE_POPPY"_J, "Prairie Poppy"},{"HERB_LOOT_RAMS_HEAD"_J, "Rams Head"},{"HERB_LOOT_RED_RASPBERRY"_J, "Red Raspberry"},{"HERB_LOOT_RED_SAGE"_J, "Red Sage"},{"HERB_LOOT_VANILLA_FLOWER"_J, "Vanilla Flower"},{"HERB_LOOT_VIOLET_SNOWDROP"_J, "Violet Snowdrop"},{"HERB_LOOT_WILD_CARROTS"_J, "Wild Carrots"},{"HERB_LOOT_WILD_FEVERFEW"_J, "Wild Feverfew"},{"HERB_LOOT_WILD_MINT"_J, "Wild Mint"},{"HERB_LOOT_WINTERGREEN_BERRY"_J, "Wintergreen Berry"},{"HERB_LOOT_YARROW"_J, "Yarrow"},{"HERB_LOOT_AGARITA"_J, "Agarita"},{"HERB_LOOT_BITTERWEED"_J, "Bitterweed"},{"HERB_LOOT_BLUE_BONNET"_J, "Blue Bonnet"},{"HERB_LOOT_BLOOD_FLOWER"_J, "Blood Flower"},{"HERB_LOOT_CARDINAL_FLOWER"_J, "Cardinal Flower"},{"HERB_LOOT_CHOCOLATE_DAISY"_J, "Chocolate Daisy"},{"HERB_LOOT_CREEK_PLUM"_J, "Creek Plum"},{"HERB_LOOT_RHUBARB"_J, "Rhubarb"},{"HERB_LOOT_WISTERIA"_J, "Wisteria"},{"HERB_LOOT_HARRIETUM"_J, "Harrietum"},};
if (ImGui::BeginCombo("Herbs", herb_translations[selectedHerb].c_str()))
{
for (auto& [herb, translation] : herb_translations)
{
if (ImGui::Selectable(std::string(translation).c_str(), herb == selectedHerb))
{
selectedHerb = herb;
}
}
ImGui::EndCombo();
}

static int amount = 1;
ImGui::SliderInt("Amount", &amount, 1, 10);

if (ImGui::Button("Give Selected"))
{
FiberPool::Push([] {
if (!Scripts::RequestScript("interactive_campfire"_J))
return;

for (int i = 0; i < amount; i++)
ScriptFunctions::GiveLootTableAward.StaticCall(selectedHerb, 0);
});
}
}
}));
recoveryOptions->AddItem(std::make_shared<BoolCommandItem>("unlimiteditems"_J));
recoveryOptions->AddItem(std::make_shared<BoolCommandItem>("fastmoonshine"_J));
recovery->AddItem(spawnCollectiblesGroup);
recovery->AddItem(spawnHerbsGroup);
recovery->AddItem(recoveryOptions);

AddCategory(std::move(recovery));
Expand Down
14 changes: 9 additions & 5 deletions src/game/rdr/ScriptFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,15 @@ namespace YimMenu
{
}

void ScriptFunction::RunScript(rage::scrThread* thread, rage::scrProgram* program, const std::vector<uint64_t>& args)
void ScriptFunction::RunScript(rage::scrThread* thread, rage::scrProgram* program, const std::vector<uint64_t>& args, void* returnValue, uint32_t returnSize)
{
const auto globals_initialized = std::vector<std::uint8_t>(50, true); // std::vector<bool> does weird stuff so we aren't using that

auto old_thread = *Pointers.CurrentScriptThread;
auto old_thread_running = rage::tlsContext::Get()->m_RunningScript;
auto stack = reinterpret_cast<uint64_t*>(thread->m_Stack);
auto context = thread->m_Context;
auto top = context.m_StackPointer;

for (auto& arg : args)
stack[context.m_StackPointer++] = arg;
Expand All @@ -85,9 +86,12 @@ namespace YimMenu

rage::tlsContext::Get()->m_RunningScript = old_thread_running;
*Pointers.CurrentScriptThread = old_thread;

if (returnValue)
memcpy(returnValue, stack + top, returnSize);
}

void ScriptFunction::StaticCall(const std::vector<uint64_t>& args)
void ScriptFunction::StaticCallImpl(const std::vector<uint64_t>& args, void* returnValue, uint32_t returnSize)
{
auto pc = GetPC();
auto program = Scripts::FindScriptProgram(m_Hash);
Expand All @@ -103,13 +107,13 @@ namespace YimMenu
thread->m_Context.m_StackSize = 25000;
thread->m_Context.m_StackPointer = 1;

RunScript(thread, program, args);
RunScript(thread, program, args, returnValue, returnSize);

delete[] stack;
delete[] (uint8_t*)thread;
}

void ScriptFunction::Call(const std::vector<uint64_t>& args)
void ScriptFunction::CallImpl(const std::vector<uint64_t>& args, void* returnValue, uint32_t returnSize)
{
auto pc = GetPC();
auto thread = Scripts::FindScriptThread(m_Hash);
Expand All @@ -118,6 +122,6 @@ namespace YimMenu
if (!pc || !thread || !program)
return;

RunScript(thread, program, args);
RunScript(thread, program, args, returnValue, returnSize);
}
}
44 changes: 36 additions & 8 deletions src/game/rdr/ScriptFunction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#include "core/memory/Pattern.hpp"
#include "util/Joaat.hpp"

#include <type_traits>

namespace rage
{
class scrThread;
Expand All @@ -19,30 +21,56 @@ namespace YimMenu

std::optional<std::int32_t> GetPC();

void RunScript(rage::scrThread* thread, rage::scrProgram* program, const std::vector<uint64_t>& args);
void RunScript(rage::scrThread* thread, rage::scrProgram* program, const std::vector<uint64_t>& args, void* returnValue, uint32_t returnSize);

void Call(const std::vector<uint64_t>& args);
void CallImpl(const std::vector<uint64_t>& args, void* returnValue = 0, uint32_t returnSize = 0);

void StaticCall(const std::vector<uint64_t>& args);
void StaticCallImpl(const std::vector<uint64_t>& args, void* returnValue = 0, uint32_t returnSize = 0);
public:
ScriptFunction(joaat_t hash, SimplePattern pattern);

// TODO: return value support
template<typename Ret = void, typename... Args>
Ret StaticCall(Args... args)
{
std::vector<uint64_t> params;
(params.push_back(static_cast<std::uint64_t>(args)), ...);

if constexpr (!std::is_same_v<Ret, void>)
{
Ret returnValue;
StaticCallImpl(params, &returnValue, sizeof(returnValue));
return returnValue;
}
else
{
StaticCallImpl(params);
}
}

template<typename... Args>
void StaticCall(Args... args)
template<typename Ret = void, typename... Args>
Ret Call(Args... args)
{
std::vector<uint64_t> params;
(params.push_back(static_cast<std::uint64_t>(args)), ...);
StaticCall(params);

if constexpr (!std::is_same_v<Ret, void>)
{
Ret returnValue;
CallImpl(params, &returnValue, sizeof(returnValue));
return returnValue;
}
else
{
CallImpl(params);
}
}

template<typename... Args>
void operator()(Args... args)
{
std::vector<uint64_t> params;
(params.push_back(static_cast<std::uint64_t>(args)), ...);
Call(params);
CallImpl(params);
}
};

Expand Down
16 changes: 16 additions & 0 deletions src/game/rdr/Scripts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <script/scriptHandlerNetComponent.hpp>
#include <network/CNetworkPlayerMgr.hpp>
#include <rage/tlsContext.hpp>
#include "game/backend/ScriptMgr.hpp"
#include "game/pointers/Pointers.hpp"
#include "game/rdr/Natives.hpp"
#include "game/rdr/data/ScriptNames.hpp"
Expand Down Expand Up @@ -84,4 +85,19 @@ namespace YimMenu::Scripts
auto handler = reinterpret_cast<rage::scriptHandlerNetComponent*>(thread->m_HandlerNetComponent);
handler->DoHostMigration(Pointers.NetworkPlayerMgr->m_LocalPlayer, 0xFFFF, true);
}

bool RequestScript(joaat_t script)
{
if (!SCRIPTS::HAS_SCRIPT_WITH_NAME_HASH_LOADED(script))
{
SCRIPTS::REQUEST_SCRIPT_WITH_NAME_HASH(script);
for (int i = 0; i < 150 && !SCRIPTS::HAS_SCRIPT_WITH_NAME_HASH_LOADED(script); i++)
ScriptMgr::Yield(10ms);
}

if (SCRIPTS::HAS_SCRIPT_WITH_NAME_HASH_LOADED(script))
return true;

return false;
}
}
1 change: 1 addition & 0 deletions src/game/rdr/Scripts.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ namespace YimMenu::Scripts
extern void SendScriptEvent(uint64_t* data, int count, int metadataIndex, int bits);
extern const char* GetScriptName(joaat_t hash);
extern void ForceScriptHost(rage::scrThread* thread);
extern bool RequestScript(joaat_t script);
}
23 changes: 9 additions & 14 deletions src/util/Rewards.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#include "Rewards.hpp"
#include "game/backend/ScriptMgr.hpp"
#include "game/pointers/Pointers.hpp"
#include "game/rdr/Natives.hpp"
#include "game/rdr/ScriptFunction.hpp"
#include "game/rdr/Scripts.hpp"
#include <event/CEventGroup.hpp>
#include <event/CEventInventoryItemPickedUp.hpp>

Expand All @@ -17,12 +16,8 @@ namespace YimMenu::Rewards

void GiveScriptReward(const RewardInfo& info, bool loottable)
{
if (!SCRIPTS::HAS_SCRIPT_WITH_NAME_HASH_LOADED("interactive_campfire"_J))
{
SCRIPTS::REQUEST_SCRIPT_WITH_NAME_HASH("interactive_campfire"_J);
for (int i = 0; i < 150 && !SCRIPTS::HAS_SCRIPT_WITH_NAME_HASH_LOADED("interactive_campfire"_J); i++)
ScriptMgr::Yield(10ms);
}
if (!Scripts::RequestScript("interactive_campfire"_J))
return;

if (loottable)
ScriptFunctions::GiveLootTableAward.StaticCall(info.reward_hash, 0);
Expand Down Expand Up @@ -127,12 +122,6 @@ namespace YimMenu::Rewards
GiveScriptReward(egg);
}
break;
case eRewardType::HERBS:
for (const auto& herb : Herbs)
{
GiveScriptReward(herb);
}
break;
case eRewardType::TREASURE:
for (const auto& treasure : TreasureReward)
{
Expand Down Expand Up @@ -181,6 +170,12 @@ namespace YimMenu::Rewards
GiveScriptReward(xp, false);
}
break;
case eRewardType::TRADERGOODS:
for (const auto& good : TraderGoods)
{
GiveScriptReward(good, false);
}
break;
}
}
};
Expand Down
Loading

0 comments on commit c615522

Please sign in to comment.