add gsc functions and basic hud
This commit is contained in:
parent
b77d42d869
commit
6a07dbb4e9
826
source/proxy-dll/component/gsc_funcs.cpp
Normal file
826
source/proxy-dll/component/gsc_funcs.cpp
Normal file
@ -0,0 +1,826 @@
|
||||
#include <std_include.hpp>
|
||||
#include "gsc_funcs.hpp"
|
||||
#include "definitions/game.hpp"
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "component/scheduler.hpp"
|
||||
|
||||
|
||||
#include <utilities/hook.hpp>
|
||||
#include <utilities/json_config.hpp>
|
||||
|
||||
namespace gsc_funcs
|
||||
{
|
||||
uint32_t canon_hash(const char* str)
|
||||
{
|
||||
uint32_t hash = 0x4B9ACE2F;
|
||||
|
||||
for (const char* data = str; *data; data++)
|
||||
{
|
||||
char c = (char)tolower(*data);
|
||||
hash = ((c + hash) ^ ((c + hash) << 10)) + (((c + hash) ^ ((c + hash) << 10)) >> 6);
|
||||
}
|
||||
|
||||
return 0x8001 * ((9 * hash) ^ ((9 * hash) >> 11));
|
||||
}
|
||||
void gsc_error(const char* message, game::scriptInstance_t inst, bool terminal, ...)
|
||||
{
|
||||
static char buffer[game::scriptInstance_t::SCRIPTINSTANCE_MAX][0x800];
|
||||
|
||||
va_list va;
|
||||
va_start(va, terminal);
|
||||
vsprintf_s(buffer[inst], message, va);
|
||||
va_end(va);
|
||||
|
||||
game::ScrVm_Error(custom_error_id, inst, buffer[inst], terminal);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
enum hud_elem_align_x
|
||||
{
|
||||
HUD_ALIGN_X_LEFT = 0,
|
||||
HUD_ALIGN_X_CENTER,
|
||||
HUD_ALIGN_X_RIGHT,
|
||||
HUD_ALIGN_X_MAX,
|
||||
};
|
||||
enum hud_elem_align_y
|
||||
{
|
||||
HUD_ALIGN_Y_TOP = 0,
|
||||
HUD_ALIGN_Y_MIDDLE,
|
||||
HUD_ALIGN_Y_BOTTOM,
|
||||
HUD_ALIGN_Y_MAX
|
||||
};
|
||||
|
||||
struct hud_elem
|
||||
{
|
||||
std::string text{};
|
||||
hud_elem_align_x align_x{};
|
||||
hud_elem_align_y align_y{};
|
||||
hud_elem_align_x anchor_x{};
|
||||
hud_elem_align_y anchor_y{};
|
||||
game::vec4_t color{ 1,1,1,1 };
|
||||
float x{};
|
||||
float y{};
|
||||
float scale = 1;
|
||||
|
||||
void set_color_rgba(uint32_t rgba)
|
||||
{
|
||||
color[0] = (game::vec_t)(rgba & 0xFF) / 0x100;
|
||||
color[1] = (game::vec_t)((rgba >> 8) & 0xFF) / 0x100;
|
||||
color[2] = (game::vec_t)((rgba >> 16) & 0xFF) / 0x100;
|
||||
uint32_t alpha = (rgba >> 24) & 0xFF;
|
||||
color[3] = alpha ? (game::vec_t)(alpha) / 0x100 : 1;
|
||||
}
|
||||
|
||||
float get_relative_x(float screen_width, float width) const
|
||||
{
|
||||
float delta{};
|
||||
switch (align_x)
|
||||
{
|
||||
case HUD_ALIGN_X_LEFT:
|
||||
delta = 0;
|
||||
break;
|
||||
case HUD_ALIGN_X_CENTER:
|
||||
delta = width / 2;
|
||||
break;
|
||||
case HUD_ALIGN_X_RIGHT:
|
||||
delta = -width;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (anchor_x)
|
||||
{
|
||||
case HUD_ALIGN_X_LEFT:
|
||||
return delta + x;
|
||||
case HUD_ALIGN_X_CENTER:
|
||||
return screen_width / 2 + delta + x;
|
||||
case HUD_ALIGN_X_RIGHT:
|
||||
return screen_width + delta + x;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
float get_relative_y(float screen_height, float height) const
|
||||
{
|
||||
float delta{};
|
||||
switch (align_y)
|
||||
{
|
||||
case HUD_ALIGN_Y_TOP:
|
||||
delta = 0;
|
||||
break;
|
||||
case HUD_ALIGN_Y_MIDDLE:
|
||||
delta = height / 2;
|
||||
break;
|
||||
case HUD_ALIGN_Y_BOTTOM:
|
||||
delta = -height;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (anchor_y)
|
||||
{
|
||||
case HUD_ALIGN_Y_TOP:
|
||||
return delta + y;
|
||||
case HUD_ALIGN_Y_MIDDLE:
|
||||
return screen_height / 2 + delta + y;
|
||||
case HUD_ALIGN_Y_BOTTOM:
|
||||
return screen_height + delta + y;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
std::unordered_map<uint64_t, hud_elem> hud_elems{};
|
||||
|
||||
void shield_log(game::scriptInstance_t inst)
|
||||
{
|
||||
game::ScrVarType_t type = game::ScrVm_GetType(inst, 0);
|
||||
switch (type)
|
||||
{
|
||||
case game::TYPE_UNDEFINED:
|
||||
logger::write(logger::LOG_TYPE_INFO, "[ %s VM ] undefined", inst ? "CSC" : "GSC");
|
||||
break;
|
||||
case game::TYPE_STRING:
|
||||
logger::write(logger::LOG_TYPE_INFO, "[ %s VM ] %s", inst ? "CSC" : "GSC", game::ScrVm_GetString(inst, 0));
|
||||
break;
|
||||
case game::TYPE_HASH:
|
||||
{
|
||||
game::BO4_AssetRef_t hash{};
|
||||
logger::write(logger::LOG_TYPE_INFO, "[ %s VM ] %llx", inst ? "CSC" : "GSC", game::ScrVm_GetHash(&hash, inst, 0)->hash);
|
||||
}
|
||||
break;
|
||||
case game::TYPE_INTEGER:
|
||||
logger::write(logger::LOG_TYPE_INFO, "[ %s VM ] %lld", inst ? "CSC" : "GSC", game::ScrVm_GetInt(inst, 0));
|
||||
break;
|
||||
case game::TYPE_FLOAT:
|
||||
logger::write(logger::LOG_TYPE_INFO, "[ %s VM ] %f", inst ? "CSC" : "GSC", game::ScrVm_GetFloat(inst, 0));
|
||||
break;
|
||||
case game::TYPE_VECTOR:
|
||||
{
|
||||
game::vec3_t vec{};
|
||||
game::ScrVm_GetVector(inst, 0, &vec);
|
||||
logger::write(logger::LOG_TYPE_INFO, "[ %s VM ] (%f, %f, %f)", inst ? "CSC" : "GSC", vec[0], vec[1], vec[2]);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
gsc_error("Call of ShieldLog with unknown type: %d", inst, false, type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void shield_clear_hud_elems(game::scriptInstance_t inst)
|
||||
{
|
||||
hud_elems.clear();
|
||||
}
|
||||
|
||||
void shield_register_hud_elem(game::scriptInstance_t inst)
|
||||
{
|
||||
game::BO4_AssetRef_t hashRef{};
|
||||
|
||||
uint64_t id = game::ScrVm_GetHash(&hashRef, inst, 0)->hash;
|
||||
|
||||
hud_elem& elem = hud_elems[id];
|
||||
|
||||
uint32_t params = game::ScrVm_GetNumParam(inst);
|
||||
|
||||
if (params > 1)
|
||||
{
|
||||
elem.text = game::ScrVm_GetString(inst, 1);
|
||||
}
|
||||
else {
|
||||
elem.text = "";
|
||||
}
|
||||
|
||||
if (params > 2)
|
||||
{
|
||||
elem.set_color_rgba((uint32_t)game::ScrVm_GetInt(inst, 2));
|
||||
}
|
||||
else {
|
||||
elem.set_color_rgba(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
if (params > 3)
|
||||
{
|
||||
elem.x = game::ScrVm_GetFloat(inst, 3);
|
||||
}
|
||||
else {
|
||||
elem.x = 0;
|
||||
}
|
||||
|
||||
if (params > 4)
|
||||
{
|
||||
elem.y = game::ScrVm_GetFloat(inst, 4);
|
||||
}
|
||||
else {
|
||||
elem.y = 0;
|
||||
}
|
||||
|
||||
if (params > 5)
|
||||
{
|
||||
int64_t val = game::ScrVm_GetInt(inst, 5);
|
||||
|
||||
if (val >= 0 && val > HUD_ALIGN_X_MAX)
|
||||
{
|
||||
gsc_error("bad hud anchor x value: %lld", inst, false, val);
|
||||
elem.anchor_x = HUD_ALIGN_X_LEFT;
|
||||
}
|
||||
else {
|
||||
elem.anchor_x = (hud_elem_align_x)val;
|
||||
}
|
||||
}
|
||||
else {
|
||||
elem.anchor_x = HUD_ALIGN_X_LEFT;
|
||||
}
|
||||
|
||||
if (params > 6)
|
||||
{
|
||||
int64_t val = game::ScrVm_GetInt(inst, 6);
|
||||
|
||||
if (val >= 0 && val > HUD_ALIGN_Y_MAX)
|
||||
{
|
||||
gsc_error("bad hud anchor y value: %lld", inst, false, val);
|
||||
elem.anchor_y = HUD_ALIGN_Y_TOP;
|
||||
}
|
||||
else {
|
||||
elem.anchor_y = (hud_elem_align_y)val;
|
||||
}
|
||||
}
|
||||
else {
|
||||
elem.anchor_y = HUD_ALIGN_Y_TOP;
|
||||
}
|
||||
|
||||
if (params > 7)
|
||||
{
|
||||
int64_t val = game::ScrVm_GetInt(inst, 7);
|
||||
|
||||
if (val >= 0 && val > HUD_ALIGN_X_MAX)
|
||||
{
|
||||
gsc_error("bad hud align x value: %lld", inst, false, val);
|
||||
elem.align_x = HUD_ALIGN_X_LEFT;
|
||||
}
|
||||
else {
|
||||
elem.align_x = (hud_elem_align_x)val;
|
||||
}
|
||||
}
|
||||
else {
|
||||
elem.align_x = HUD_ALIGN_X_LEFT;
|
||||
}
|
||||
|
||||
if (params > 8)
|
||||
{
|
||||
int64_t val = game::ScrVm_GetInt(inst, 8);
|
||||
|
||||
if (val >= 0 && val > HUD_ALIGN_Y_MAX)
|
||||
{
|
||||
gsc_error("bad hud align y value: %lld", inst, false, val);
|
||||
elem.align_y = HUD_ALIGN_Y_TOP;
|
||||
}
|
||||
else {
|
||||
elem.align_y = (hud_elem_align_y)val;
|
||||
}
|
||||
}
|
||||
else {
|
||||
elem.align_y = HUD_ALIGN_Y_TOP;
|
||||
}
|
||||
|
||||
if (params > 9)
|
||||
{
|
||||
float val = game::ScrVm_GetFloat(inst, 9);
|
||||
|
||||
if (val >= 0.01)
|
||||
{
|
||||
elem.scale = val;
|
||||
}
|
||||
else {
|
||||
gsc_error("bad scale value: %f", inst, false, val);
|
||||
elem.scale = 1.0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
elem.scale = 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
void shield_remove_hud_elem(game::scriptInstance_t inst)
|
||||
{
|
||||
game::BO4_AssetRef_t hashRef{};
|
||||
|
||||
hud_elems.erase(game::ScrVm_GetHash(&hashRef, inst, 0)->hash);
|
||||
}
|
||||
|
||||
void shield_hud_elem_set_text(game::scriptInstance_t inst)
|
||||
{
|
||||
game::BO4_AssetRef_t hashRef{};
|
||||
|
||||
uint64_t id = game::ScrVm_GetHash(&hashRef, inst, 0)->hash;
|
||||
auto it = hud_elems.find(id);
|
||||
|
||||
if (it == hud_elems.end())
|
||||
{
|
||||
gsc_error("can't find hud element with id 0x%llx", inst, false, id);
|
||||
return;
|
||||
}
|
||||
|
||||
it->second.text = game::ScrVm_GetString(inst, 1);
|
||||
}
|
||||
|
||||
void shield_hud_elem_set_x(game::scriptInstance_t inst)
|
||||
{
|
||||
game::BO4_AssetRef_t hashRef{};
|
||||
|
||||
uint64_t id = game::ScrVm_GetHash(&hashRef, inst, 0)->hash;
|
||||
auto it = hud_elems.find(id);
|
||||
|
||||
if (it == hud_elems.end())
|
||||
{
|
||||
gsc_error("can't find hud element with id 0x%llx", inst, false, id);
|
||||
return;
|
||||
}
|
||||
|
||||
it->second.x = game::ScrVm_GetFloat(inst, 1);
|
||||
}
|
||||
|
||||
void shield_hud_elem_set_y(game::scriptInstance_t inst)
|
||||
{
|
||||
game::BO4_AssetRef_t hashRef{};
|
||||
|
||||
uint64_t id = game::ScrVm_GetHash(&hashRef, inst, 0)->hash;
|
||||
auto it = hud_elems.find(id);
|
||||
|
||||
if (it == hud_elems.end())
|
||||
{
|
||||
gsc_error("can't find hud element with id 0x%llx", inst, false, id);
|
||||
return;
|
||||
}
|
||||
|
||||
float val = game::ScrVm_GetFloat(inst, 1);
|
||||
if (val >= 0.01)
|
||||
{
|
||||
it->second.y = val;
|
||||
}
|
||||
else {
|
||||
gsc_error("bad scale value: %f", inst, false, val);
|
||||
}
|
||||
}
|
||||
|
||||
void shield_hud_elem_set_color(game::scriptInstance_t inst)
|
||||
{
|
||||
game::BO4_AssetRef_t hashRef{};
|
||||
|
||||
uint64_t id = game::ScrVm_GetHash(&hashRef, inst, 0)->hash;
|
||||
auto it = hud_elems.find(id);
|
||||
|
||||
if (it == hud_elems.end())
|
||||
{
|
||||
gsc_error("can't find hud element with id 0x%llx", inst, false, id);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
hud_elem& elem = it->second;
|
||||
uint32_t params = game::ScrVm_GetNumParam(inst);
|
||||
|
||||
if (params == 2)
|
||||
{
|
||||
game::ScrVarType_t type = game::ScrVm_GetType(inst, 1);
|
||||
if (type == game::TYPE_VECTOR)
|
||||
{
|
||||
game::vec3_t vec{};
|
||||
game::ScrVm_GetVector(inst, 1, &vec);
|
||||
|
||||
elem.color[0] = vec[0];
|
||||
elem.color[1] = vec[1];
|
||||
elem.color[2] = vec[2];
|
||||
|
||||
}
|
||||
else if (type == game::TYPE_INTEGER)
|
||||
{
|
||||
elem.set_color_rgba((uint32_t)game::ScrVm_GetInt(inst, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
gsc_error("ShieldHudElemSetColor used with bad type %d", inst, false, type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (params == 4)
|
||||
{
|
||||
bool float_based = game::ScrVm_GetType(inst, 1) == game::TYPE_FLOAT || game::ScrVm_GetType(inst, 2) == game::TYPE_FLOAT || game::ScrVm_GetType(inst, 3) == game::TYPE_FLOAT;
|
||||
bool int_based = game::ScrVm_GetType(inst, 1) == game::TYPE_INTEGER || game::ScrVm_GetType(inst, 2) == game::TYPE_INTEGER || game::ScrVm_GetType(inst, 3) == game::TYPE_INTEGER;
|
||||
|
||||
if (float_based && int_based)
|
||||
{
|
||||
gsc_error("ShieldHudElemSetColor should be used with only integers or floats", inst, false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (float_based)
|
||||
{
|
||||
elem.color[0] = game::ScrVm_GetFloat(inst, 1);
|
||||
elem.color[1] = game::ScrVm_GetFloat(inst, 2);
|
||||
elem.color[2] = game::ScrVm_GetFloat(inst, 3);
|
||||
} else
|
||||
{
|
||||
elem.color[0] = (game::vec_t)game::ScrVm_GetInt(inst, 1) / 0x100;
|
||||
elem.color[1] = (game::vec_t)game::ScrVm_GetInt(inst, 2) / 0x100;
|
||||
elem.color[2] = (game::vec_t)game::ScrVm_GetInt(inst, 3) / 0x100;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
gsc_error("usage of ShieldHudElemSetColor with a bad number of params", inst, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void shield_hud_elem_set_scale(game::scriptInstance_t inst)
|
||||
{
|
||||
game::BO4_AssetRef_t hashRef{};
|
||||
|
||||
uint64_t id = game::ScrVm_GetHash(&hashRef, inst, 0)->hash;
|
||||
auto it = hud_elems.find(id);
|
||||
|
||||
if (it == hud_elems.end())
|
||||
{
|
||||
gsc_error("can't find hud element with id 0x%llx", inst, false, id);
|
||||
return;
|
||||
}
|
||||
|
||||
it->second.scale = game::ScrVm_GetFloat(inst, 1);
|
||||
}
|
||||
|
||||
game::BO4_BuiltinFunctionDef custom_functions_gsc[] =
|
||||
{
|
||||
{ // ShieldLog(message)
|
||||
.canonId = canon_hash("ShieldLog"),
|
||||
.min_args = 1,
|
||||
.max_args = 1,
|
||||
.actionFunc = shield_log,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldClearHudElems()
|
||||
.canonId = canon_hash("ShieldClearHudElems"),
|
||||
.min_args = 0,
|
||||
.max_args = 0,
|
||||
.actionFunc = shield_clear_hud_elems,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldRegisterHudElem(id, text = "", color = 0xFFFFFFFF, x = 0, y = 0, anchor_x = 0, anchor_y = 0, align_x = 0, align_y = 0, scale = 1.0)
|
||||
.canonId = canon_hash("ShieldRegisterHudElem"),
|
||||
.min_args = 1,
|
||||
.max_args = 10,
|
||||
.actionFunc = shield_register_hud_elem,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldRemoveHudElem(id)
|
||||
.canonId = canon_hash("ShieldRemoveHudElem"),
|
||||
.min_args = 1,
|
||||
.max_args = 1,
|
||||
.actionFunc = shield_remove_hud_elem,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldHudElemSetText(id, text)
|
||||
.canonId = canon_hash("ShieldHudElemSetText"),
|
||||
.min_args = 2,
|
||||
.max_args = 2,
|
||||
.actionFunc = shield_hud_elem_set_text,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldHudElemSetX(id, x)
|
||||
.canonId = canon_hash("ShieldHudElemSetX"),
|
||||
.min_args = 2,
|
||||
.max_args = 2,
|
||||
.actionFunc = shield_hud_elem_set_x,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldHudElemSetY(id, y)
|
||||
.canonId = canon_hash("ShieldHudElemSetY"),
|
||||
.min_args = 2,
|
||||
.max_args = 2,
|
||||
.actionFunc = shield_hud_elem_set_y,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldHudElemSetY(id, color_vec) | ShieldHudElemSetY(id, color_rgba) | ShieldHudElemSetY(id, r, g, b)
|
||||
.canonId = canon_hash("ShieldHudElemSetColor"),
|
||||
.min_args = 2,
|
||||
.max_args = 4,
|
||||
.actionFunc = shield_hud_elem_set_color,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldHudElemSetY(id, scale)
|
||||
.canonId = canon_hash("ShieldHudElemSetScale"),
|
||||
.min_args = 2,
|
||||
.max_args = 2,
|
||||
.actionFunc = shield_hud_elem_set_scale,
|
||||
.type = 0,
|
||||
}
|
||||
};
|
||||
game::BO4_BuiltinFunctionDef custom_functions_csc[] =
|
||||
{
|
||||
{ // ShieldLog(message)
|
||||
.canonId = canon_hash("ShieldLog"),
|
||||
.min_args = 1,
|
||||
.max_args = 1,
|
||||
.actionFunc = shield_log,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldClearHudElems()
|
||||
.canonId = canon_hash("ShieldClearHudElems"),
|
||||
.min_args = 0,
|
||||
.max_args = 0,
|
||||
.actionFunc = shield_clear_hud_elems,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldRegisterHudElem(id, text = "", color = 0xFFFFFFFF, x = 0, y = 0, anchor_x = 0, anchor_y = 0, align_x = 0, align_y = 0, scale = 1.0)
|
||||
.canonId = canon_hash("ShieldRegisterHudElem"),
|
||||
.min_args = 1,
|
||||
.max_args = 10,
|
||||
.actionFunc = shield_register_hud_elem,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldRemoveHudElem(id)
|
||||
.canonId = canon_hash("ShieldRemoveHudElem"),
|
||||
.min_args = 1,
|
||||
.max_args = 1,
|
||||
.actionFunc = shield_remove_hud_elem,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldHudElemSetText(id, text)
|
||||
.canonId = canon_hash("ShieldHudElemSetText"),
|
||||
.min_args = 2,
|
||||
.max_args = 2,
|
||||
.actionFunc = shield_hud_elem_set_text,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldHudElemSetX(id, x)
|
||||
.canonId = canon_hash("ShieldHudElemSetX"),
|
||||
.min_args = 2,
|
||||
.max_args = 2,
|
||||
.actionFunc = shield_hud_elem_set_x,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldHudElemSetY(id, y)
|
||||
.canonId = canon_hash("ShieldHudElemSetY"),
|
||||
.min_args = 2,
|
||||
.max_args = 2,
|
||||
.actionFunc = shield_hud_elem_set_y,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldHudElemSetY(id, color_vec) | ShieldHudElemSetY(id, color_rgba) | ShieldHudElemSetY(id, r, g, b)
|
||||
.canonId = canon_hash("ShieldHudElemSetColor"),
|
||||
.min_args = 2,
|
||||
.max_args = 4,
|
||||
.actionFunc = shield_hud_elem_set_color,
|
||||
.type = 0,
|
||||
},
|
||||
{ // ShieldHudElemSetY(id, scale)
|
||||
.canonId = canon_hash("ShieldHudElemSetScale"),
|
||||
.min_args = 2,
|
||||
.max_args = 2,
|
||||
.actionFunc = shield_hud_elem_set_scale,
|
||||
.type = 0,
|
||||
}
|
||||
};
|
||||
|
||||
void draw_hud()
|
||||
{
|
||||
const game::vec_t screen_width = game::ScrPlace_GetView(0)->realViewportSize[0];
|
||||
const game::vec_t screen_height = game::ScrPlace_GetView(0)->realViewportSize[1];
|
||||
|
||||
if (game::Com_IsRunningUILevel())
|
||||
{
|
||||
// clear huds
|
||||
hud_elems.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// render huds
|
||||
void* font = reinterpret_cast<void*>(game::sharedUiInfo->assets.bigFont);
|
||||
if (!font) return;
|
||||
|
||||
for (auto& [id, elem] : hud_elems)
|
||||
{
|
||||
const char* text = elem.text.c_str();
|
||||
int height = game::UI_TextHeight(font, elem.scale);
|
||||
int width = game::UI_TextWidth(0, text, 0x7FFFFFFF, font, elem.scale);
|
||||
float rx = elem.get_relative_x(screen_width, (float)width);
|
||||
float ry = elem.get_relative_y(screen_height, (float)height) + height;
|
||||
|
||||
game::R_AddCmdDrawText(text, 0x7FFFFFFF, font, rx, ry, elem.scale, elem.scale, 0.0f, elem.color, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool enable_dev_func = false;
|
||||
|
||||
utilities::hook::detour scr_get_function_reverse_lookup;
|
||||
utilities::hook::detour cscr_get_function_reverse_lookup;
|
||||
utilities::hook::detour scr_get_function;
|
||||
utilities::hook::detour cscr_get_function;
|
||||
utilities::hook::detour scr_get_method;
|
||||
utilities::hook::detour cscr_get_method;
|
||||
utilities::hook::detour scrvm_error;
|
||||
|
||||
bool scr_get_function_reverse_lookup_stub(void* func, uint32_t* hash, bool* isFunction)
|
||||
{
|
||||
if (scr_get_function_reverse_lookup.invoke<bool>(func, hash, isFunction))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
auto f = std::find_if(std::begin(custom_functions_gsc), std::end(custom_functions_gsc), [func](const game::BO4_BuiltinFunctionDef& def) { return def.actionFunc == func; });
|
||||
|
||||
if (f != std::end(custom_functions_gsc))
|
||||
{
|
||||
*hash = f->canonId;
|
||||
*isFunction = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
bool cscr_get_function_reverse_lookup_stub(void* func, uint32_t* hash, bool* isFunction)
|
||||
{
|
||||
if (cscr_get_function_reverse_lookup.invoke<bool>(func, hash, isFunction))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
auto f = std::find_if(std::begin(custom_functions_csc), std::end(custom_functions_csc), [func](const game::BO4_BuiltinFunctionDef& def) { return def.actionFunc == func; });
|
||||
|
||||
if (f != std::end(custom_functions_csc))
|
||||
{
|
||||
*hash = f->canonId;
|
||||
*isFunction = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void* scr_get_function_stub(uint32_t name, int32_t* type, int32_t* min_args, int32_t* max_args)
|
||||
{
|
||||
void* func = scr_get_function.invoke<void*>(name, type, min_args, max_args);
|
||||
|
||||
if (enable_dev_func)
|
||||
{
|
||||
*type = 0;
|
||||
}
|
||||
|
||||
if (func)
|
||||
{
|
||||
return func;
|
||||
}
|
||||
|
||||
auto f = std::find_if(std::begin(custom_functions_gsc), std::end(custom_functions_gsc), [name](const game::BO4_BuiltinFunctionDef& func) { return func.canonId == name; });
|
||||
|
||||
if (f != std::end(custom_functions_gsc))
|
||||
{
|
||||
*type = f->type && !enable_dev_func;
|
||||
*min_args = f->min_args;
|
||||
*max_args = f->max_args;
|
||||
|
||||
return f->actionFunc;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
void* cscr_get_function_stub(uint32_t name, int32_t* type, int32_t* min_args, int32_t* max_args)
|
||||
{
|
||||
void* func = cscr_get_function.invoke<void*>(name, type, min_args, max_args);
|
||||
|
||||
if (enable_dev_func)
|
||||
{
|
||||
*type = 0;
|
||||
}
|
||||
|
||||
if (func)
|
||||
{
|
||||
return func;
|
||||
}
|
||||
|
||||
auto f = std::find_if(std::begin(custom_functions_csc), std::end(custom_functions_csc), [name](const game::BO4_BuiltinFunctionDef& func) { return func.canonId == name; });
|
||||
|
||||
if (f != std::end(custom_functions_csc))
|
||||
{
|
||||
*type = f->type && !enable_dev_func;
|
||||
*min_args = f->min_args;
|
||||
*max_args = f->max_args;
|
||||
|
||||
return f->actionFunc;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
void* scr_get_method_stub(uint32_t name, int32_t* type, int32_t* min_args, int32_t* max_args)
|
||||
{
|
||||
void* func = scr_get_method.invoke<void*>(name, type, min_args, max_args);
|
||||
|
||||
if (enable_dev_func)
|
||||
{
|
||||
*type = 0;
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
void* cscr_get_method_stub(uint32_t name, int32_t* type, int32_t* min_args, int32_t* max_args)
|
||||
{
|
||||
void* func = cscr_get_method.invoke<void*>(name, type, min_args, max_args);
|
||||
|
||||
if (enable_dev_func)
|
||||
{
|
||||
*type = 0;
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
void scrvm_error_stub(uint64_t code, game::scriptInstance_t inst, char* unused, bool terminal)
|
||||
{
|
||||
static char buffer[game::scriptInstance_t::SCRIPTINSTANCE_MAX][0x200] = { 0 };
|
||||
|
||||
// reimplement assert/assertmsg/errormsg functions
|
||||
switch (code)
|
||||
{
|
||||
case 2737681163:// Assert(val, msg) with message error
|
||||
{
|
||||
const char* msg = game::ScrVm_GetString(inst, 1);
|
||||
sprintf_s(buffer[inst], "assert fail: %s", msg);
|
||||
game::scrVarPub[inst]->error_message = buffer[inst];
|
||||
}
|
||||
break;
|
||||
case 1385570291:// AssertMsg(msg)
|
||||
{
|
||||
const char* msg = game::ScrVm_GetString(inst, 0);
|
||||
sprintf_s(buffer[inst], "assert fail: %s", msg);
|
||||
game::scrVarPub[inst]->error_message = buffer[inst];
|
||||
}
|
||||
break;
|
||||
case 2532286589:// ErrorMsg(msg)
|
||||
{
|
||||
const char* msg = game::ScrVm_GetString(inst, 0);
|
||||
sprintf_s(buffer[inst], "error: %s", msg);
|
||||
game::scrVarPub[inst]->error_message = buffer[inst];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// put custom message for our id
|
||||
if (code == custom_error_id)
|
||||
{
|
||||
game::scrVarPub[inst]->error_message = unused;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
logger::write(terminal ? logger::LOG_TYPE_ERROR : logger::LOG_TYPE_WARN, "[ %s VM ] %s (%lld)",
|
||||
inst ? "CSC" : "GSC", game::scrVarPub[inst]->error_message ? game::scrVarPub[inst]->error_message : "no message", code);
|
||||
|
||||
scrvm_error.invoke<void>(code, inst, unused, terminal);
|
||||
}
|
||||
|
||||
void scrvm_log_compiler_error(const char* fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
char buffer[0x800];
|
||||
|
||||
int e = vsprintf_s(buffer, fmt, va);
|
||||
va_end(va);
|
||||
|
||||
if (e > 0 && buffer[e - 1] == '\n')
|
||||
{
|
||||
buffer[e - 1] = 0; // remove end new line
|
||||
}
|
||||
|
||||
std::string str{ buffer };
|
||||
|
||||
logger::write(logger::LOG_TYPE_ERROR, str);
|
||||
}
|
||||
|
||||
class component final : public component_interface
|
||||
{
|
||||
public:
|
||||
void post_unpack() override
|
||||
{
|
||||
// enable dev functions still available in the game
|
||||
enable_dev_func = utilities::json_config::ReadBoolean("gsc", "dev_funcs", false);
|
||||
|
||||
scr_get_function_reverse_lookup.create(0x1433AF8A0_g, scr_get_function_reverse_lookup_stub);
|
||||
cscr_get_function_reverse_lookup.create(0x141F132A0_g, cscr_get_function_reverse_lookup_stub);
|
||||
cscr_get_function.create(0x141F13140_g, cscr_get_function_stub);
|
||||
cscr_get_method.create(0x141F13650_g, cscr_get_method_stub);
|
||||
scr_get_function.create(0x1433AF840_g, scr_get_function_stub);
|
||||
scr_get_method.create(0x1433AFC20_g, scr_get_method_stub);
|
||||
|
||||
// log gsc errors
|
||||
scrvm_error.create(0x142770330_g, scrvm_error_stub);
|
||||
utilities::hook::jump(0x142890470_g, scrvm_log_compiler_error);
|
||||
|
||||
scheduler::loop(draw_hud, scheduler::renderer);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
REGISTER_COMPONENT(gsc_funcs::component)
|
12
source/proxy-dll/component/gsc_funcs.hpp
Normal file
12
source/proxy-dll/component/gsc_funcs.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include <std_include.hpp>
|
||||
#include "definitions/game.hpp"
|
||||
|
||||
namespace gsc_funcs
|
||||
{
|
||||
uint32_t canon_hash(const char* str);
|
||||
|
||||
constexpr uint64_t custom_error_id = 0x42693201;
|
||||
|
||||
void gsc_error(const char* message, game::scriptInstance_t inst, bool terminal, ...);
|
||||
}
|
@ -17,6 +17,8 @@ namespace game
|
||||
typedef vec_t vec3_t[3];
|
||||
typedef vec_t vec4_t[4];
|
||||
|
||||
typedef uint32_t ScrVarIndex_t;
|
||||
typedef uint64_t ScrVarNameIndex_t;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// STRUCTS //
|
||||
@ -37,6 +39,83 @@ namespace game
|
||||
return m128i;
|
||||
}
|
||||
|
||||
enum scriptInstance_t : int32_t
|
||||
{
|
||||
SCRIPTINSTANCE_SERVER = 0x0,
|
||||
SCRIPTINSTANCE_CLIENT = 0x1,
|
||||
SCRIPTINSTANCE_MAX = 0x2,
|
||||
};
|
||||
|
||||
typedef void (*BuiltinFunction)(scriptInstance_t);
|
||||
|
||||
struct BO4_BuiltinFunctionDef
|
||||
{
|
||||
uint32_t canonId;
|
||||
uint32_t min_args;
|
||||
uint32_t max_args;
|
||||
BuiltinFunction actionFunc;
|
||||
uint32_t type;
|
||||
};
|
||||
|
||||
struct __declspec(align(4)) BO4_scrVarGlobalVars_t
|
||||
{
|
||||
uint32_t name;
|
||||
ScrVarIndex_t id;
|
||||
bool persist;
|
||||
};
|
||||
|
||||
|
||||
enum ScrVarType_t : uint32_t {
|
||||
TYPE_UNDEFINED = 0x0,
|
||||
TYPE_POINTER = 0x1,
|
||||
TYPE_STRING = 0x2,
|
||||
TYPE_VECTOR = 0x3,
|
||||
TYPE_HASH = 0x4,
|
||||
TYPE_FLOAT = 0x5,
|
||||
TYPE_INTEGER = 0x6,
|
||||
TYPE_UINTPTR = 0x7,
|
||||
TYPE_ENTITY_OFFSET = 0x8,
|
||||
TYPE_CODEPOS = 0x9,
|
||||
TYPE_PRECODEPOS = 0xA,
|
||||
TYPE_API_FUNCTION = 0xB,
|
||||
TYPE_SCRIPT_FUNCTION = 0xC,
|
||||
TYPE_STACK = 0xD,
|
||||
TYPE_THREAD = 0xE,
|
||||
TYPE_NOTIFY_THREAD = 0xF,
|
||||
TYPE_TIME_THREAD = 0x10,
|
||||
TYPE_FRAME_THREAD = 0x11,
|
||||
TYPE_CHILD_THREAD = 0x12,
|
||||
TYPE_CLASS = 0x13,
|
||||
TYPE_SHARED_STRUCT = 0x14,
|
||||
TYPE_STRUCT = 0x15,
|
||||
TYPE_REMOVED_ENTITY = 0x16,
|
||||
TYPE_ENTITY = 0x17,
|
||||
TYPE_ARRAY = 0x18,
|
||||
TYPE_REMOVED_THREAD = 0x19,
|
||||
TYPE_FREE = 0x1a,
|
||||
TYPE_THREAD_LIST = 0x1b,
|
||||
TYPE_ENT_LIST = 0x1c
|
||||
};
|
||||
|
||||
|
||||
struct BO4_scrVarPub {
|
||||
const char* fieldBuffer;
|
||||
const char* error_message;
|
||||
byte* programBuffer;
|
||||
byte* endScriptBuffer;
|
||||
byte* programHunkUser; // HunkUser
|
||||
BO4_scrVarGlobalVars_t globalVars[16];
|
||||
ScrVarNameIndex_t entFieldNameIndex;
|
||||
ScrVarIndex_t freeEntList;
|
||||
ScrVarIndex_t tempVariable;
|
||||
uint32_t checksum;
|
||||
uint32_t entId;
|
||||
uint32_t varHighWatermark;
|
||||
uint32_t numScriptThreads;
|
||||
uint32_t numVarAllocations;
|
||||
int32_t varHighWatermarkId;
|
||||
};
|
||||
|
||||
enum keyNum_t
|
||||
{
|
||||
K_NONE = 0x00,
|
||||
@ -489,12 +568,36 @@ namespace game
|
||||
WEAK symbol<ScreenPlacement* (int localClientNum)> ScrPlace_GetView{ 0x142876E70_g };
|
||||
|
||||
WEAK symbol<bool()> Com_IsInGame{ 0x14288FDB0_g };
|
||||
WEAK symbol<bool()> Com_IsRunningUILevel{ 0x14288FDF0_g };
|
||||
|
||||
WEAK symbol<int> keyCatchers{ 0x148A53F84_g };
|
||||
WEAK symbol<PlayerKeyState> playerKeys{ 0x148A3EF80_g };
|
||||
|
||||
WEAK symbol<sharedUiInfo_t> sharedUiInfo{ 0x14F956850_g };
|
||||
|
||||
// Scr Functions
|
||||
|
||||
WEAK symbol<void(scriptInstance_t inst, int value)> ScrVm_AddBool{ 0x14276E760_g };
|
||||
WEAK symbol<void(scriptInstance_t inst, float value)> ScrVm_AddFloat{ 0x14276E9B0_g };
|
||||
WEAK symbol<void(scriptInstance_t inst, BO4_AssetRef_t* value)> ScrVm_AddHash{ 0x14276EAB0_g };
|
||||
WEAK symbol<void(scriptInstance_t inst, int64_t value)> ScrVm_AddInt{ 0x14276EB80_g };
|
||||
WEAK symbol<void(scriptInstance_t inst, const char* value) > ScrVm_AddString{ 0x14276EE30_g };
|
||||
WEAK symbol<void(scriptInstance_t inst)> ScrVm_AddUndefined{ 0x14276F3C0_g };
|
||||
WEAK symbol<void(scriptInstance_t inst, int32_t value)> ScrVm_AddConstString{ 0x14276E5F0_g };
|
||||
WEAK symbol<bool(scriptInstance_t inst, unsigned int index)> ScrVm_GetBool{ 0x142772AB0_g };
|
||||
WEAK symbol<float(scriptInstance_t inst, unsigned int index)> ScrVm_GetFloat{ 0x1427733F0_g };
|
||||
WEAK symbol<BO4_AssetRef_t* (BO4_AssetRef_t* hash, scriptInstance_t inst, unsigned int index)> ScrVm_GetHash{ 0x1427738E0_g };
|
||||
WEAK symbol<int64_t(scriptInstance_t inst, unsigned int index)> ScrVm_GetInt{ 0x142773B50_g };
|
||||
WEAK symbol<const char*(scriptInstance_t inst, unsigned int index)> ScrVm_GetString{ 0x142774840_g };
|
||||
WEAK symbol<void(scriptInstance_t inst, unsigned int index, vec3_t* vector)> ScrVm_GetVector{ 0x142774E40_g };
|
||||
WEAK symbol<int32_t(scriptInstance_t inst, unsigned int index)> ScrVm_GetConstString{ 0x142772E10_g };
|
||||
WEAK symbol<uint32_t(scriptInstance_t inst)> ScrVm_GetNumParam{ 0x142774440_g };
|
||||
WEAK symbol<ScrVarType_t(scriptInstance_t inst, unsigned int index)> ScrVm_GetPointerType{ 0x1427746E0_g };
|
||||
WEAK symbol<ScrVarType_t(scriptInstance_t inst, unsigned int index)> ScrVm_GetType{ 0x142774A20_g };
|
||||
|
||||
WEAK symbol<void(uint64_t code, scriptInstance_t inst, char* unused, bool terminal)> ScrVm_Error{ 0x142770330_g };
|
||||
WEAK symbol<BO4_scrVarPub[scriptInstance_t::SCRIPTINSTANCE_MAX]> scrVarPub{ 0x148307880_g };
|
||||
|
||||
|
||||
#define R_AddCmdDrawText(TXT, MC, F, X, Y, XS, YS, R, C, S) \
|
||||
T8_AddBaseDrawTextCmd(TXT, MC, F, X, Y, XS, YS, R, C, S, -1, 0, 0)
|
||||
|
Loading…
Reference in New Issue
Block a user