Mapents & scripting changes + some fixes

This commit is contained in:
Federico Cecchetto 2022-06-30 21:24:49 +02:00
parent c71c20a29a
commit a63ce4f254
8 changed files with 337 additions and 34 deletions

View File

@ -63,15 +63,22 @@ namespace asset_list
ImGui::InputText("asset name", &assets_name_filter[type]);
ImGui::BeginChild("assets list");
fastfiles::enum_assets(type, [type](const game::XAssetHeader header)
size_t asset_num{};
fastfiles::enum_assets(type, [type, &asset_num](const game::XAssetHeader header)
{
const auto asset = game::XAsset{type, header};
const auto* const asset_name = game::DB_GetXAssetName(&asset);
auto asset_name = game::DB_GetXAssetName(&asset);
if (asset_name[0] == '\0')
{
asset_name = utils::string::va("__%i", asset_num);
}
if (utils::string::strstr_lower(asset_name, assets_name_filter[type].data()) && ImGui::Button(asset_name))
{
gui::copy_to_clipboard(asset_name);
}
asset_num++;
}, true);
ImGui::EndChild();

View File

@ -9,6 +9,7 @@
#include "scheduler.hpp"
#include "mapents.hpp"
#include "command.hpp"
#include "game/scripting/functions.hpp"
#include <utils/hook.hpp>
#include <utils/concurrency.hpp>
@ -22,7 +23,7 @@ namespace mapents
game::dvar_t* addon_mapname = nullptr;
utils::memory::allocator allocator;
std::unordered_map<std::string, int> keys =
std::unordered_map<std::string, unsigned int> keys =
{
{"code_classname", 172},
{"classname", 170},
@ -50,7 +51,7 @@ namespace mapents
{"skycolor", 34255},
{"suncolor", 1049},
{"sundirection", 1050},
{"modelscale", 23881},
{"export", 13703},
{"script_flag", 31190},
@ -72,8 +73,15 @@ namespace mapents
{"script_parameters", 31388},
{"script_combatmode", 31102},
{"script_ammo_clip", 31034},
{"script_moveoverride", 31299},
{"script_forcegoal", 31212},
{"script_ammo_max", 31036},
};
std::unordered_map<unsigned int, game::scriptType_e> custom_fields;
unsigned int token_id_start = 0x16000;
// zonetool/iw4/addonmapents.cpp
class asset_reader
{
@ -202,29 +210,27 @@ namespace mapents
empty = false;
auto key_id = 0;
if (key[0] != '"')
auto key_id = std::atoi(key.data());
if (key_id != 0)
{
key_id = std::atoi(key.data());
out_buffer.append(utils::string::va("%i \"%s\"\n", key_id, value.data()));
continue;
}
else if (key.size() >= 3 && key[key.size() - 1] == '"')
{
const auto key_ = key.substr(1, key.size() - 2);
if (keys.find(key_) == keys.end())
{
console::warn("[addon_map_ents parser] Key '%s' not found, on line %i", key_.data(), line_index);
continue;
}
key_id = keys[key_];//
}
else
if (key.size() < 3 || (!key.starts_with("\"") || !key.ends_with("\"")))
{
console::warn("[addon_map_ents parser] Bad key '%s' on line %i", key.data(), line_index);
continue;
}
out_buffer.append(utils::string::va("%i \"%s\"\n", key_id, value.data()));
const auto key_ = key.substr(1, key.size() - 2);
if (keys.find(key_) == keys.end())
{
console::warn("[addon_map_ents parser] Key '%s' not found, on line %i", key_.data(), line_index);
continue;
}
out_buffer.append(utils::string::va("%i \"%s\"\n", keys[key_], value.data()));
}
return out_buffer;
@ -257,6 +263,7 @@ namespace mapents
void try_parse_mapents(const std::string& path, const std::string& data, game::AddonMapEnts* mapents)
{
const auto parsed = parse_mapents(data);
utils::io::write_file("parsed_mapents.txt", parsed, false);
mapents->entityString = allocator.duplicate_string(parsed.data());
mapents->numEntityChars = static_cast<int>(parsed.size()) + 1;
@ -316,6 +323,26 @@ namespace mapents
game::Com_Error(game::ERR_DROP, "CM_TriggerModelBounds: you are probably missing a mapents.triggers file");
}
}
void add_field(const std::string& name, game::scriptType_e type)
{
const auto id = token_id_start++;
custom_fields[id] = type;
keys[name] = id;
scripting::token_map[name] = id;
}
utils::hook::detour scr_find_field_hook;
unsigned int scr_find_field_stub(unsigned int name, game::scriptType_e* type)
{
if (custom_fields.find(name) != custom_fields.end())
{
*type = custom_fields[name];
return name;
}
return scr_find_field_hook.invoke<unsigned int>(name, type);
}
}
void clear_dvars()
@ -333,6 +360,8 @@ namespace mapents
public:
void post_unpack() override
{
scr_find_field_hook.create(0x1405C5240, scr_find_field_stub);
scheduler::once([]()
{
addon_mapname = dvars::register_string("addon_mapname", "", 0, "");
@ -365,6 +394,8 @@ namespace mapents
utils::hook::call(0x14058BDD3, db_find_xasset_header_stub);
utils::hook::call(0x14058BD6B, should_load_addon_mapents);
utils::hook::call(0x1406B3384, cm_trigger_model_bounds_stub);
add_field("script_specialops", game::SCRIPT_INTEGER);
}
};
}

View File

@ -5,7 +5,7 @@
namespace scripting
{
animation::animation(unsigned int value)
animation::animation(uint64_t value)
: value_(value)
{
}

View File

@ -7,7 +7,7 @@ namespace scripting
class animation final
{
public:
animation(unsigned int value);
animation(uint64_t value);
uint64_t get_value() const;
private:

View File

@ -39,6 +39,21 @@ namespace scripting
return script_value(game::scr_VmPub->top[1 - game::scr_VmPub->outparamcount]);
}
bool is_entity_variable(const game::scr_entref_t& entref, const unsigned int id)
{
const auto type = game::scr_VarGlob->objectVariableValue[id].w.type;
if (entref.classnum == 0)
{
return type == game::SCRIPT_ENTITY;
}
else if (entref.classnum > 0)
{
return true;
}
return false;
}
}
void push_value(const script_value& value)
@ -149,8 +164,9 @@ namespace scripting
{
const auto entref = entity.get_entity_reference();
const int id = get_field_id(entref.classnum, field);
const auto ent_id = entity.get_entity_id();
if (id != -1)
if (id != -1 && is_entity_variable(entref, ent_id))
{
stack_isolation _;
push_value(value);
@ -165,7 +181,7 @@ namespace scripting
}
else
{
set_object_variable(entity.get_entity_id(), field, value);
set_object_variable(ent_id, field, value);
}
}
@ -173,8 +189,9 @@ namespace scripting
{
const auto entref = entity.get_entity_reference();
const auto id = get_field_id(entref.classnum, field);
const auto ent_id = entity.get_entity_id();
if (id != -1)
if (id != -1 && is_entity_variable(entref, ent_id))
{
stack_isolation _;
@ -192,7 +209,7 @@ namespace scripting
return value;
}
return get_object_variable(entity.get_entity_id(), field);
return get_object_variable(ent_id, field);
}
unsigned int make_array()

View File

@ -411,9 +411,9 @@ namespace scripting
{"objective_delete", 0x1E4}, // 0x50FA30
{"objective_state", 0x1E5}, // 0x50EFD0
{"objective_icon", 0x1E6}, // 0x50F010
{"objective_position", 0x1E7}, // 0x50F110
{"objective_current", 0x1E8}, // 0x50F1B0
{"_func_1e9", 0x1E9}, // similar to objective_current_nomessage
{"_func_1e7", 0x1E7}, // 0x50F110
{"objective_position", 0x1E8}, // 0x50F1B0
{"objective_current", 0x1E9}, // similar to objective_current_nomessage
{"weaponinventorytype", 0x1EA}, // 0x4EE760
{"weaponstartammo", 0x1EB}, // 0x4EE920
{"weaponmaxammo", 0x1EC}, // 0x4EEB40
@ -1778,10 +1778,253 @@ namespace scripting
std::unordered_map<std::string, unsigned> token_map =
{
{"maps/_utility", 42407},
{"common_scripts/utility", 42237},
{"maps/_load", 42323},
{"maps/_compass", 42272},
{"maps/_spawner", 42372},
{"init", 521},
{"main", 616},
{"player", 794},
{"default_start", 10126},
{"maps/_utility", 42407},
{"setupminimap", 33575},
{"set_player_viewhand_model", 32417},
// built-in entity fields
{"code_classname", 172},
{"classname", 170},
{"model", 669},
{"count", 216},
{"health", 486},
{"dmg", 293},
{"maxhealth", 626},
{"anglelerprate", 64},
{"activator", 19},
{"slidevelocity", 974},
{"disableplayeradsloscheck", 291},
{"accuracy", 10},
{"lookforward", 604},
{"lookright", 605},
{"lookup", 607},
{"fovcosine", 411},
{"fovcosinebusy", 412},
{"fovcosinez", 413},
{"upaimlimit", 1252},
{"downaimlimit", 307},
{"rightaimlimit", 894},
{"leftaimlimit", 590},
{"maxsightdistsqrd", 628},
{"sightlatency", 967},
{"defaultsightlatency", 968},
{"ignoreclosefoliage", 508},
{"interval", 525},
{"teammovewaittime", 1199},
{"damagetaken", 257},
{"damagedir", 252},
{"damageyaw", 259},
{"damagelocation", 253},
{"damageweapon", 258},
{"damagemod", 254},
{"proneok", 841},
{"walkdistfacingmotion", 1299},
{"walkdist", 1298},
{"desiredangle", 278},
{"pacifist", 744},
{"pacifistwait", 745},
{"footstepdetectdist", 398},
{"footstepdetectdistwalk", 400},
{"footstepdetectdistsprint", 399},
{"reactiontargetpos", 859},
{"newenemyreactiondistsq", 686},
{"ignoreexplosionevents", 509},
{"ignoresuppression", 513},
{"suppressionwait", 1060},
{"suppressionduration", 1056},
{"suppressionstarttime", 1058},
{"suppressionmeter", 1057},
{"ignoreplayersuppression", 514},
{"name", 680},
{"weapon", 1302},
{"dontavoidplayer", 304},
{"grenadeawareness", 465},
{"grenade", 458},
{"grenadeweapon", 470},
{"grenadeammo", 464},
{"grenadetargetpos", 467},
{"grenadetargetvalid", 468},
{"grenadetossvel", 469},
{"favoriteenemy", 377},
{"highlyawareradius", 495},
{"minpaindamage", 642},
{"allowpain", 52},
{"allowdeath", 49},
{"delayeddeath", 274},
{"diequietly", 287},
{"forceragdollimmediate", 405},
{"providecoveringfire", 842},
{"doingambush", 302},
{"combatmode", 199},
{"alertlevel", 38},
{"alertlevelint", 39},
{"useable", 1257},
{"ignoretriggers", 515},
{"pushable", 846},
{"script_pushable", 926},
{"dropweapon", 309},
{"drawoncompass", 308},
{"groundtype", 474},
{"anim_pose", 68},
{"goalradius", 452},
{"goalheight", 450},
{"goalpos", 451},
{"nodeoffsetpos", 705},
{"ignoreforfixednodesafecheck", 510},
{"fixednode", 381},
{"fixednodesaferadius", 382},
{"pathgoalpos", 762},
{"pathrandompercent", 764},
{"usechokepoints", 1258},
{"stopanimdistsq", 1044},
{"lastenemysightpos", 584},
{"pathenemylookahead", 761},
{"pathenemyfightdist", 760},
{"meleeattackdist", 633},
{"movemode", 675},
{"script_move_distance_override", 31298},
{"usecombatscriptatcover", 1259},
{"safetochangescript", 906},
{"keepclaimednode", 561},
{"keepclaimednodeifvalid", 562},
{"keepnodeduringscriptedanim", 563},
{"dodangerreact", 295},
{"dangerreactduration", 260},
{"nododgemove", 706},
{"noteammove", 707},
{"leanamount", 587},
{"pitchamount", 788},
{"turnrate", 1230},
{"turnanimactive", 1229},
{"badplaceawareness", 107},
{"damageshield", 256},
{"nogrenadereturnthrow", 709},
{"noattackeraccuracymod", 698},
{"frontshieldanglecos", 426},
{"lookaheaddir", 601},
{"lookaheaddist", 602},
{"lookaheadhitsstairs", 603},
{"velocity", 1283},
{"prevanimdelta", 821},
{"exposedduration", 356},
{"requestarrivalnotify", 875},
{"scriptedarrivalent", 938},
{"goingtoruntopos", 455},
{"engagemindist", 334},
{"engageminfalloffdist", 335},
{"engagemaxdist", 332},
{"engagemaxfalloffdist", 333},
{"usingcovermoveup", 42987},
{"finalaccuracy", 378},
{"facemotion", 373},
{"gunblockedbywall", 475},
{"relativedir", 866},
{"lockorientation", 597},
{"maxfaceenemydist", 625},
{"stairsstate", 1012},
{"script", 912},
{"prevscript", 823},
{"headicon", 483},
{"headiconteam", 484},
{"coversearchinterval", 219},
{"threatupdateinterval", 37018},
{"canclimbladders", 150},
{"swimmer", 1063},
{"space", 986},
{"doghandler", 301},
{"sharpturnlookaheaddist", 961},
{"postsharpturnlookaheaddist", 813},
{"sharpturntooclosetodestdist", 963},
{"usepathsmoothingvalues", 1262},
{"pathlookaheaddist", 763},
{"maxturnspeed", 629},
{"sharpturn", 960},
{"disablesightandthreatupdate", 54743},
{"team", 1194},
{"threatbias", 1204},
{"threatbiasgroup", 1205},
{"node", 700},
{"prevnode", 822},
{"enemy", 322},
{"syncedmeleetarget", 1065},
{"lastattacker", 583},
{"lastpusher", 42997},
{"ignoreme", 511},
{"ignoreall", 507},
{"maxvisibledist", 630},
{"surprisedbymedistsq", 1062},
{"attackeraccuracy", 86},
{"ignorerandombulletdamage", 512},
{"dodamagetoall", 294},
{"turretinvulnerability", 1240},
{"useorcaavoidance", 1261},
{"reciprocality", 863},
{"avoidanceboundshalfsize", 94},
{"onlygoodnearestnodes", 735},
{"playername", 803},
{"deathinvulnerabletime", 266},
{"criticalbulletdamagedist", 222},
{"attackercount", 87},
{"damagemultiplier", 255},
{"laststand", 586},
{"motiontrackerenabled", 672},
{"veh_speed", 1276},
{"veh_pathspeed", 1273},
{"veh_transmission", 1279},
{"veh_pathdir", 1272},
{"veh_pathtype", 1274},
{"veh_topspeed", 1278},
{"veh_brake", 1266},
{"veh_throttle", 1277},
{"x", 1331},
{"y", 1339},
{"z", 1342},
{"fontscale", 393},
{"font", 392},
{"alignx", 44},
{"aligny", 45},
{"horzalign", 499},
{"vertalign", 1284},
{"color", 196},
{"alpha", 55},
{"label", 578},
{"sort", 983},
{"foreground", 408},
{"lowresbackground", 612},
{"hidewhendead", 491},
{"hidewheninmenu", 493},
{"glowcolor", 445},
{"glowalpha", 444},
{"positioninworld", 812},
{"relativeoffset", 867},
{"enablehudlighting", 315},
{"enableinputprogressicon", 42996},
{"rotation", 902},
{"targetname", 1193},
{"target", 1191},
{"animscript", 71},
{"script_linkname", 920},
{"script_noteworthy", 922},
{"origin", 740},
{"angles", 65},
{"minusedistsq", 643},
{"parentname", 749},
{"spawnflags", 989},
{"type", 1244},
{"owner", 743},
{"radius", 851},
{"customangles", 9555},
{"speed", 997},
{"lookahead", 600},
{"script_vehicle_anim", 40318},
};
}

View File

@ -326,6 +326,11 @@ namespace scripting::lua
return keys;
};
array_type["getentity"] = [](const array& array, const sol::this_state s)
{
return array.get_raw();
};
auto entity_type = state.new_usertype<entity>("entity");
for (const auto& func : method_map)

View File

@ -176,6 +176,11 @@ namespace scripting::lua
auto table = sol::table::create(state);
auto metatable = sol::table::create(state);
table["getentity"] = [parent_id]()
{
return entity(parent_id);
};
metatable[sol::meta_function::new_index] = [parent_id](const sol::table t, const sol::this_state s,
const sol::lua_value& field, const sol::lua_value& value)
{
@ -287,11 +292,6 @@ namespace scripting::lua
return {state, value.as<std::string>()};
}
if (value.is<std::map<std::string, script_value>>())
{
return entity_to_struct(state, value.get_raw().u.uintValue);
}
if (value.is<array>())
{
return {state, value.as<array>()};