Skip to content

Commit d869b6d

Browse files
committed
Cleaned up logic and UI placement as per feedback.
Reorganized into a dedicated category under the Self menu (not a separate submenu). Some Error handling and more fixes .
1 parent 629572c commit d869b6d

File tree

3 files changed

+198
-0
lines changed

3 files changed

+198
-0
lines changed
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
#include "OutfitEditor.hpp"
2+
3+
#include "core/frontend/manager/UIManager.hpp"
4+
#include "game/backend/Self.hpp"
5+
#include "game/frontend/items/Items.hpp"
6+
#include "game/gta/Natives.hpp"
7+
#include "imgui.h"
8+
9+
namespace YimMenu::Submenus
10+
{
11+
std::shared_ptr<YimMenu::Category> OutfitEditor::CreateCategory()
12+
{
13+
auto category = std::make_shared<YimMenu::Category>("Edit Outfits and Props");
14+
15+
category->AddItem(std::make_shared<ImGuiItem>([] {
16+
auto ped = Self::GetPed();
17+
if (!ENTITY::DOES_ENTITY_EXIST(static_cast<int>(ped.GetHandle())))
18+
{
19+
ImGui::TextDisabled("Error: Player not found");
20+
return;
21+
}
22+
23+
// Outfit Slots
24+
static const char* outfitSlotNames[] = {"Head", "Masks", "Hair", "Torso", "Legs", "Bags/Parachutes", "Shoes", "Accessories", "Undershirts", "Body Armor", "Decals", "Tops 2"};
25+
26+
for (int i = 0; i < 12; ++i)
27+
{
28+
int drawable, texture;
29+
OutfitEditor::GetOutfitSlot(i, drawable, texture);
30+
31+
const int maxDrawable = OutfitEditor::GetMaxDrawable(i);
32+
if (maxDrawable <= 0)
33+
{
34+
ImGui::TextDisabled("%s (Slot %d): No options available", outfitSlotNames[i], i);
35+
continue;
36+
}
37+
38+
int maxTexture = OutfitEditor::GetMaxTexture(i, drawable);
39+
40+
ImGui::Text("%s (Slot %d)", outfitSlotNames[i], i);
41+
if (ImGui::SliderInt(std::format("{} Drawable##{}", outfitSlotNames[i], i).c_str(), &drawable, 0, maxDrawable - 1))
42+
{
43+
drawable = std::clamp(drawable, 0, maxDrawable - 1);
44+
OutfitEditor::SetOutfitSlot(i, drawable, texture);
45+
maxTexture = OutfitEditor::GetMaxTexture(i, drawable);
46+
}
47+
if (maxTexture > 0 && ImGui::SliderInt(std::format("{} Texture##{}", outfitSlotNames[i], i).c_str(), &texture, 0, maxTexture - 1))
48+
{
49+
texture = std::clamp(texture, 0, maxTexture - 1);
50+
OutfitEditor::SetOutfitSlot(i, drawable, texture);
51+
}
52+
}
53+
54+
// Prop Slots
55+
static const char* propNames[] = {"Hat", "Glasses", "Earrings", nullptr, nullptr, nullptr, "Watches", "Bracelets"};
56+
57+
for (int i : {0, 1, 2, 6, 7})
58+
{
59+
int drawable, texture;
60+
OutfitEditor::GetPropSlot(i, drawable, texture);
61+
62+
const int maxDrawable = OutfitEditor::GetMaxPropDrawable(i);
63+
if (maxDrawable <= 0)
64+
{
65+
ImGui::TextDisabled("%s (Slot %d): No options available", propNames[i], i);
66+
continue;
67+
}
68+
69+
int maxTexture = OutfitEditor::GetMaxPropTexture(i, drawable);
70+
71+
if (propNames[i]) // Skip nullptr entries
72+
{
73+
ImGui::Text("%s (Slot %d)", propNames[i], i);
74+
if (ImGui::SliderInt(std::format("{} Drawable##{}", propNames[i], i).c_str(), &drawable, 0, maxDrawable - 1))
75+
{
76+
drawable = std::clamp(drawable, 0, maxDrawable - 1);
77+
OutfitEditor::SetPropSlot(i, drawable, texture);
78+
maxTexture = OutfitEditor::GetMaxPropTexture(i, drawable);
79+
}
80+
if (maxTexture > 0 && ImGui::SliderInt(std::format("{} Texture##{}", propNames[i], i).c_str(), &texture, 0, maxTexture - 1))
81+
{
82+
texture = std::clamp(texture, 0, maxTexture - 1);
83+
OutfitEditor::SetPropSlot(i, drawable, texture);
84+
}
85+
}
86+
}
87+
}));
88+
89+
return category;
90+
}
91+
92+
void OutfitEditor::SetOutfitSlot(int slot, int drawable, int texture)
93+
{
94+
auto ped = Self::GetPed();
95+
if (!ENTITY::DOES_ENTITY_EXIST(static_cast<int>(ped.GetHandle())))
96+
{
97+
return; // Invalid ped handle
98+
}
99+
100+
int maxDrawable = GetMaxDrawable(slot);
101+
int maxTexture = GetMaxTexture(slot, drawable);
102+
103+
if (drawable < 0 || drawable >= maxDrawable || texture < 0 || texture >= maxTexture)
104+
{
105+
return; // Invalid drawable or texture
106+
}
107+
108+
PED::SET_PED_COMPONENT_VARIATION(static_cast<int>(ped.GetHandle()), slot, drawable, texture, 0);
109+
}
110+
111+
void OutfitEditor::SetPropSlot(int slot, int drawable, int texture)
112+
{
113+
auto ped = Self::GetPed();
114+
if (!ENTITY::DOES_ENTITY_EXIST(static_cast<int>(ped.GetHandle())))
115+
{
116+
return; // Invalid ped handle
117+
}
118+
119+
int maxDrawable = GetMaxPropDrawable(slot);
120+
int maxTexture = GetMaxPropTexture(slot, drawable);
121+
122+
if (drawable < 0 || drawable >= maxDrawable || texture < 0 || texture >= maxTexture)
123+
{
124+
return; // Invalid drawable or texture
125+
}
126+
127+
PED::SET_PED_PROP_INDEX(static_cast<int>(ped.GetHandle()), slot, drawable, texture, true, 0);
128+
}
129+
130+
void OutfitEditor::GetOutfitSlot(int slot, int& drawable, int& texture)
131+
{
132+
auto ped = Self::GetPed();
133+
drawable = PED::GET_PED_DRAWABLE_VARIATION(static_cast<int>(ped.GetHandle()), slot);
134+
texture = PED::GET_PED_TEXTURE_VARIATION(static_cast<int>(ped.GetHandle()), slot);
135+
}
136+
137+
void OutfitEditor::GetPropSlot(int slot, int& drawable, int& texture)
138+
{
139+
auto ped = Self::GetPed();
140+
drawable = PED::GET_PED_PROP_INDEX(static_cast<int>(ped.GetHandle()), slot, 0);
141+
if (drawable == -1)
142+
{
143+
drawable = 0;
144+
texture = 0;
145+
return;
146+
}
147+
texture = PED::GET_PED_PROP_TEXTURE_INDEX(static_cast<int>(ped.GetHandle()), slot);
148+
}
149+
150+
int OutfitEditor::GetMaxDrawable(int slot)
151+
{
152+
auto ped = Self::GetPed();
153+
return PED::GET_NUMBER_OF_PED_DRAWABLE_VARIATIONS(static_cast<int>(ped.GetHandle()), slot);
154+
}
155+
156+
int OutfitEditor::GetMaxTexture(int slot, int drawable)
157+
{
158+
auto ped = Self::GetPed();
159+
return PED::GET_NUMBER_OF_PED_TEXTURE_VARIATIONS(static_cast<int>(ped.GetHandle()), slot, drawable);
160+
}
161+
162+
int OutfitEditor::GetMaxPropDrawable(int slot)
163+
{
164+
auto ped = Self::GetPed();
165+
return PED::GET_NUMBER_OF_PED_PROP_DRAWABLE_VARIATIONS(static_cast<int>(ped.GetHandle()), slot);
166+
}
167+
168+
int OutfitEditor::GetMaxPropTexture(int slot, int drawable)
169+
{
170+
auto ped = Self::GetPed();
171+
return PED::GET_NUMBER_OF_PED_PROP_TEXTURE_VARIATIONS(static_cast<int>(ped.GetHandle()), slot, drawable);
172+
}
173+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#pragma once
2+
#include <memory>
3+
#include "core/frontend/manager/Category.hpp"
4+
5+
namespace YimMenu::Submenus
6+
{
7+
class OutfitEditor
8+
{
9+
public:
10+
static std::shared_ptr<YimMenu::Category> CreateCategory();
11+
12+
static void SetOutfitSlot(int slot, int drawable, int texture);
13+
static void SetPropSlot(int slot, int drawable, int texture);
14+
static void GetOutfitSlot(int slot, int& drawable, int& texture);
15+
static void GetPropSlot(int slot, int& drawable, int& texture);
16+
static int GetMaxDrawable(int slot);
17+
static int GetMaxTexture(int slot, int drawable);
18+
static int GetMaxPropDrawable(int slot);
19+
static int GetMaxPropTexture(int slot, int drawable);
20+
};
21+
}

src/game/frontend/submenus/Self.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "core/util/Joaat.hpp"
44
#include "game/frontend/items/Items.hpp"
5+
#include "OutfitEditor.hpp"
56

67
namespace YimMenu::Submenus
78
{
@@ -84,5 +85,8 @@ namespace YimMenu::Submenus
8485
vehicle->AddItem(vehicleGlobalsGroup);
8586
vehicle->AddItem(vehicleMiscGroup);
8687
AddCategory(std::move(vehicle));
88+
89+
auto outfitEditorCategory = OutfitEditor::CreateCategory();
90+
AddCategory(std::move(outfitEditorCategory));
8791
}
8892
}

0 commit comments

Comments
 (0)