diff --git a/src/client/component/camera.cpp b/src/client/component/camera.cpp index e698154e..88ef97ba 100644 --- a/src/client/component/camera.cpp +++ b/src/client/component/camera.cpp @@ -3,11 +3,15 @@ #include "game/game.hpp" #include "game/dvars.hpp" +#include "game/ui_scripting/execution.hpp" #include "command.hpp" #include "console.hpp" +#include "camera.hpp" +#include "gui/gui.hpp" #include +#include namespace camera { @@ -17,6 +21,9 @@ namespace camera game::dvar_t* cl_free_move_scale = nullptr; game::dvar_t** cg_paused = nullptr; + + using cb_type = std::optional>; + utils::concurrency::container callback; float angle_normalize(const float angle) { @@ -40,6 +47,12 @@ namespace camera float camera_origin[3]{}; + auto using_camera_override = false; + auto using_camera_angles_override = false; + + float camera_origin_override[3]{}; + float camera_angles_override[3]{}; + void paused_free_move() { if ((*cg_paused)->current.integer != 2) @@ -57,10 +70,27 @@ namespace camera return; } - game::cgs->refdefViewAngles[0] = angle_normalize((cmd.angles[0] * 0.000021457672f) + ps->delta_angles[0]); - game::cgs->refdefViewAngles[1] = angle_normalize((cmd.angles[1] * 0.000021457672f) + ps->delta_angles[1]); - game::cgs->refdefViewAngles[2] = angle_normalize((cmd.angles[2] * 0.000021457672f) + ps->delta_angles[2]); - game::cgs->refdefViewAngles[2] = 0; + callback.access([](cb_type& cb) + { + if (cb.has_value()) + { + auto& fn = cb.value(); + fn(); + } + }); + + if (using_camera_angles_override) + { + game::cgs->refdefViewAngles[0] = camera_angles_override[0]; + game::cgs->refdefViewAngles[1] = camera_angles_override[1]; + game::cgs->refdefViewAngles[2] = camera_angles_override[2]; + } + else + { + game::cgs->refdefViewAngles[0] = angle_normalize((cmd.angles[0] * 0.000021457672f) + ps->delta_angles[0]); + game::cgs->refdefViewAngles[1] = angle_normalize((cmd.angles[1] * 0.000021457672f) + ps->delta_angles[1]); + game::cgs->refdefViewAngles[2] = 0; + } const auto game_time = game::CG_GetGameTime(local_client_num); @@ -118,9 +148,18 @@ namespace camera ps->origin[2] -= scale * 10.f; } - game::refdef->org[0] = ps->origin[0]; - game::refdef->org[1] = ps->origin[1]; - game::refdef->org[2] = ps->origin[2] + ps->viewHeightCurrent; + if (using_camera_override) + { + game::refdef->org[0] = camera_origin_override[0]; + game::refdef->org[1] = camera_origin_override[1]; + game::refdef->org[2] = camera_origin_override[2]; + } + else + { + game::refdef->org[0] = ps->origin[0]; + game::refdef->org[1] = ps->origin[1]; + game::refdef->org[2] = ps->origin[2] + ps->viewHeightCurrent; + } camera_origin[0] = game::refdef->org[0]; camera_origin[1] = game::refdef->org[1]; @@ -147,12 +186,95 @@ namespace camera } } + void enable_free_move() + { + (*cg_paused)->current.integer = 2; + } + + void disable_free_move() + { + (*cg_paused)->current.integer = 0; + } + + bool is_free_move_enabled() + { + return *cg_paused && (*cg_paused)->current.integer == 2; + } + + void set_camera_position(const float x, const float y, const float z) + { + camera_origin_override[0] = x; + camera_origin_override[1] = y; + camera_origin_override[2] = z; + } + + void set_camera_angles(const float x, const float y, const float z) + { + camera_angles_override[0] = x; + camera_angles_override[1] = y; + camera_angles_override[2] = z; + } + + void set_using_origin_override(bool value) + { + using_camera_override = value; + } + + void set_using_angles_override(bool value) + { + using_camera_angles_override = value; + } + + ui_scripting::table get_camera_position() + { + ui_scripting::table res; + res["x"] = camera_origin[0]; + res["y"] = camera_origin[1]; + res["z"] = camera_origin[2]; + return res; + } + + void set_callback(const ui_scripting::script_value& callback_) + { + callback.access([=](cb_type& cb) + { + cb = [=]() + { + try + { + const auto state = *game::hks::lua_state; + const ui_scripting::table globals = state->globals.v.table; + const auto pcall = globals["pcall"]; + const auto results = pcall(callback_); + + if (!results[0].as()) + { + const auto error = results[1].as(); + console::error("Error executing camera callback: %s\n", error.data()); + } + } + catch (const std::exception& e) + { + console::error("Error executing camera callback: %s\n", e.what()); + } + }; + }); + } + + void clear_lua() + { + callback.access([=](cb_type& cb) + { + cb.reset(); + }); + } + class component final : public component_interface { public: void post_unpack() override { - cl_free_move_scale = dvars::register_float("cl_freemoveScale", 1.f, 0.01f, 100.f, + cl_free_move_scale = dvars::register_float("cl_freemoveScale", 1.f, 0.0001f, 100.f, game::DVAR_FLAG_SAVED, "Scale how fast you move in cl_freemove mode"); cg_paused = reinterpret_cast(0x141E39FC0); diff --git a/src/client/component/camera.hpp b/src/client/component/camera.hpp new file mode 100644 index 00000000..6fc5fbaa --- /dev/null +++ b/src/client/component/camera.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "game/ui_scripting/execution.hpp" + +namespace camera +{ + void enable_free_move(); + void disable_free_move(); + bool is_free_move_enabled(); + + void set_camera_position(const float x, const float y, const float z); + void set_camera_angles(const float x, const float y, const float z); + + void set_using_origin_override(bool value); + void set_using_angles_override(bool value); + + ui_scripting::table get_camera_position(); + + void set_callback(const ui_scripting::script_value& callback); + + void clear_lua(); +} diff --git a/src/client/component/ui_scripting.cpp b/src/client/component/ui_scripting.cpp index 7683bc33..e2dd5e36 100644 --- a/src/client/component/ui_scripting.cpp +++ b/src/client/component/ui_scripting.cpp @@ -18,6 +18,7 @@ #include "config.hpp" #include "motd.hpp" #include "achievements.hpp" +#include "camera.hpp" #include "game/ui_scripting/execution.hpp" #include "game/scripting/execution.hpp" @@ -708,6 +709,20 @@ namespace ui_scripting return table; }; + + table camera_table; + lua["camera"] = camera_table; + + camera::clear_lua(); + camera_table["enablefreemove"] = camera::enable_free_move; + camera_table["disablefreemove"] = camera::disable_free_move; + camera_table["isfreemoveenabled"] = camera::is_free_move_enabled; + camera_table["setposition"] = camera::set_camera_position; + camera_table["setangles"] = camera::set_camera_angles; + camera_table["getposition"] = camera::get_camera_position; + camera_table["setusingoriginoverride"] = camera::set_using_origin_override; + camera_table["setusinganglesoverride"] = camera::set_using_angles_override; + camera_table["setcallback"] = camera::set_callback; } void start() @@ -788,6 +803,7 @@ namespace ui_scripting void hks_shutdown_stub() { + camera::clear_lua(); converted_functions.clear(); globals = {}; hks_shutdown_hook.invoke(); diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index c0f99293..5ac48b78 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -69,7 +69,8 @@ namespace game { char __pad0[26]; vec3_t origin; - char __pad1[100]; + vec3_t angles; + char __pad1[88]; EntityState s; char __pad2[50]; Bounds box;