Entity list fixes + add sharedget/set functions to ui/server scripting
This commit is contained in:
parent
ab027b7f3a
commit
019fed2baa
@ -21,11 +21,13 @@ namespace entity_list
|
||||
{
|
||||
enum entity_type
|
||||
{
|
||||
type_any,
|
||||
entity,
|
||||
actor,
|
||||
spawner,
|
||||
weapon,
|
||||
vehicle,
|
||||
node,
|
||||
vehicle_node,
|
||||
count,
|
||||
};
|
||||
|
||||
@ -49,7 +51,7 @@ namespace entity_list
|
||||
struct entity_info_t
|
||||
{
|
||||
unsigned int id;
|
||||
unsigned int num;
|
||||
game::scr_entref_t entref;
|
||||
std::unordered_map<std::string, std::string> fields;
|
||||
};
|
||||
|
||||
@ -278,7 +280,7 @@ namespace entity_list
|
||||
};
|
||||
|
||||
utils::concurrency::container<data_t> data_{};
|
||||
unsigned int selected_entity{};
|
||||
game::scr_entref_t selected_entity{};
|
||||
bool set_field_window{};
|
||||
bool selected_fields_window{};
|
||||
int selected_type = game::SCRIPT_INTEGER;
|
||||
@ -288,88 +290,60 @@ namespace entity_list
|
||||
std::string field_value_buffer{};
|
||||
std::string vector_input[3]{};
|
||||
|
||||
bool verify_entity(unsigned int id)
|
||||
{
|
||||
const auto type = game::scr_VarGlob->objectVariableValue[id].w.type;
|
||||
return type == game::SCRIPT_ENTITY;
|
||||
}
|
||||
|
||||
std::optional<scripting::array> get_entity_array(const entity_type type, const entity_team team)
|
||||
{
|
||||
const auto value = scripting::call("getentarray");
|
||||
if (!value.is<scripting::array>())
|
||||
if (type == entity_type::entity)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto all = value.as<scripting::array>();
|
||||
|
||||
if (type == entity_type::type_any)
|
||||
{
|
||||
return {all};
|
||||
return {scripting::call("getentarray").as<scripting::array>()};
|
||||
}
|
||||
|
||||
if (type == entity_type::actor)
|
||||
{
|
||||
scripting::array result{};
|
||||
|
||||
for (auto i = 0; i < all.size(); i++)
|
||||
const auto actors = scripting::call("getaiarray").as<scripting::array>();
|
||||
for (auto i = 0; i < actors.size(); i++)
|
||||
{
|
||||
const auto raw = all[i].get_raw();
|
||||
if (raw.type != game::SCRIPT_OBJECT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
const auto entity = actors[i].as<scripting::entity>();
|
||||
const auto team_string = entity.get("team").as<std::string>();
|
||||
|
||||
if (!verify_entity(raw.u.uintValue))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto entity = all[i].as<scripting::entity>();
|
||||
|
||||
const auto classname_value = entity.get("classname");
|
||||
if (!classname_value.is<std::string>())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto team_value = entity.get("team");
|
||||
if (!team_value.is<std::string>())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto classname = classname_value.as<std::string>();
|
||||
const auto team_ = team_value.as<std::string>();
|
||||
if (utils::string::find_lower(classname, "actor_") &&
|
||||
(team == entity_team::team_any || team_ == team_names[team]))
|
||||
if (team == entity_team::team_any || team_string == team_names[team])
|
||||
{
|
||||
result.push(entity);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return {result};
|
||||
}
|
||||
|
||||
if (type == entity_type::spawner && team == entity_team::team_any)
|
||||
{
|
||||
return scripting::call("getspawnerarray").as<scripting::array>();
|
||||
return {scripting::call("getspawnerarray").as<scripting::array>()};
|
||||
}
|
||||
|
||||
if (type == entity_type::spawner)
|
||||
{
|
||||
return scripting::call("getspawnerteamarray", {team_names[team]}).as<scripting::array>();
|
||||
return {scripting::call("getspawnerteamarray", {team_names[team]}).as<scripting::array>()};
|
||||
}
|
||||
|
||||
if (type == entity_type::weapon)
|
||||
{
|
||||
return scripting::call("getweaponarray").as<scripting::array>();
|
||||
return {scripting::call("getweaponarray").as<scripting::array>()};
|
||||
}
|
||||
|
||||
if (type == entity_type::node)
|
||||
{
|
||||
return scripting::call("getnodearray").as<scripting::array>();
|
||||
return {scripting::call("getallnodes").as<scripting::array>()};
|
||||
}
|
||||
|
||||
if (type == entity_type::vehicle_node)
|
||||
{
|
||||
return {scripting::call("getallvehiclenodes").as<scripting::array>()};
|
||||
}
|
||||
|
||||
if (type == entity_type::vehicle)
|
||||
{
|
||||
return {scripting::call("vehicle_getarray").as<scripting::array>()};
|
||||
}
|
||||
|
||||
return {};
|
||||
@ -404,29 +378,18 @@ namespace entity_list
|
||||
data.entity_info.clear();
|
||||
|
||||
const auto array = value.value();
|
||||
const scripting::entity player{{0, 0}};
|
||||
|
||||
for (auto i = 0; i < array.size(); i++)
|
||||
{
|
||||
const auto raw = array[i].get_raw();
|
||||
if (raw.type != game::SCRIPT_OBJECT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!verify_entity(raw.u.uintValue))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto entity = array[i].as<scripting::entity>();
|
||||
entity_info_t info{};
|
||||
|
||||
info.id = raw.u.uintValue;
|
||||
info.num = entity.get_entity_reference().entnum;
|
||||
info.id = entity.get_entity_id();
|
||||
info.entref = entity.get_entity_reference();
|
||||
|
||||
if (data.filters.filter_by_range)
|
||||
{
|
||||
const auto player = scripting::call("getentbynum", {0}).as<scripting::entity>();
|
||||
const auto distance = scripting::call("distance", {player.get("origin"), entity.get("origin")}).as<float>();
|
||||
|
||||
if (distance > data.filters.range)
|
||||
@ -472,60 +435,60 @@ namespace entity_list
|
||||
});
|
||||
}
|
||||
|
||||
void teleport_to(data_t& data, unsigned int num)
|
||||
void teleport_to(data_t& data, game::scr_entref_t entref)
|
||||
{
|
||||
data.tasks.push_back([num]()
|
||||
data.tasks.push_back([entref]()
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto entity = scripting::call("getentbynum", {num}).as<scripting::entity>();
|
||||
const auto player = scripting::call("getentbynum", {0}).as<scripting::entity>();
|
||||
const scripting::entity entity{entref};
|
||||
const scripting::entity player{{0, 0}};
|
||||
player.call("setorigin", {entity.get("origin")});
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
gui::notification("Error", utils::string::va("^1error teleporting player to entity num %i!", num));
|
||||
gui::notification("Error", utils::string::va("^1error teleporting player to entity num %i!", entref.entnum));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void teleport_to_reverse(data_t& data, unsigned int num)
|
||||
void teleport_to_reverse(data_t& data, game::scr_entref_t entref)
|
||||
{
|
||||
data.tasks.push_back([num]()
|
||||
data.tasks.push_back([entref]()
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto entity = scripting::call("getentbynum", {num}).as<scripting::entity>();
|
||||
const auto player = scripting::call("getentbynum", {0}).as<scripting::entity>();
|
||||
const scripting::entity entity{entref};
|
||||
const scripting::entity player{{0, 0}};
|
||||
entity.set("origin", player.get("origin"));
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
gui::notification("Error", utils::string::va("^1error teleporting entity num %i to player!", num));
|
||||
gui::notification("Error", utils::string::va("^1error teleporting entity num %i to player!", entref.entnum));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void delete_entity(data_t& data, unsigned int num)
|
||||
void delete_entity(data_t& data, game::scr_entref_t entref)
|
||||
{
|
||||
data.tasks.push_back([num]()
|
||||
data.tasks.push_back([entref]()
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto entity = scripting::call("getentbynum", {num}).as<scripting::entity>();
|
||||
const scripting::entity entity{entref};
|
||||
entity.call("delete");
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
gui::notification("Error", utils::string::va("^1error deleting entity num %i!", num));
|
||||
gui::notification("Error", utils::string::va("^1error deleting entity num %i!", entref.entnum));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void set_entity_field(data_t& data, unsigned int num,
|
||||
void set_entity_field(data_t& data, game::scr_entref_t entref,
|
||||
const std::string& name, const std::string& string_value, int type)
|
||||
{
|
||||
data.tasks.push_back([num, name, type, string_value, &data]()
|
||||
data.tasks.push_back([entref, name, type, string_value, &data]()
|
||||
{
|
||||
scripting::script_value value{};
|
||||
|
||||
@ -546,7 +509,7 @@ namespace entity_list
|
||||
|
||||
try
|
||||
{
|
||||
const auto entity = scripting::call("getentbynum", {num}).as<scripting::entity>();
|
||||
const scripting::entity entity{entref};
|
||||
scripting::set_entity_field(entity, name, value);
|
||||
data.force_update = true;
|
||||
}
|
||||
@ -557,14 +520,14 @@ namespace entity_list
|
||||
});
|
||||
}
|
||||
|
||||
void set_entity_field_vector(data_t& data, unsigned int num,
|
||||
void set_entity_field_vector(data_t& data, game::scr_entref_t entref,
|
||||
const std::string& name, const scripting::vector& value)
|
||||
{
|
||||
data.tasks.push_back([num, name, value, &data]()
|
||||
data.tasks.push_back([entref, name, value, &data]()
|
||||
{
|
||||
try
|
||||
{
|
||||
const auto entity = scripting::call("getentbynum", {num}).as<scripting::entity>();
|
||||
const scripting::entity entity{entref};
|
||||
scripting::set_entity_field(entity, name, value);
|
||||
data.force_update = true;
|
||||
}
|
||||
@ -665,11 +628,13 @@ namespace entity_list
|
||||
{
|
||||
auto result = 0;
|
||||
|
||||
result += ImGui::RadioButton("any", reinterpret_cast<int*>(&data.filters.type), entity_type::type_any);
|
||||
result += ImGui::RadioButton("entity", reinterpret_cast<int*>(&data.filters.type), entity_type::entity);
|
||||
result += ImGui::RadioButton("actor", reinterpret_cast<int*>(&data.filters.type), entity_type::actor);
|
||||
result += ImGui::RadioButton("spawner", reinterpret_cast<int*>(&data.filters.type), entity_type::spawner);
|
||||
result += ImGui::RadioButton("weapon", reinterpret_cast<int*>(&data.filters.type), entity_type::weapon);
|
||||
result += ImGui::RadioButton("node", reinterpret_cast<int*>(&data.filters.type), entity_type::node);
|
||||
result += ImGui::RadioButton("vehicle", reinterpret_cast<int*>(&data.filters.type), entity_type::vehicle);
|
||||
result += ImGui::RadioButton("path node", reinterpret_cast<int*>(&data.filters.type), entity_type::node);
|
||||
result += ImGui::RadioButton("vehicle node", reinterpret_cast<int*>(&data.filters.type), entity_type::vehicle_node);
|
||||
|
||||
if (result)
|
||||
{
|
||||
@ -679,7 +644,8 @@ namespace entity_list
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Entity team"))
|
||||
if ((data.filters.type == entity_type::actor || data.filters.type == entity_type::spawner)
|
||||
&& ImGui::TreeNode("Entity team"))
|
||||
{
|
||||
auto result = 0;
|
||||
|
||||
@ -728,20 +694,33 @@ namespace entity_list
|
||||
|
||||
for (const auto& info : data.entity_info)
|
||||
{
|
||||
if (ImGui::TreeNode(utils::string::va("Entity num %i", info.num)))
|
||||
if (ImGui::TreeNode(utils::string::va("Entity num %i class %i",
|
||||
info.entref.entnum, info.entref.classnum)))
|
||||
{
|
||||
ImGui::Text("Info");
|
||||
|
||||
const auto num_str = utils::string::va("%i", info.num);
|
||||
const auto num_str = utils::string::va("%i", info.entref.entnum);
|
||||
const auto classnum_str = utils::string::va("%i", info.entref.classnum);
|
||||
|
||||
ImGui::Text("Entity num");
|
||||
ImGui::Text("Entity number");
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(num_str))
|
||||
{
|
||||
gui::copy_to_clipboard(num_str);
|
||||
}
|
||||
|
||||
const auto entity_code = utils::string::va("game:getentbynum(%i)", info.num);
|
||||
ImGui::Text("Entity class");
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button(classnum_str))
|
||||
{
|
||||
gui::copy_to_clipboard(classnum_str);
|
||||
}
|
||||
|
||||
const auto entity_code = utils::string::va("game:getentbyref(%i, %i)",
|
||||
info.entref.entnum, info.entref.classnum);
|
||||
|
||||
if (ImGui::Button(entity_code))
|
||||
{
|
||||
gui::copy_to_clipboard(entity_code);
|
||||
@ -752,24 +731,24 @@ namespace entity_list
|
||||
if (ImGui::Button("Set field"))
|
||||
{
|
||||
set_field_window = true;
|
||||
selected_entity = info.num;
|
||||
selected_entity = info.entref;
|
||||
}
|
||||
|
||||
if (ImGui::Button("Teleport to"))
|
||||
{
|
||||
teleport_to(data, info.num);
|
||||
teleport_to(data, info.entref);
|
||||
data.force_update = true;
|
||||
}
|
||||
|
||||
if (ImGui::Button("Teleport to you"))
|
||||
{
|
||||
teleport_to_reverse(data, info.num);
|
||||
teleport_to_reverse(data, info.entref);
|
||||
data.force_update = true;
|
||||
}
|
||||
|
||||
if (info.num != 0 && ImGui::Button("Delete"))
|
||||
if (info.entref.classnum == 0 && info.entref.entnum != 0 && ImGui::Button("Delete"))
|
||||
{
|
||||
delete_entity(data, info.num);
|
||||
delete_entity(data, info.entref);
|
||||
data.force_update = true;
|
||||
}
|
||||
|
||||
@ -835,7 +814,7 @@ namespace entity_list
|
||||
{
|
||||
if (!game::CL_IsCgameInitialized())
|
||||
{
|
||||
selected_entity = 0;
|
||||
selected_entity = {};
|
||||
data.entity_info = {};
|
||||
data.tasks = {};
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ namespace scripting
|
||||
{
|
||||
std::unordered_map<int, std::unordered_map<std::string, int>> fields_table;
|
||||
std::unordered_map<std::string, std::unordered_map<std::string, const char*>> script_function_table;
|
||||
utils::concurrency::container<shared_table_t> shared_table;
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -54,14 +55,24 @@ namespace scripting
|
||||
vm_notify_hook.invoke<void>(notify_list_owner_id, string_value, top);
|
||||
}
|
||||
|
||||
void clear_shared_table()
|
||||
{
|
||||
shared_table.access([](shared_table_t& table)
|
||||
{
|
||||
table.clear();
|
||||
});
|
||||
}
|
||||
|
||||
void player_spawn_stub(const game::gentity_s* player)
|
||||
{
|
||||
player_spawn_hook.invoke<void>(player);
|
||||
clear_shared_table();
|
||||
lua::engine::start();
|
||||
}
|
||||
|
||||
void g_shutdown_game_stub(const int free_scripts)
|
||||
{
|
||||
clear_shared_table();
|
||||
lua::engine::stop();
|
||||
g_shutdown_game_hook.invoke<void>(free_scripts);
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
#pragma once
|
||||
#include <utils/concurrency.hpp>
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
using shared_table_t = std::unordered_map<std::string, std::string>;
|
||||
|
||||
extern std::unordered_map<int, std::unordered_map<std::string, int>> fields_table;
|
||||
extern std::unordered_map<std::string, std::unordered_map<std::string, const char*>> script_function_table;
|
||||
extern utils::concurrency::container<shared_table_t> shared_table;
|
||||
}
|
@ -27,7 +27,7 @@ namespace scripting
|
||||
}
|
||||
|
||||
entity::entity(game::scr_entref_t entref)
|
||||
: entity(game::FindEntityId(entref.entnum, entref.classnum))
|
||||
: entity(game::Scr_GetEntityId(entref.entnum, entref.classnum))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,7 @@ namespace scripting::lua
|
||||
|
||||
void setup_entity_type(sol::state& state, event_handler& handler, scheduler& scheduler)
|
||||
{
|
||||
state["level"] = entity{*game::levelEntityId};
|
||||
state["level"] = entity{*::game::levelEntityId};
|
||||
state["player"] = call("getentbynum", {0}).as<entity>();
|
||||
|
||||
state["io"]["fileexists"] = utils::io::file_exists;
|
||||
@ -301,6 +301,13 @@ namespace scripting::lua
|
||||
return result;
|
||||
};
|
||||
|
||||
entity_type["getentref"] = [](const entity& entity)
|
||||
{
|
||||
const auto entref = entity.get_entity_reference();
|
||||
std::vector<unsigned int> returns = {entref.entnum, entref.classnum};
|
||||
return sol::as_returns(returns);
|
||||
};
|
||||
|
||||
struct game
|
||||
{
|
||||
};
|
||||
@ -530,6 +537,38 @@ namespace scripting::lua
|
||||
|
||||
return table;
|
||||
};
|
||||
|
||||
game_type["sharedset"] = [](const game&, const std::string& key, const std::string& value)
|
||||
{
|
||||
scripting::shared_table.access([key, value](scripting::shared_table_t& table)
|
||||
{
|
||||
table[key] = value;
|
||||
});
|
||||
};
|
||||
|
||||
game_type["sharedget"] = [](const game&, const std::string& key)
|
||||
{
|
||||
std::string result;
|
||||
scripting::shared_table.access([key, &result](scripting::shared_table_t& table)
|
||||
{
|
||||
result = table[key];
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
game_type["getentbyref"] = [](const game&, const sol::this_state s,
|
||||
const unsigned int entnum, const unsigned int classnum)
|
||||
{
|
||||
const auto id = ::game::Scr_GetEntityId(entnum, classnum);
|
||||
if (id)
|
||||
{
|
||||
return convert(s, scripting::entity{id});
|
||||
}
|
||||
else
|
||||
{
|
||||
return sol::lua_value{s, sol::lua_nil};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,7 @@ namespace game
|
||||
WEAK symbol<const float* (const float* v)> Scr_AllocVector{0x5C3220};
|
||||
WEAK symbol<void()> Scr_ClearOutParams{0x5C6E50};
|
||||
WEAK symbol<scr_entref_t(unsigned int entId)> Scr_GetEntityIdRef{0x5C56C0};
|
||||
WEAK symbol<unsigned int(int entnum, unsigned int classnum)> Scr_GetEntityId{0x5C5610};
|
||||
WEAK symbol<int(unsigned int classnum, int entnum, int offset)> Scr_SetObjectField{0x512190};
|
||||
WEAK symbol<void(unsigned int id, scr_string_t stringValue, unsigned int paramcount)> Scr_NotifyId{0x5C8240};
|
||||
WEAK symbol<unsigned int(unsigned int threadId)> Scr_GetSelf{0x5C57C0};
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "../execution.hpp"
|
||||
|
||||
#include "../../../component/ui_scripting.hpp"
|
||||
#include "../../../component/scripting.hpp"
|
||||
#include "../../../component/command.hpp"
|
||||
|
||||
#include "component/game_console.hpp"
|
||||
@ -1006,6 +1007,24 @@ namespace ui_scripting::lua
|
||||
return sol::as_returns(returns);
|
||||
};
|
||||
|
||||
game_type["sharedset"] = [](const game&, const std::string& key, const std::string& value)
|
||||
{
|
||||
scripting::shared_table.access([key, value](scripting::shared_table_t& table)
|
||||
{
|
||||
table[key] = value;
|
||||
});
|
||||
};
|
||||
|
||||
game_type["sharedget"] = [](const game&, const std::string& key)
|
||||
{
|
||||
std::string result;
|
||||
scripting::shared_table.access([key, &result](scripting::shared_table_t& table)
|
||||
{
|
||||
result = table[key];
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
auto userdata_type = state.new_usertype<userdata>("userdata_");
|
||||
|
||||
userdata_type["new"] = sol::property(
|
||||
|
Loading…
x
Reference in New Issue
Block a user