Skip to content
This repository was archived by the owner on Jun 18, 2024. It is now read-only.

Commit a04ad45

Browse files
committed
add show hitbox
1 parent 8f962d4 commit a04ad45

File tree

8 files changed

+289
-10
lines changed

8 files changed

+289
-10
lines changed

mod.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"gd": {
44
"win": "2.204"
55
},
6-
"version": "v2.4.6",
6+
"version": "v2.4.7",
77
"id": "maxnu.gd_mega_overlay",
88
"name": "GD Mega Overlay",
99
"developer": "maxnu & SpaghettDev",

src/Common.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ void Common::updateCheating()
190190
isCheating = true;
191191
return;
192192
}
193-
else if((levelID > 97454394 || levelID == 0 || pl->m_level->m_timestamp > 0) && tps > 240)
193+
else if((levelID > 97454394 || levelID == 0) && tps > 240)
194194
{
195195
isCheating = true;
196196
return;

src/GUI/Window.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,6 @@ void Window::draw()
7272
if (GUI::isVisible && visibleInScreen() || !GUI::isVisible)
7373
windowFunction();
7474

75-
if (GUI::isVisible)
75+
if (GUI::isVisible && visibleInScreen())
7676
ImGui::End();
7777
}

src/Hacks/PhysicsBypass.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,14 @@ void PhysicsBypass::calculateTickrate()
2929

3030
if(Macrobot::playerMode == Macrobot::PLAYBACK)
3131
tps = Macrobot::macro.framerate;
32-
33-
if(tps == 240.f)
34-
return;
3532

36-
if(tps < 1.f)
33+
if(tps < 1.f)
3734
tps = 1.f;
3835

39-
util::Write<float>(base::get() + 0x49D548, 1.f / tps);
36+
util::Write<float>(base::get() + 0x49D548, 1.f / tps);
37+
38+
if(tps == 240.f)
39+
return;
4040

4141
if(GameManager::get()->getPlayLayer() && GameManager::get()->getPlayLayer()->m_level->m_timestamp > 0)
4242
{

src/Hacks/ShowHitboxes.cpp

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
#include "ShowHitboxes.h"
2+
#include "Common.h"
3+
#include "Settings.hpp"
4+
5+
#include <Geode/modify/CCDrawNode.hpp>
6+
#include <Geode/modify/LevelEditorLayer.hpp>
7+
#include <Geode/modify/PlayLayer.hpp>
8+
9+
using namespace ShowHitboxes;
10+
11+
CCDrawNode* ShowHitboxes::getDrawNode()
12+
{
13+
return MBO(CCDrawNode*, GameManager::get()->getGameLayer(), 11632);
14+
}
15+
16+
CCRect ShowHitboxes::getObjectRect(cocos2d::CCRect r, float a, float b)
17+
{
18+
r.origin.x += r.size.width / 2;
19+
r.origin.y += r.size.height / 2;
20+
r.size.width *= a;
21+
r.size.height *= b;
22+
r.origin.x -= r.size.width / 2;
23+
r.origin.y -= r.size.height / 2;
24+
return r;
25+
}
26+
27+
void ShowHitboxes::drawRectangleHitbox(CCDrawNode* node, cocos2d::CCRect const& rect, ccColor4B colBase)
28+
{
29+
constexpr size_t N = 4;
30+
std::vector<cocos2d::CCPoint> points(N);
31+
32+
points[0] = CCPointMake(rect.getMinX(), rect.getMinY());
33+
points[1] = CCPointMake(rect.getMinX(), rect.getMaxY());
34+
points[2] = CCPointMake(rect.getMaxX(), rect.getMaxY());
35+
points[3] = CCPointMake(rect.getMaxX(), rect.getMinY());
36+
37+
node->drawPolygon(const_cast<cocos2d::CCPoint*>(points.data()), points.size(), ccc4FFromccc4B(colBase),
38+
0.25, ccc4FFromccc4B(colBase));
39+
}
40+
41+
void ShowHitboxes::drawForPlayer(CCDrawNode* node, PlayerObject* player)
42+
{
43+
if(!player)
44+
return;
45+
46+
CCRect* rect1 = reinterpret_cast<CCRect*(__thiscall*)(GameObject*)>(base::get() + 0x13a570)(player);
47+
CCRect rect2 = player->m_vehicleSize >= 1.f ? getObjectRect(*rect1, 0.25f, 0.25f) : getObjectRect(*rect1, 0.4f, 0.4f);
48+
drawRectangleHitbox(node, *rect1, ccColor4B(255, 0, 0, 255));
49+
drawRectangleHitbox(node, rect2, ccColor4B(0, 255, 0, 255));
50+
}
51+
52+
void ShowHitboxes::forceDraw(GJBaseGameLayer* self, bool editor)
53+
{
54+
bool show = Settings::get<bool>("level/show_hitbox/enabled", false);
55+
getDrawNode()->setVisible(show);
56+
57+
GameManager::get()->setGameVariable("0045", show);
58+
59+
if(!show)
60+
return;
61+
62+
bool onDeath = Settings::get<bool>("level/show_hitbox/on_death", false);
63+
64+
if(onDeath)
65+
getDrawNode()->setVisible(dead);
66+
67+
debugDrawing = true;
68+
reinterpret_cast<void(__thiscall*)(cocos2d::CCLayer*)>(base::get() + (editor ? 0x248420 : 0x1986f0))(
69+
self);
70+
71+
bool isDual = MBO(bool, self, 878);
72+
bool trail = Settings::get<bool>("level/show_hitbox/queue_enabled", false);
73+
74+
drawForPlayer(getDrawNode(), self->m_player1);
75+
if(isDual)
76+
drawForPlayer(getDrawNode(), self->m_player2);
77+
78+
if(!trail)
79+
{
80+
debugDrawing = false;
81+
return;
82+
}
83+
84+
for(auto&pair : player1Queue)
85+
{
86+
drawRectangleHitbox(getDrawNode(), pair.first, ccColor4B(255, 0, 0, 255));
87+
drawRectangleHitbox(getDrawNode(), pair.second, ccColor4B(0, 255, 0, 255));
88+
}
89+
90+
for(auto&pair : player2Queue)
91+
{
92+
drawRectangleHitbox(getDrawNode(), pair.first, ccColor4B(255, 0, 0, 255));
93+
drawRectangleHitbox(getDrawNode(), pair.second, ccColor4B(0, 255, 0, 255));
94+
}
95+
debugDrawing = false;
96+
}
97+
98+
void LevelEditorLayerUpdateEditor(LevelEditorLayer* self, float dt)
99+
{
100+
reinterpret_cast<void(__thiscall *)(LevelEditorLayer *, float)>(base::get() + 0x23f720)(self, dt);
101+
102+
dead = false;
103+
104+
forceDraw(self, true);
105+
}
106+
107+
void GJBaseGameLayerProcessCommands(GJBaseGameLayer* self)
108+
{
109+
reinterpret_cast<void(__thiscall *)(GJBaseGameLayer *)>(base::get() + 0x1BD240)(self);
110+
111+
bool show = Settings::get<bool>("level/show_hitbox/enabled", false);
112+
bool trail = Settings::get<bool>("level/show_hitbox/queue_enabled", false);
113+
114+
if(!show || !trail)
115+
return;
116+
117+
bool isDual = MBO(bool, self, 878);
118+
119+
CCRect* rect1 = reinterpret_cast<CCRect*(__thiscall*)(GameObject*)>(base::get() + 0x13a570)(self->m_player1);
120+
CCRect rect2 = self->m_player1->m_vehicleSize >= 1.f ? getObjectRect(*rect1, 0.25f, 0.25f) : getObjectRect(*rect1, 0.4f, 0.4f);
121+
122+
player1Queue.push_back({*rect1, rect2});
123+
124+
int maxQueue = Settings::get<int>("level/show_hitbox/max_queue", 240);
125+
126+
if(player1Queue.size() > maxQueue)
127+
player1Queue.pop_front();
128+
129+
if(!isDual)
130+
return;
131+
132+
rect1 = reinterpret_cast<CCRect*(__thiscall*)(GameObject*)>(base::get() + 0x13a570)(self->m_player2);
133+
rect2 = self->m_player2->m_vehicleSize >= 1.f ? getObjectRect(*rect1, 0.25f, 0.25f) : getObjectRect(*rect1, 0.4f, 0.4f);
134+
135+
player2Queue.push_back({*rect1, rect2});
136+
137+
if(player2Queue.size() > maxQueue)
138+
player2Queue.pop_front();
139+
}
140+
141+
$execute
142+
{
143+
Mod::get()->hook(reinterpret_cast<void *>(base::get() + 0x23f720), &LevelEditorLayerUpdateEditor, "LevelEditorLayer::UpdateEditor", tulip::hook::TulipConvention::Thiscall);
144+
Mod::get()->hook(reinterpret_cast<void *>(base::get() + 0x1BD240), &GJBaseGameLayerProcessCommands, "GJBaseGameLayer::processCommands", tulip::hook::TulipConvention::Thiscall);
145+
}
146+
147+
class $modify(CCDrawNode)
148+
{
149+
bool drawPolygon(CCPoint *verts, unsigned int count, const ccColor4F &colFill, float borderWidth, const ccColor4F& colBase)
150+
{
151+
ccColor4F colBaseNew = colBase;
152+
ccColor4F colFillNew = colBase;
153+
154+
if(ShowHitboxes::debugDrawing)
155+
{
156+
borderWidth = Settings::get<float>("level/show_hitbox/size", 0.25f);
157+
colBaseNew.a = Settings::get<int>("level/show_hitbox/border_alpha", 255) / 255.f;
158+
colFillNew.a = Settings::get<int>("level/show_hitbox/fill_alpha", 50) / 255.f;
159+
}
160+
161+
bool res = CCDrawNode::drawPolygon(verts, count, colFillNew, borderWidth, colBaseNew);
162+
163+
return res;
164+
}
165+
};
166+
167+
class $modify(PlayLayer)
168+
{
169+
void postUpdate(float dt)
170+
{
171+
PlayLayer::postUpdate(dt);
172+
173+
forceDraw(this, false);
174+
};
175+
176+
void resetLevel()
177+
{
178+
PlayLayer::resetLevel();
179+
player1Queue.clear();
180+
player2Queue.clear();
181+
182+
dead = false;
183+
}
184+
185+
void fullReset()
186+
{
187+
PlayLayer::fullReset();
188+
189+
dead = false;
190+
}
191+
192+
void destroyPlayer(PlayerObject* p0, GameObject* p1)
193+
{
194+
PlayLayer::destroyPlayer(p0, p1);
195+
196+
if(p1 && p1->getPositionX() == 0 && p1->getPositionY() == 105)
197+
return;
198+
199+
dead = true;
200+
}
201+
};
202+
203+
class $modify(LevelEditorLayer)
204+
{
205+
void onPlaytest()
206+
{
207+
LevelEditorLayer::onPlaytest();
208+
209+
player1Queue.clear();
210+
player2Queue.clear();
211+
}
212+
};
213+
214+
class $modify(GJBaseGameLayer)
215+
{
216+
bool init()
217+
{
218+
dead = false;
219+
return GJBaseGameLayer::init();
220+
}
221+
};

src/Hacks/ShowHitboxes.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#pragma once
2+
3+
#include <Geode/Geode.hpp>
4+
#include <Geode/modify/GJBaseGameLayer.hpp>
5+
6+
#include <deque>
7+
8+
using namespace geode::prelude;
9+
10+
namespace ShowHitboxes
11+
{
12+
inline bool debugDrawing = false;
13+
inline bool dead = false;
14+
inline std::deque<std::pair<CCRect, CCRect>> player1Queue;
15+
inline std::deque<std::pair<CCRect, CCRect>> player2Queue;
16+
17+
CCDrawNode* getDrawNode();
18+
CCRect getObjectRect(cocos2d::CCRect r, float a, float b);
19+
20+
void drawForPlayer(CCDrawNode* node, PlayerObject* player);
21+
void drawRectangleHitbox(CCDrawNode* node, cocos2d::CCRect const& rect, ccColor4B col);
22+
void forceDraw(GJBaseGameLayer* self, bool editor);
23+
}

src/Macrobot/Record.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,9 @@ void Record::renderWindow()
381381
Record::recorder.start();
382382
}
383383

384+
if(GUI::shouldRender() && disabled && ImGui::IsItemHovered())
385+
ImGui::SetTooltip("You need to be playing a macro to record");
386+
384387
if (GUI::button("Stop Recording") && Record::recorder.m_recording)
385388
Record::recorder.stop();
386389

@@ -416,6 +419,9 @@ void Record::renderWindow()
416419
}
417420
}
418421

422+
if(GUI::shouldRender() && disabled && ImGui::IsItemHovered())
423+
ImGui::SetTooltip("You need to be playing a macro to record");
424+
419425
if (GUI::button("Stop Audio") && Record::recorder.m_recording_audio)
420426
{
421427
recorder.m_recording_audio = false;
@@ -479,6 +485,6 @@ void Record::renderWindow()
479485

480486
GUI::marker("[INFO]",
481487
"Press start recording to get a smooth recording of the level. "
482-
"To render music and sfx, press Start Music and wait for the level to finish again, then your "
483-
"rendered video will have music and sfx.");
488+
"To render music, clicks and sfx, press Start Music and wait for the level to finish again, then your "
489+
"rendered video will have music, clicks and sfx.");
484490
}

src/main.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ void init()
5151

5252
void initGUI()
5353
{
54+
ImGui::GetCurrentContext()->PlatformLocaleDecimalPoint = *localeconv()->decimal_point;
5455
GUI::windows.clear();
5556

5657
GUI::Window generalWindow("General", [] {
@@ -195,6 +196,34 @@ void initGUI()
195196
Mod::get()->setSavedValue<int>("level/startpos_switcher/right", key);
196197
},
197198
ImGuiWindowFlags_AlwaysAutoResize);
199+
200+
GUI::checkbox("Show Hitboxes", "level/show_hitbox/enabled");
201+
GUI::arrowButton("Show Hitboxes Settings");
202+
GUI::modalPopup(
203+
"Show Hitboxes Settings",
204+
[] {
205+
float borderSize = Settings::get<float>("level/show_hitbox/size", 0.25f);
206+
int borderAlpha = Settings::get<int>("level/show_hitbox/border_alpha", 255);
207+
int fillAlpha = Settings::get<int>("level/show_hitbox/fill_alpha", 50);
208+
209+
int maxQueue = Settings::get<int>("level/show_hitbox/max_queue", 240);
210+
211+
GUI::checkbox("Show Trail", "level/show_hitbox/queue_enabled");
212+
GUI::checkbox("Only On Death", "level/show_hitbox/on_death");
213+
214+
if (GUI::inputFloat("Border Size", &borderSize, 0.f, 3.f))
215+
Mod::get()->setSavedValue<float>("level/show_hitbox/size", borderSize);
216+
217+
if (GUI::inputInt("Border Opacity", &borderAlpha, 1, 255))
218+
Mod::get()->setSavedValue<int>("level/show_hitbox/border_alpha", borderAlpha);
219+
220+
if (GUI::inputInt("Fill Opacity", &fillAlpha, 1, 255))
221+
Mod::get()->setSavedValue<int>("level/show_hitbox/fill_alpha", fillAlpha);
222+
223+
if (GUI::inputInt("Max Queue Length", &maxQueue, 1, 99999999))
224+
Mod::get()->setSavedValue<int>("level/show_hitbox/max_queue", maxQueue);
225+
},
226+
ImGuiWindowFlags_AlwaysAutoResize);
198227

199228
GUI::checkbox("Auto Deafen", "level/auto_deafen/enabled");
200229

0 commit comments

Comments
 (0)