Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions mods-v2/Click-Between-Frames-master/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[CMakeLists.txt]
indent_style = space
indent_size = 2

[*.{cpp, hpp, h}]
indent_style = space
indent_size = 4
52 changes: 52 additions & 0 deletions mods-v2/Click-Between-Frames-master/.github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: Build

on:
push:
branches: [master]
pull_request:
workflow_dispatch:

permissions:
contents: write

jobs:
build:
runs-on: windows-latest

steps:
- name: Checkout
uses: actions/checkout@v4
with:
submodules: recursive

- name: Configure
run: cmake -B build -A Win32 "-DCMAKE_POLICY_VERSION_MINIMUM=3.5"

- name: Build
run: cmake --build build --config Release

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ClickBetweenFrames
path: build/Release/ClickBetweenFrames.dll
if-no-files-found: error

- name: Move nightly tag
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
run: |
git tag -f nightly ${{ github.sha }}
git push -f origin nightly

- name: Release
if: github.event_name == 'push' && github.ref == 'refs/heads/master'
uses: softprops/action-gh-release@v2
with:
tag_name: nightly
name: Nightly build
body: |
Automated build of `${{ github.sha }}`.

${{ github.event.head_commit.message }}
files: build/Release/ClickBetweenFrames.dll
prerelease: true
2 changes: 2 additions & 0 deletions mods-v2/Click-Between-Frames-master/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
build/
.vscode/
9 changes: 9 additions & 0 deletions mods-v2/Click-Between-Frames-master/.gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[submodule "libraries/minhook"]
path = libraries/minhook
url = https://github.com/TsudaKageyu/minhook.git
[submodule "libraries/cocos-headers"]
path = libraries/cocos-headers
url = https://github.com/HJfod/cocos-headers
[submodule "libraries/gd.h"]
path = libraries/gd.h
url = https://github.com/poweredbypie/gd.h
27 changes: 27 additions & 0 deletions mods-v2/Click-Between-Frames-master/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.10)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

project(ClickBetweenFrames)

file(GLOB SOURCE_FILES CONFIGURE_DEPENDS src/*.cpp)
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES})

# this is so stupid
set(CMAKE_SIZEOF_VOID_P 4)

if (${CMAKE_CXX_COMPILER_ID} STREQUAL Clang)
# ensure 32 bit on clang
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -target i386-pc-windows-msvc")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -target i386-pc-windows-msvc")
add_definitions("--target=i386-pc-windows-msvc")
endif()

target_include_directories(${PROJECT_NAME} PRIVATE
libraries/minhook/include
)

add_subdirectory(libraries/minhook)
add_subdirectory(libraries/cocos-headers)

target_link_libraries(${PROJECT_NAME} minhook cocos2d)
21 changes: 21 additions & 0 deletions mods-v2/Click-Between-Frames-master/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 theyareonit

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
45 changes: 45 additions & 0 deletions mods-v2/Click-Between-Frames-master/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
I'm not gonna bother updating the README for this mod since it's a bit of a mess, but here it is anyway.

# Installation

Install [Geode](https://geode-sdk.org/install/), then install this mod from the Geode index.

# What does it do

This mod allows your inputs to register in between visual frames, which drastically increases input precision on low framerates like 60FPS.

If you like the mod, please consider [donating](https://www.paypal.com/donate/?hosted_button_id=U2LWN9H395TF8)!

# Why not just use Click Between Steps?

Because CBS is limited to 480TPS precision, while this mod does not have a hard limit on input precision (well, it technically does, but it's an extremely large number that would be hard to calculate). Also, this mod has a few fixes to improve the precision even further than Robtop's implementation, even if you ignore the 480TPS limit of Rob's version.

# How to use

If the icon is automatically jumping when you respawn, disable the "Stop Triggers on Death" hack in Mega Hack.

To edit keybinds, go to the GD options menu and click the "Keys" button in the top right (requires Custom Keybinds).

It is recommended to use either Physics Bypass or one of these FPS values: 60, 80, 120, or 240. \
This is because 2.2 has stutters on FPS values that aren't factors or multiples of 240 unless you enable Physics Bypass.

Disable TPS Bypass/Draw Divide when using this mod, because they're pointless. \
This mod automatically overrides the vanilla "Click On Steps" and "Click Between Steps" options, so you don't need to worry about those.

The mod comes with its own version of Physics Bypass in the mod options (on Windows/Linux). Be warned that not all lists or leaderboards that allow CBF will consider this legit!

If on Linux, and the mod doesn't work, please try running the command <cr>sudo usermod -aG input $USER</c> (this will make your system slightly less secure).

# Known issues

- This mod does not work with bots
- Linux controller support is experimental

# Credits

Icon by alex/sincos.

Android, macOS, & iOS code based off [Click on Steps by zmx](https://github.com/qimiko/click-on-steps), used with permission. \
Android port by [mat](https://github.com/matcool), macOS & iOS ports by [Jasmine](https://github.com/hiimjasmine00).

(these credits are slightly outdated since the mod just uses the vanilla game's input handling now but oh well)
29 changes: 29 additions & 0 deletions mods-v2/Click-Between-Frames-master/src/dllmain.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>

HMODULE g_module = nullptr;

void modLoaded();

DWORD WINAPI thread_func(void*) {
// quickldr can get us in before cocos is around and we hook one of its exports
for (int i = 0; i < 200 && !GetModuleHandleA("libcocos2d.dll"); i++) Sleep(50);

modLoaded();
return 0;
}

BOOL APIENTRY DllMain(HMODULE handle, DWORD reason, LPVOID reserved) {
if (reason == DLL_PROCESS_ATTACH) {
g_module = handle;
DisableThreadLibraryCalls(handle);

auto h = CreateThread(0, 0, thread_func, handle, 0, 0);
if (h)
CloseHandle(h);
else
return FALSE;
}
return TRUE;
}
147 changes: 147 additions & 0 deletions mods-v2/Click-Between-Frames-master/src/gd.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#pragma once

// minimal 2.113 bindings, offsets from the windows binary

#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <Windows.h>
#include <cstdint>
#include <string>
#include <cocos2d.h>

using namespace cocos2d;

inline uintptr_t gdBase() {
static uintptr_t base = reinterpret_cast<uintptr_t>(GetModuleHandleA(nullptr));
return base;
}

inline uintptr_t cocosBase() {
static uintptr_t base = reinterpret_cast<uintptr_t>(GetModuleHandleA("libcocos2d.dll"));
return base;
}

enum class PlayerButton : int {
Jump = 1,
Left = 2,
Right = 3
};

// our own ids for controller buttons, they just have to be unique
enum ControllerKeyCodes : int {
CONTROLLER_A = 1000,
CONTROLLER_B = 1001,
CONTROLLER_X = 1002,
CONTROLLER_Y = 1003,
CONTROLLER_Start = 1004,
CONTROLLER_Back = 1005,
CONTROLLER_RB = 1006,
CONTROLLER_LB = 1007,
CONTROLLER_RT = 1008,
CONTROLLER_LT = 1009,
CONTROLLER_Up = 1010,
CONTROLLER_Down = 1011,
CONTROLLER_Left = 1012,
CONTROLLER_Right = 1013,
CONTROLLER_LTHUMBSTICK_UP = 1014,
CONTROLLER_LTHUMBSTICK_DOWN = 1015,
CONTROLLER_LTHUMBSTICK_LEFT = 1016,
CONTROLLER_LTHUMBSTICK_RIGHT = 1017,
CONTROLLER_RTHUMBSTICK_UP = 1018,
CONTROLLER_RTHUMBSTICK_DOWN = 1019,
CONTROLLER_RTHUMBSTICK_LEFT = 1020,
CONTROLLER_RTHUMBSTICK_RIGHT = 1021
};

class PlayerObject {
public:
char m_pad000[0x488];
CCDictionary* m_collisionLogBottom; // 0x488
CCDictionary* m_collisionLogTop; // 0x48C
char m_pad490[0x4B8 - 0x490];
int m_lastCollisionBottom; // 0x4B8
int m_lastCollisionTop; // 0x4BC
char m_pad4C0[0x628 - 0x4C0];
double m_yVelocity; // 0x628
bool m_isOnSlope; // 0x630
bool m_wasOnSlope; // 0x631
char m_pad632[0x638 - 0x632];
bool m_isShip; // 0x638
bool m_isBird; // 0x639
bool m_isBall; // 0x63A
bool m_isDart; // 0x63B
bool m_isRobot; // 0x63C
bool m_isSpider; // 0x63D
bool m_isUpsideDown; // 0x63E
char m_pad63F[1];
bool m_isOnGround; // 0x640
bool m_isDashing; // 0x641
char m_pad642[0x66C - 0x642];
CCArray* m_touchingRings; // 0x66C
char m_pad670[0x67C - 0x670];
CCPoint m_position; // 0x67C
};

class PlayLayer {
public:
char m_pad000[0x224];
PlayerObject* m_player1; // 0x224
PlayerObject* m_player2; // 0x228
char m_pad22C[0x2A9 - 0x22C];
bool m_isDualMode; // 0x2A9
char m_pad2AA[0x39C - 0x2AA];
bool m_playerDied; // 0x39C
char m_pad39D[0x494 - 0x39D];
bool m_isTestMode; // 0x494
char m_pad495[0x4BD - 0x495];
bool m_hasLevelCompleteMenu; // 0x4BD
char m_pad4BE[0x52F - 0x4BE];
bool m_isPaused; // 0x52F

static PlayLayer* get();

// 2.1 takes the delta in xmm2 and the player on the stack, so this needs a thunk
void checkCollisions(PlayerObject* player, float dt);

// 2.1's equivalent of GJBaseGameLayer::handleButton; the int argument is unused
void pushButton(int button, bool isPlayer1) {
reinterpret_cast<void(__thiscall*)(PlayLayer*, int, bool)>(gdBase() + 0x111500)(this, button, isPlayer1);
}
void releaseButton(int button, bool isPlayer1) {
reinterpret_cast<void(__thiscall*)(PlayLayer*, int, bool)>(gdBase() + 0x111660)(this, button, isPlayer1);
}
};

class GameManager {
public:
char m_pad000[0x164];
PlayLayer* m_playLayer; // 0x164
void* m_editorLayer; // 0x168

static GameManager* sharedState() {
return reinterpret_cast<GameManager*(__cdecl*)()>(gdBase() + 0xC4A50)();
}

PlayLayer* getPlayLayer() { return m_playLayer; }
void* getEditorLayer() { return m_editorLayer; }
};

#pragma runtime_checks("s", off)
class FLAlertLayer {
public:
// the caption is passed by value as an std::string so the caller has to clean the stack
static FLAlertLayer* create(void* target, const char* title, const char* btn1, const char* btn2, std::string caption) {
auto ret = reinterpret_cast<FLAlertLayer*(__fastcall*)(void*, const char*, const char*, const char*, std::string)>(
gdBase() + 0x22680)(target, title, btn1, btn2, caption);
__asm add esp, 0x20
return ret;
}
void show() {
reinterpret_cast<void(__thiscall*)(FLAlertLayer*)>(gdBase() + 0x23560)(this);
}
};
#pragma runtime_checks("s", restore)

inline PlayLayer* PlayLayer::get() {
return GameManager::sharedState()->getPlayLayer();
}
Loading