diff --git a/cheat-library/cheat-library.vcxproj b/cheat-library/cheat-library.vcxproj
index 7a895ce..18e4953 100644
--- a/cheat-library/cheat-library.vcxproj
+++ b/cheat-library/cheat-library.vcxproj
@@ -22,6 +22,7 @@
+
@@ -116,6 +117,7 @@
+
diff --git a/cheat-library/cheat-library.vcxproj.filters b/cheat-library/cheat-library.vcxproj.filters
index 3541fa9..f8b6557 100644
--- a/cheat-library/cheat-library.vcxproj.filters
+++ b/cheat-library/cheat-library.vcxproj.filters
@@ -255,6 +255,9 @@
Header Files
+
+ Header Files
+
Header Files
@@ -471,6 +474,9 @@
Source Files
+
+ Source Files
+
Source Files
diff --git a/cheat-library/src/user/cheat/cheat.cpp b/cheat-library/src/user/cheat/cheat.cpp
index 234b7f9..58f6614 100644
--- a/cheat-library/src/user/cheat/cheat.cpp
+++ b/cheat-library/src/user/cheat/cheat.cpp
@@ -57,6 +57,7 @@
#include
#include
#include
+#include
#include "GenshinCM.h"
@@ -87,6 +88,7 @@ namespace cheat
FEAT_INST(NoClip),
FEAT_INST(RapidFire),
FEAT_INST(AutoRun),
+ FEAT_INST(FallControl),
FEAT_INST(AutoLoot),
FEAT_INST(AutoTreeFarm),
diff --git a/cheat-library/src/user/cheat/game/Entity.cpp b/cheat-library/src/user/cheat/game/Entity.cpp
index 37c3747..6e0fed3 100644
--- a/cheat-library/src/user/cheat/game/Entity.cpp
+++ b/cheat-library/src/user/cheat/game/Entity.cpp
@@ -229,7 +229,7 @@ namespace cheat::game
SAFE_END();
}
- app::Vector3 Entity::forward()
+ app::Vector3 Entity::forward() const
{
if (m_RawEntity == nullptr)
return {};
@@ -237,12 +237,12 @@ namespace cheat::game
return app::MoleMole_BaseEntity_GetForward(m_RawEntity, nullptr);
}
- app::Vector3 Entity::back()
+ app::Vector3 Entity::back() const
{
return -forward();
}
- app::Vector3 Entity::right()
+ app::Vector3 Entity::right() const
{
if (m_RawEntity == nullptr)
return {};
@@ -250,12 +250,12 @@ namespace cheat::game
return app::MoleMole_BaseEntity_GetRight(m_RawEntity, nullptr);
}
- app::Vector3 Entity::left()
+ app::Vector3 Entity::left() const
{
return -right();
}
- app::Vector3 Entity::up()
+ app::Vector3 Entity::up() const
{
if (m_RawEntity == nullptr)
return {};
@@ -263,7 +263,7 @@ namespace cheat::game
return app::MoleMole_BaseEntity_GetUp(m_RawEntity, nullptr);
}
- app::Vector3 Entity::down()
+ app::Vector3 Entity::down() const
{
return -up();
}
diff --git a/cheat-library/src/user/cheat/game/Entity.h b/cheat-library/src/user/cheat/game/Entity.h
index 6a4e9b2..7aa96a3 100644
--- a/cheat-library/src/user/cheat/game/Entity.h
+++ b/cheat-library/src/user/cheat/game/Entity.h
@@ -39,12 +39,12 @@ namespace cheat::game
app::Rigidbody* rigidbody();
app::Animator* animator();
- app::Vector3 forward();
- app::Vector3 back();
- app::Vector3 right();
- app::Vector3 left();
- app::Vector3 up();
- app::Vector3 down();
+ app::Vector3 forward() const;
+ app::Vector3 back() const;
+ app::Vector3 right() const;
+ app::Vector3 left() const;
+ app::Vector3 up() const;
+ app::Vector3 down() const;
template
T* plugin(void* pClass)
diff --git a/cheat-library/src/user/cheat/player/FallControl.cpp b/cheat-library/src/user/cheat/player/FallControl.cpp
new file mode 100644
index 0000000..7851b75
--- /dev/null
+++ b/cheat-library/src/user/cheat/player/FallControl.cpp
@@ -0,0 +1,121 @@
+#include "pch-il2cpp.h"
+#include "FallControl.h"
+
+#include
+#include
+
+namespace cheat::feature
+{
+ bool FallControl::isFalling = false;
+
+ FallControl::FallControl() : Feature(),
+ NF(f_Enabled, "Fall Control", "FallControl", false),
+ NF(f_Speed, "Speed", "FallControl", 10.0f)
+ {
+ events::GameUpdateEvent += MY_METHOD_HANDLER(FallControl::OnGameUpdate);
+ events::MoveSyncEvent += MY_METHOD_HANDLER(FallControl::OnMoveSync);
+ }
+
+ const FeatureGUIInfo& cheat::feature::FallControl::GetGUIInfo() const
+ {
+ static const FeatureGUIInfo info{ "Fall-Control", "Player", true };
+ return info;
+ }
+
+ void cheat::feature::FallControl::DrawMain()
+ {
+ ConfigWidget("Enabled", f_Enabled, "Enables fall control");
+ ConfigWidget("Speed", f_Speed, 1.0f, 0.0f, 100.0f, "Movement speed when using fall control");
+ }
+
+ bool cheat::feature::FallControl::NeedStatusDraw() const
+ {
+ return f_Enabled;
+ }
+
+ void cheat::feature::FallControl::DrawStatus()
+ {
+ ImGui::Text("Fall Control [%.1f]", f_Speed.value());
+ }
+
+ FallControl& cheat::feature::FallControl::GetInstance()
+ {
+ static FallControl instance;
+ return instance;
+ }
+
+ // Fall control update function
+ // Detects and moves avatar when movement keys are pressed.
+ void FallControl::OnGameUpdate()
+ {
+ if (!f_Enabled || !isFalling)
+ return;
+
+ auto& manager = game::EntityManager::instance();
+
+ const auto avatarEntity = manager.avatar();
+ auto rigidBody = avatarEntity->rigidbody();
+ if (rigidBody == nullptr)
+ return;
+
+ const auto cameraEntity = game::Entity(reinterpret_cast(manager.mainCamera()));
+ app::Vector3 direction = {};
+ if (Hotkey(ImGuiKey_W).IsPressed())
+ direction = direction + cameraEntity.forward();;
+ if (Hotkey(ImGuiKey_S).IsPressed())
+ direction = direction + cameraEntity.back();;
+ if (Hotkey(ImGuiKey_D).IsPressed())
+ direction = direction + cameraEntity.right();;
+ if (Hotkey(ImGuiKey_A).IsPressed())
+ direction = direction + cameraEntity.left();;
+ if (IsVectorZero(direction))
+ return;
+ // Do not change falling velocity when camera relative
+ direction.y = 0;
+
+ // Alternative, using set_velocity. Does not work while falling?
+ // const float speed = f_Speed.value();
+ // const auto currentVelocity = app::Rigidbody_get_velocity(rigidBody, nullptr);
+ // const auto desiredvelocity = currentVelocity + direction * speed;
+ // LOG_DEBUG("Current velocity: [%.1f,%.1f,%.1f]", currentVelocity.x, currentVelocity.y, currentVelocity.z);
+ // LOG_DEBUG("Desired velocity: [%.1f,%.1f,%.1f]\n", desiredvelocity.x, desiredvelocity.y, desiredvelocity.z);
+ // app::Rigidbody_set_collisionDetectionMode(rigidBody, app::CollisionDetectionMode__Enum::Continuous, nullptr);
+ // app::Rigidbody_set_velocity(rigidBody, desiredvelocity, nullptr);
+
+ const app::Vector3 prevPos = avatarEntity->relativePosition();
+ const auto currentVelocity = app::Rigidbody_get_velocity(rigidBody, nullptr);
+ const float speed = f_Speed.value();
+ const float deltaTime = app::Time_get_deltaTime(nullptr);
+ const app::Vector3 newPos = prevPos + (currentVelocity + direction * speed) * deltaTime;
+ avatarEntity->setRelativePosition(newPos);
+ }
+
+ // Detects when player is falling and enables the FallControl cheat
+ void FallControl::OnMoveSync(uint32_t entityId, app::MotionInfo* syncInfo)
+ {
+ if (!f_Enabled) {
+ // Edgecase for when you turn off cheat while falling
+ isFalling = false;
+ return;
+ }
+
+ const auto motionState = syncInfo->fields.motionState;
+ switch (motionState)
+ {
+ // These states tell us we are falling
+ case app::MotionState__Enum::MotionDrop:
+ isFalling = true;
+ return;
+
+ // State that doesn't tell us anything
+ case app::MotionState__Enum::MotionStandby:
+ case app::MotionState__Enum::MotionNotify:
+ return;
+
+ // We are not falling
+ default:
+ isFalling = false;
+ break;
+ }
+ }
+}
diff --git a/cheat-library/src/user/cheat/player/FallControl.h b/cheat-library/src/user/cheat/player/FallControl.h
new file mode 100644
index 0000000..5979114
--- /dev/null
+++ b/cheat-library/src/user/cheat/player/FallControl.h
@@ -0,0 +1,32 @@
+#pragma once
+#include
+#include
+
+#include
+
+namespace cheat::feature
+{
+ class FallControl : public Feature
+ {
+ public:
+ config::Field> f_Enabled;
+ config::Field f_Speed;
+
+ static FallControl& GetInstance();
+
+ // Inherited via Feature
+ virtual const FeatureGUIInfo& GetGUIInfo() const override;
+ virtual void DrawMain() override;
+
+ virtual bool NeedStatusDraw() const override;
+ void DrawStatus() override;
+
+ void OnGameUpdate();
+ void OnMoveSync(uint32_t entityId, app::MotionInfo* syncInfo);
+
+ private:
+ FallControl();
+
+ static bool isFalling;
+ };
+}