Skip to content

Commit 68e9f52

Browse files
committed
i hate cocos2d::BorderAlignment
1 parent 7d22883 commit 68e9f52

File tree

3 files changed

+321
-7
lines changed

3 files changed

+321
-7
lines changed
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
#include "HitboxNode.hpp"
2+
#include "HitboxColours.hpp"
3+
4+
using namespace geode::prelude;
5+
6+
bool HitboxNode::init()
7+
{
8+
if (!CCDrawNode::init())
9+
return false;
10+
11+
return true;
12+
}
13+
14+
void HitboxNode::updateNode()
15+
{
16+
this->clear();
17+
18+
if (auto gjbgl = GJBaseGameLayer::get())
19+
{
20+
forEachObject(gjbgl, [this](GameObject* obj)
21+
{
22+
if (shouldObjectDraw(obj))
23+
drawObjectHitbox(obj);
24+
});
25+
}
26+
}
27+
28+
HitboxColourType HitboxNode::getObjectColour(GameObject* obj)
29+
{
30+
if (objTypeMatchesAny(obj, { GameObjectType::Hazard, GameObjectType::AnimatedHazard }))
31+
return HitboxColourType::Hazard;
32+
33+
if (objTypeMatchesAny(obj, { GameObjectType::Solid, GameObjectType::Slope }))
34+
return HitboxColourType::Solid;
35+
36+
if (objTypeMatchesAny(obj, { GameObjectType::Breakable }) || obj->m_isPassable)
37+
return HitboxColourType::Passable;
38+
39+
if (objTypeMatchesAny(obj, { GameObjectType::UserCoin, GameObjectType::Collectible, GameObjectType::SecretCoin }))
40+
return HitboxColourType::Interactable;
41+
42+
if (objTypeMatchesAny(obj, {
43+
GameObjectType::InverseGravityPortal,
44+
GameObjectType::NormalGravityPortal,
45+
GameObjectType::ShipPortal,
46+
GameObjectType::CubePortal,
47+
GameObjectType::YellowJumpPad,
48+
GameObjectType::PinkJumpPad,
49+
GameObjectType::GravityPad,
50+
GameObjectType::YellowJumpRing,
51+
GameObjectType::PinkJumpRing,
52+
GameObjectType::GravityRing,
53+
GameObjectType::InverseMirrorPortal,
54+
GameObjectType::NormalMirrorPortal,
55+
GameObjectType::BallPortal,
56+
GameObjectType::RegularSizePortal,
57+
GameObjectType::MiniSizePortal,
58+
GameObjectType::UfoPortal,
59+
GameObjectType::DualPortal,
60+
GameObjectType::SoloPortal,
61+
GameObjectType::WavePortal,
62+
GameObjectType::RobotPortal,
63+
GameObjectType::TeleportPortal,
64+
GameObjectType::GreenRing,
65+
GameObjectType::DropRing,
66+
GameObjectType::SpiderPortal,
67+
GameObjectType::RedJumpPad,
68+
GameObjectType::RedJumpRing,
69+
GameObjectType::CustomRing,
70+
GameObjectType::DashRing,
71+
GameObjectType::GravityDashRing,
72+
GameObjectType::SwingPortal,
73+
GameObjectType::GravityTogglePortal,
74+
GameObjectType::SpiderOrb,
75+
GameObjectType::SpiderPad,
76+
GameObjectType::TeleportOrb,
77+
}))
78+
return HitboxColourType::Interactable;
79+
80+
return HitboxColourType::Unk;
81+
}
82+
83+
bool HitboxNode::objTypeMatchesAny(GameObject* obj, std::vector<GameObjectType> types)
84+
{
85+
return std::find(types.begin(), types.end(), obj->m_objectType) != types.end();
86+
}
87+
88+
cocos2d::ccColor3B HitboxNode::colourForType(HitboxColourType colour)
89+
{
90+
switch (colour)
91+
{
92+
case HitboxColourType::Hazard:
93+
return HitboxHazard::get()->getColour();
94+
95+
case HitboxColourType::Solid:
96+
return HitboxSolid::get()->getColour();
97+
98+
case HitboxColourType::Passable:
99+
return HitboxPassable::get()->getColour();
100+
101+
case HitboxColourType::Interactable:
102+
return HitboxInteractable::get()->getColour();
103+
104+
case HitboxColourType::PlayerReg:
105+
return HitboxPlayer::get()->getColour();
106+
107+
case HitboxColourType::PlayerRot:
108+
return HitboxPlayerRot::get()->getColour();
109+
110+
default:
111+
return ccWHITE;
112+
}
113+
}
114+
115+
bool HitboxNode::shouldObjectDraw(GameObject* obj)
116+
{
117+
if (obj->m_isDecoration || obj->m_isDecoration2)
118+
return false;
119+
120+
if (objTypeMatchesAny(obj, { GameObjectType::EnterEffectObject, GameObjectType::Modifier }))
121+
return false;
122+
123+
if (obj->m_unk3ee)
124+
return false;
125+
126+
if (getObjectColour(obj) == HitboxColourType::Unk)
127+
return false;
128+
129+
return true;
130+
}
131+
132+
bool HitboxNode::shouldFillHitboxes()
133+
{
134+
return HitboxFill::get()->getRealEnabled();
135+
}
136+
137+
float HitboxNode::getHitboxThickness()
138+
{
139+
return 0.35f * (HitboxThickOutline::get()->getRealEnabled() ? 2 : 1);
140+
}
141+
142+
void HitboxNode::drawObjectHitbox(GameObject* obj)
143+
{
144+
auto col = colourForType(getObjectColour(obj));
145+
auto col2 = ccc4f(col.r / 255.0f, col.g / 255.0f, col.b / 255.0f, 1);
146+
147+
if (obj->m_objectRadius != 0)
148+
{
149+
drawCircle(ccp(obj->m_positionX, obj->m_positionY), obj->m_objectRadius * std::max<float>(obj->m_scaleX, obj->m_scaleY), ccc4f(0, 0, 0, 0), getHitboxThickness(), col2, 69);
150+
return;
151+
}
152+
153+
if (obj->m_isOrientedBoxDirty)
154+
obj->calculateOrientedBox();
155+
156+
auto rect = obj->m_orientedBox;
157+
158+
if (!rect)
159+
return;
160+
161+
if (obj->m_objectType == GameObjectType::Slope)
162+
{
163+
auto r = obj->getObjectRect();
164+
165+
CCPoint vertices[] = {
166+
ccp(r.getMaxX(), r.getMinY()), // br
167+
ccp(r.getMinX(), r.getMaxY()), // tl
168+
ccp(r.getMinX(), r.getMinY()), // bl
169+
};
170+
171+
switch (obj->m_slopeDirection)
172+
{
173+
case 0:
174+
case 7:
175+
vertices[1] = ccp(r.getMaxX(), r.getMaxY());
176+
break;
177+
178+
case 3:
179+
case 6:
180+
vertices[0] = ccp(r.getMaxX(), r.getMaxY());
181+
break;
182+
183+
case 1:
184+
case 5:
185+
vertices[2] = ccp(r.getMinX(), r.getMaxY());
186+
vertices[1] = ccp(r.getMaxX(), r.getMaxY());
187+
vertices[0] = ccp(r.getMaxX(), r.getMinY());
188+
break;
189+
}
190+
191+
drawPolygon(vertices, 3, ccc4f(0, 0, 0, 0), getHitboxThickness(), col2, BorderAlignment::Inside);
192+
return;
193+
}
194+
195+
CCPoint vertices[] = {
196+
rect->m_corners[0],
197+
rect->m_corners[1],
198+
rect->m_corners[2],
199+
rect->m_corners[3]
200+
};
201+
202+
// obj->m_isOrientedBoxDirty = true;
203+
204+
float v = 0;
205+
206+
if (shouldFillHitboxes())
207+
v = HitboxFillOpacity::get()->getValue();
208+
209+
drawPolygon(vertices, 4, ccc4f(0, 0, 0, 0), getHitboxThickness(), col2, BorderAlignment::Inside);
210+
}
211+
212+
void HitboxNode::forEachObject(GJBaseGameLayer* game, const std::function<void(GameObject*)>& callback)
213+
{
214+
if (!callback || !game)
215+
return;
216+
217+
int count = game->m_sections.empty() ? -1 : game->m_sections.size();
218+
for (int i = game->m_leftSectionIndex; i <= game->m_rightSectionIndex && i < count; ++i)
219+
{
220+
auto leftSection = game->m_sections[i];
221+
if (!leftSection) continue;
222+
223+
auto leftSectionSize = leftSection->size();
224+
for (int j = game->m_bottomSectionIndex; j <= game->m_topSectionIndex && j < leftSectionSize; ++j)\
225+
{
226+
auto section = leftSection->at(j);
227+
if (!section) continue;
228+
229+
auto sectionSize = game->m_sectionSizes[i]->at(j);
230+
for (int k = 0; k < sectionSize; ++k)
231+
{
232+
auto obj = section->at(k);
233+
if (!obj) continue;
234+
235+
if (obj == game->m_player1CollisionBlock)
236+
continue;
237+
238+
if (obj == game->m_player2CollisionBlock)
239+
continue;
240+
241+
if (obj == game->m_anticheatSpike)
242+
continue;
243+
244+
callback(obj);
245+
}
246+
}
247+
}
248+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#pragma once
2+
3+
#include <Geode/Geode.hpp>
4+
5+
enum class HitboxColourType
6+
{
7+
Unk,
8+
Solid,
9+
Hazard,
10+
Passable,
11+
Interactable,
12+
PlayerReg,
13+
PlayerRot,
14+
};
15+
16+
class HitboxNode : public cocos2d::CCDrawNode
17+
{
18+
protected:
19+
20+
bool shouldFillHitboxes();
21+
float getHitboxThickness();
22+
bool shouldObjectDraw(GameObject* obj);
23+
HitboxColourType getObjectColour(GameObject* obj);
24+
cocos2d::ccColor3B colourForType(HitboxColourType colour);
25+
bool objTypeMatchesAny(GameObject* obj, std::vector<GameObjectType> types);
26+
// thanks prevter
27+
void forEachObject(GJBaseGameLayer* game, const std::function<void(GameObject*)>& callback);
28+
29+
public:
30+
CREATE_FUNC(HitboxNode);
31+
32+
void drawObjectHitbox(GameObject* obj);
33+
34+
virtual bool init();
35+
void updateNode();
36+
};

src/Hacks/Level/Hitboxes/Hooks.cpp

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <Geode/modify/GameObject.hpp>
88
#include <Geode/modify/LevelEditorLayer.hpp>
99
#include "../Noclip/Hooks.hpp"
10+
#include "HitboxNode.hpp"
1011

1112
SUBMIT_HACK(ShowHitboxes);
1213
SUBMIT_HACK(ShowHitboxesOnDeath);
@@ -49,6 +50,8 @@ class $modify (HitboxBaseGameLayer, GJBaseGameLayer)
4950
struct Fields
5051
{
5152
std::vector<HitboxTrailState> states = {};
53+
std::vector<HitboxTrailState> statesBlue = {};
54+
HitboxNode* node = nullptr;
5255
};
5356

5457
void drawForPlayer(PlayerObject* po)
@@ -79,7 +82,7 @@ class $modify (HitboxBaseGameLayer, GJBaseGameLayer)
7982
m_debugDrawNode->drawPolygon(squareVertices2, 4, ccc4f(0, 0, 0, 0), 0.35f, ccc4f(0, 0.25f, 1, 1));
8083
}
8184

82-
void drawForState(HitboxTrailState state)
85+
void drawForState(HitboxTrailState state, bool blue = false)
8386
{
8487
CCPoint squareSize = state.size;
8588
CCPoint squarePosition = state.location;
@@ -91,14 +94,22 @@ class $modify (HitboxBaseGameLayer, GJBaseGameLayer)
9194
ccp(squarePosition.x - squareSize.x / 2, squarePosition.y + squareSize.y / 2)
9295
};
9396

94-
m_debugDrawNode->drawPolygon(squareVertices, 4, ccc4f(0, 0, 0, 0), 0.35f, ccc4f(-1, -1, -1, -1));
97+
m_debugDrawNode->drawPolygon(squareVertices, 4, ccc4f(0, 0, 0, 0), 0.35f, blue ? ccc4f(0, 0.25f, 1, 1) : ccc4f(-1, -1, -1, -1));
9598
}
9699

97100
virtual void updateDebugDraw()
98101
{
99102
if (typeinfo_cast<LevelEditorLayer*>(this))
100103
return GJBaseGameLayer::updateDebugDraw();
101104

105+
if (!m_fields->node)
106+
{
107+
m_fields->node = HitboxNode::create();
108+
m_debugDrawNode->getParent()->addChild(m_fields->node);
109+
}
110+
111+
m_fields->node->updateNode();
112+
102113
std::unordered_map<GameObject*, std::pair<float, float>> hitboxes = {};
103114
auto array = CCArrayExt<GameObject*>(m_objects);
104115

@@ -136,29 +147,45 @@ class $modify (HitboxBaseGameLayer, GJBaseGameLayer)
136147

137148
auto fields = m_fields.self();
138149

150+
drawForPlayer(m_player1);
151+
152+
if (m_player2 && m_player2->isRunning())
153+
drawForPlayer(m_player2);
154+
139155
if (HitboxTrail::get()->getRealEnabled())
140156
{
141157
if (!m_player1->m_isDead)
158+
{
142159
fields->states.insert(fields->states.begin(), { m_player1->m_position, m_player1->getObjectRect().size });
160+
fields->statesBlue.insert(fields->statesBlue.begin(), { m_player1->m_position, m_player1->getObjectRect(0.25f, 0.25f).size });
161+
}
143162

144163
if (m_player2 && m_player2->isRunning() && !m_player2->m_isDead)
164+
{
145165
fields->states.insert(fields->states.begin(), { m_player2->m_position, m_player2->getObjectRect().size });
166+
fields->statesBlue.insert(fields->statesBlue.begin(), { m_player2->m_position, m_player2->getObjectRect(0.25f, 0.25f).size });
167+
}
146168

147169
while (fields->states.size() > HitboxTrailMaxPositions::get()->getStringInt())
148170
{
149171
fields->states.pop_back();
150172
}
173+
174+
while (fields->statesBlue.size() > HitboxTrailMaxPositions::get()->getStringInt())
175+
{
176+
fields->statesBlue.pop_back();
177+
}
151178

152179
for (auto state : fields->states)
153180
{
154181
drawForState(state);
155182
}
156-
}
157183

158-
drawForPlayer(m_player1);
159-
160-
if (m_player2 && m_player2->isRunning())
161-
drawForPlayer(m_player2);
184+
for (auto state : fields->statesBlue)
185+
{
186+
drawForState(state, true);
187+
}
188+
}
162189
}
163190

164191
void resetLevelVariables()
@@ -168,7 +195,10 @@ class $modify (HitboxBaseGameLayer, GJBaseGameLayer)
168195
if (!typeinfo_cast<LevelEditorLayer*>(this))
169196
{
170197
if (HitboxTrailResetOnDeath::get()->getRealEnabled())
198+
{
171199
m_fields->states.clear();
200+
m_fields->statesBlue.clear();
201+
}
172202
}
173203
}
174204
};

0 commit comments

Comments
 (0)