Skip to content

Commit

Permalink
Merge pull request spelunky-fyi#340 from spelunky-fyi/UI
Browse files Browse the repository at this point in the history
Random UI things
  • Loading branch information
Dregu authored Oct 7, 2023
2 parents 32778e2 + 9ef2e06 commit 6b559e7
Show file tree
Hide file tree
Showing 17 changed files with 403 additions and 61 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ The binaries will be in `build/bin/Release/`. You can also try the scripts in `.

```
--launch_game [path] launch ../Spel2.exe, path/Spel2.exe, or a specific exe, and load OL with Detours
--oldflip launch the game with -oldflip, may improve performance with external windows
--console keep console open to debug scripts etc
--inject use the old injection method instead of Detours with --launch_game
--info_dump output a bunch of game data to 'Spelunky 2/game_data'
Expand Down
3 changes: 2 additions & 1 deletion src/game_api/custom_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,8 @@ std::span<const ENT_TYPE> get_custom_entity_types(CUSTOM_TYPE type)
"ENT_TYPE_ITEM_DMCRATE",
"ENT_TYPE_ITEM_PRESENT",
"ENT_TYPE_ITEM_GHIST_PRESENT",
"ENT_TYPE_ITEM_ALIVE_EMBEDDED_ON_ICE");
"ENT_TYPE_ITEM_ALIVE_EMBEDDED_ON_ICE",
"ENT_TYPE_ITEM_POT");
case CUSTOM_TYPE::CONVEYORBELT:
return make_custom_entity_type_list<CUSTOM_TYPE::CONVEYORBELT>(
"ENT_TYPE_FLOOR_CONVEYORBELT_LEFT",
Expand Down
7 changes: 5 additions & 2 deletions src/game_api/entities_logical.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ class ShootingStarSpawner : public Entity
class LogicalDoor : public Entity
{
public:
/// Spawns this entity when not covered by floor. Must be initialized to valid ENT_TYPE before revealed, or crashes the game.
ENT_TYPE door_type;
ENT_TYPE platform_type; // always 37? yeah, that's the floor platform...
/// Spawns this entity below when tile below is uncovered. Doesn't spawn anything if it was never covered by floor, unless platform_spawned is set to false. Must be initialized to valid ENT_TYPE before revealed, or crashes the game.
ENT_TYPE platform_type;
/// Set automatically when not covered by floor.
bool not_hidden;
/// Is set true when you bomb the door, no matter what door, can't be reset
/// Set automatically when tile below is not covered by floor. Unset to force the platform to spawn if it was never covered in the first place.
bool platform_spawned;
bool unk5;
bool unk6;
Expand Down
1 change: 1 addition & 0 deletions src/game_api/flags.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -754,4 +754,5 @@ const char* pause_types[]{
"8: ?",
"16: ?",
"32: Ankh (smooth camera, janky audio)",
"Freeze on PRE_UPDATE", // this is not a real state.pause flag, it's only used by ui.cpp for magic
};
64 changes: 64 additions & 0 deletions src/game_api/rpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2058,3 +2058,67 @@ void set_boss_door_control_enabled(bool enable)
else
recover_mem("set_boss_door_control_enabled");
}

void update_state()
{
static size_t offset = 0;
if (offset == 0)
{
offset = get_address("state_refresh");
}
if (offset != 0)
{
auto state = State::get().ptr();
typedef void refresh_func(StateMemory*);
static refresh_func* rf = (refresh_func*)(offset);
rf(state);
}
}

void set_frametime(std::optional<double> frametime)
{
static size_t offset = 0;
if (offset == 0)
offset = get_address("engine_frametime");
if (offset != 0)
{
if (frametime.has_value())
write_mem_recoverable("engine_frametime", offset, frametime.value(), true);
else
recover_mem("engine_frametime");
}
}

std::optional<double> get_frametime()
{
static size_t offset = 0;
if (offset == 0)
offset = get_address("engine_frametime");
if (offset != 0)
return memory_read<double>(offset);
return std::nullopt;
}

void set_frametime_inactive(std::optional<double> frametime)
{
static size_t offset = 0;
if (offset == 0)
offset = get_address("engine_frametime") + 0x10;
if (offset != 0)
{
if (frametime.has_value())
write_mem_recoverable("engine_frametime_inactive", offset, frametime.value(), true);
else
recover_mem("engine_frametime_inactive");
}
}

std::optional<double> get_frametime_inactive()
{
static size_t offset = 0;
if (offset == 0)
offset = get_address("engine_frametime") + 0x10;
if (offset != 0)
return memory_read<double>(offset);
return std::nullopt;
}
5 changes: 5 additions & 0 deletions src/game_api/rpc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,3 +143,8 @@ void activate_tiamat_position_hack(bool activate);
void activate_crush_elevator_hack(bool activate);
void activate_hundun_hack(bool activate);
void set_boss_door_control_enabled(bool enable);
void update_state();
void set_frametime(std::optional<double> frametime);
std::optional<double> get_frametime();
void set_frametime_inactive(std::optional<double> frametime);
std::optional<double> get_frametime_inactive();
4 changes: 4 additions & 0 deletions src/game_api/script.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,7 @@ void SpelunkyScript::render_options()
{
m_Impl->Lock()->render_options();
}
std::string SpelunkyScript::execute(std::string code)
{
return m_Impl->Lock()->execute(code);
}
2 changes: 2 additions & 0 deletions src/game_api/script.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ class SpelunkyScript
void draw(ImDrawList* dl);
void render_options();

std::string execute(std::string code);

private:
std::unique_ptr<ScriptImpl> m_Impl;
};
25 changes: 20 additions & 5 deletions src/game_api/script/lua_vm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2048,31 +2048,46 @@ end
return AABB(ax + index * w + 0.02f * f, ay, ax + index * w + w - 0.02f * f, ay - h);
};

/// Olmec cutscene moves Olmec and destroys the four floor tiles, so those things never happen if the cutscene is disabled, and Olmec will spawn on even ground. More useful for level gen mods, where the cutscene doesn't make sense. You can also set olmec_cutscene.timer to the last frame (809) to skip to the end, with Olmec in the hole.
lua["set_olmec_cutscene_enabled"] = set_olmec_cutscene_enabled;

/// Tiamat cutscene is also responsible for locking the exit door
/// So you may need to close it yourself if you still want to be required to kill Tiamat
/// Tiamat cutscene is also responsible for locking the exit door, so you may need to close it yourself if you still want Tiamat kill to be required
lua["set_tiamat_cutscene_enabled"] = set_tiamat_cutscene_enabled;

/// Activate custom variables for position used for detecting the player (normally hardcoded)
/// note: because those variables are custom and game does not initiate them, you need to do it yourself for each Tiamat entity, recommending `set_post_entity_spawn`
/// note: because those variables are custom and game does not initiate them, you need to do it yourself for each Tiamat entity, recommending set_post_entity_spawn
/// default game values are: attack_x = 17.5 attack_y = 62.5
lua["activate_tiamat_position_hack"] = activate_tiamat_position_hack;

/// Activate custom variables for speed and y coordinate limit for crushing elevator
/// note: because those variables are custom and game does not initiate them, you need to do it yourself for each CrushElevator entity, recommending `set_post_entity_spawn`
/// note: because those variables are custom and game does not initiate them, you need to do it yourself for each CrushElevator entity, recommending set_post_entity_spawn
/// default game values are: speed = 0.0125, y_limit = 98.5
lua["activate_crush_elevator_hack"] = activate_crush_elevator_hack;

/// Activate custom variables for y coordinate limit for hundun and spawn of it's heads
/// note: because those variables are custom and game does not initiate them, you need to do it yourself for each Hundun entity, recommending `set_post_entity_spawn`
/// note: because those variables are custom and game does not initiate them, you need to do it yourself for each Hundun entity, recommending set_post_entity_spawn
/// default game value are: y_limit = 98.5, rising_speed_x = 0, rising_speed_y = 0.0125, bird_head_spawn_y = 55, snake_head_spawn_y = 71
lua["activate_hundun_hack"] = activate_hundun_hack;

/// Allows you to disable the control over the door for Hundun and Tiamat
/// This will also prevent game crashing when there is no exit door when they are in level
lua["set_boss_door_control_enabled"] = set_boss_door_control_enabled;

/// Run state update manually, i.e. simulate one logic frame. Use in e.g. POST_UPDATE, but be mindful of infinite loops, this will cause another POST_UPDATE. Can even be called thousands of times to simulate minutes of gameplay in a few seconds.
lua["update_state"] = update_state;

/// Set engine target frametime (1/framerate, default 1/60). Always capped by your GPU max FPS / VSync. To run the engine faster than rendered FPS, try update_state. Set to 0 to go as fast as possible. Call without arguments to reset.
lua["set_frametime"] = set_frametime;

/// Get engine target frametime (1/framerate, default 1/60).
lua["get_frametime"] = get_frametime;

/// Set engine target frametime when game is unfocused (1/framerate, default 1/33). Always capped by the engine frametime. Set to 0 to go as fast as possible. Call without arguments to reset.
lua["set_frametime_unfocused"] = set_frametime_inactive;

/// Get engine target frametime when game is unfocused (1/framerate, default 1/33).
lua["get_frametime_unfocused"] = get_frametime_inactive;

lua.create_named_table("INPUTS", "NONE", 0, "JUMP", 1, "WHIP", 2, "BOMB", 4, "ROPE", 8, "RUN", 16, "DOOR", 32, "MENU", 64, "JOURNAL", 128, "LEFT", 256, "RIGHT", 512, "UP", 1024, "DOWN", 2048);

lua.create_named_table(
Expand Down
33 changes: 33 additions & 0 deletions src/game_api/script/script_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,3 +207,36 @@ const std::filesystem::path& ScriptImpl::get_root_path() const
{
return script_folder;
}

std::string ScriptImpl::execute(std::string str)
{
if (!code.starts_with("return"))
{
std::string ret = execute_raw("return " + str);
if (!ret.starts_with("sol: "))
{
return ret;
}
}
return execute_raw(std::move(str));
}
std::string ScriptImpl::execute_raw(std::string str)
{
try
{
auto ret = execute_lua(lua, str);
if (ret.get_type() == sol::type::nil || ret.get_type() == sol::type::none)
{
return "";
}
else
{
sol::function serpent = lua["serpent"]["block"];
return serpent(ret);
}
}
catch (const sol::error& e)
{
return e.what();
}
}
3 changes: 3 additions & 0 deletions src/game_api/script/script_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,7 @@ class ScriptImpl : public LockableLuaBackend<ScriptImpl>
virtual const char* get_path() const override;
virtual const char* get_root() const override;
virtual const std::filesystem::path& get_root_path() const override;

std::string execute(std::string str);
std::string execute_raw(std::string str);
};
13 changes: 13 additions & 0 deletions src/game_api/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1840,6 +1840,19 @@ std::unordered_map<std::string_view, AddressRule> g_address_rules{
.at_exe()
.function_start(),
},
{
/* it's a static double, just find something that reads it
this+0x08 is clearly some kind of framerate related double, cause it's 60, but don't know what it does
this+0x10 is hopefully unfocused frametime for the other function, but maybe it needs own pattern
22d12248 00 00 00 double 0.01666666753590107
20 11 11
91 3f */
"engine_frametime"sv,
PatternCommandBuffer{}
.find_after_inst("48 8d 04 0a 48 85 d2 48 0f 44 c2 48 85 c9 48 0f 44 c1 66 0f 28 c8"_gh)
.decode_pc(4)
.at_exe(),
},
{
// Borrowed from Playlunky logger.cpp
"game_log_function"sv,
Expand Down
8 changes: 8 additions & 0 deletions src/game_api/window_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ bool detect_wine()
return true;
}

UINT g_SyncInterval{1};
IDXGISwapChain* g_SwapChain{nullptr};
ID3D11Device* g_Device{nullptr};
ID3D11DeviceContext* g_Context{nullptr};
Expand Down Expand Up @@ -210,6 +211,8 @@ LRESULT CALLBACK hkKeyboard(const int code, const WPARAM wParam, const LPARAM lP
static bool skip_hkPresent = false;
HRESULT STDMETHODCALLTYPE hkPresent(IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags)
{
SyncInterval = g_SyncInterval;

if (skip_hkPresent)
return g_OrigSwapChainPresent(pSwapChain, SyncInterval, Flags);

Expand Down Expand Up @@ -468,6 +471,11 @@ void hide_cursor()
}
}

void imgui_vsync(bool enable)
{
g_SyncInterval = (UINT)enable;
}

ID3D11Device* get_device()
{
return g_Device;
Expand Down
1 change: 1 addition & 0 deletions src/game_api/window_api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ HWND get_window();

void show_cursor();
void hide_cursor();
void imgui_vsync(bool enable);

struct ID3D11Device* get_device();
2 changes: 1 addition & 1 deletion src/injected/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ void attach_stdout(DWORD pid)
freopen_s(&stream, "CONOUT$", "w", stdout);
freopen_s(&stream, "CONOUT$", "w", stderr);
// freopen_s(&stream, "CONIN$", "r", stdin);
INFO("Press Ctrl+C to detach this window from the process.");
INFO("Do not close this window or the game will also die. Press Ctrl+C to detach this window from the game process.");
}

void run()
Expand Down
Loading

0 comments on commit 6b559e7

Please sign in to comment.