mirror of
https://github.com/fedddddd/iw5-gsc-utils.git
synced 2025-07-05 18:51:52 +00:00
Initial commit
This commit is contained in:
115
src/game/scripting/entity.cpp
Normal file
115
src/game/scripting/entity.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "entity.hpp"
|
||||
#include "script_value.hpp"
|
||||
#include "execution.hpp"
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
entity::entity()
|
||||
: entity(0)
|
||||
{
|
||||
}
|
||||
|
||||
entity::entity(const entity& other) : entity(other.entity_id_)
|
||||
{
|
||||
}
|
||||
|
||||
entity::entity(entity&& other) noexcept
|
||||
{
|
||||
this->entity_id_ = other.entity_id_;
|
||||
other.entity_id_ = 0;
|
||||
}
|
||||
|
||||
entity::entity(const unsigned int entity_id)
|
||||
: entity_id_(entity_id)
|
||||
{
|
||||
this->add();
|
||||
}
|
||||
|
||||
entity::~entity()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
|
||||
entity& entity::operator=(const entity& other)
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->entity_id_ = other.entity_id_;
|
||||
this->add();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
entity& entity::operator=(entity&& other) noexcept
|
||||
{
|
||||
if (&other != this)
|
||||
{
|
||||
this->release();
|
||||
this->entity_id_ = other.entity_id_;
|
||||
other.entity_id_ = 0;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned int entity::get_entity_id() const
|
||||
{
|
||||
return this->entity_id_;
|
||||
}
|
||||
|
||||
game::scr_entref_t entity::get_entity_reference() const
|
||||
{
|
||||
if (!this->entity_id_)
|
||||
{
|
||||
const auto not_null = static_cast<uint16_t>(~0ui16);
|
||||
return game::scr_entref_t{not_null, not_null};
|
||||
}
|
||||
|
||||
return game::Scr_GetEntityIdRef(this->get_entity_id());
|
||||
}
|
||||
|
||||
bool entity::operator==(const entity& other) const noexcept
|
||||
{
|
||||
return this->get_entity_id() == other.get_entity_id();
|
||||
}
|
||||
|
||||
bool entity::operator!=(const entity& other) const noexcept
|
||||
{
|
||||
return !this->operator==(other);
|
||||
}
|
||||
|
||||
void entity::add() const
|
||||
{
|
||||
if (this->entity_id_)
|
||||
{
|
||||
game::AddRefToValue(game::SCRIPT_OBJECT, {static_cast<int>(this->entity_id_)});
|
||||
}
|
||||
}
|
||||
|
||||
void entity::release() const
|
||||
{
|
||||
if (this->entity_id_)
|
||||
{
|
||||
game::RemoveRefToValue(game::SCRIPT_OBJECT, {static_cast<int>(this->entity_id_)});
|
||||
}
|
||||
}
|
||||
|
||||
void entity::set(const std::string& field, const script_value& value) const
|
||||
{
|
||||
set_entity_field(*this, field, value);
|
||||
}
|
||||
|
||||
template <>
|
||||
script_value entity::get<script_value>(const std::string& field) const
|
||||
{
|
||||
return get_entity_field(*this, field);
|
||||
}
|
||||
|
||||
script_value entity::call(const std::string& name, const std::vector<script_value>& arguments) const
|
||||
{
|
||||
return call_function(name, *this, arguments);
|
||||
}
|
||||
}
|
49
src/game/scripting/entity.hpp
Normal file
49
src/game/scripting/entity.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
#include "script_value.hpp"
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
class entity final
|
||||
{
|
||||
public:
|
||||
entity();
|
||||
entity(unsigned int entity_id);
|
||||
|
||||
entity(const entity& other);
|
||||
entity(entity&& other) noexcept;
|
||||
|
||||
~entity();
|
||||
|
||||
entity& operator=(const entity& other);
|
||||
entity& operator=(entity&& other) noexcept;
|
||||
|
||||
void set(const std::string& field, const script_value& value) const;
|
||||
|
||||
template <typename T = script_value>
|
||||
T get(const std::string& field) const;
|
||||
|
||||
script_value call(const std::string& name, const std::vector<script_value>& arguments = {}) const;
|
||||
|
||||
unsigned int get_entity_id() const;
|
||||
game::scr_entref_t get_entity_reference() const;
|
||||
|
||||
bool operator ==(const entity& other) const noexcept;
|
||||
bool operator !=(const entity& other) const noexcept;
|
||||
|
||||
private:
|
||||
unsigned int entity_id_;
|
||||
|
||||
void add() const;
|
||||
void release() const;
|
||||
};
|
||||
|
||||
template <>
|
||||
script_value entity::get(const std::string& field) const;
|
||||
|
||||
template <typename T>
|
||||
T entity::get(const std::string& field) const
|
||||
{
|
||||
return this->get<script_value>(field).as<T>();
|
||||
}
|
||||
}
|
13
src/game/scripting/event.hpp
Normal file
13
src/game/scripting/event.hpp
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "script_value.hpp"
|
||||
#include "entity.hpp"
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
struct event
|
||||
{
|
||||
std::string name;
|
||||
entity entity{};
|
||||
std::vector<script_value> arguments;
|
||||
};
|
||||
}
|
278
src/game/scripting/execution.cpp
Normal file
278
src/game/scripting/execution.cpp
Normal file
@ -0,0 +1,278 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "execution.hpp"
|
||||
#include "safe_execution.hpp"
|
||||
#include "stack_isolation.hpp"
|
||||
#include "event.hpp"
|
||||
|
||||
#include "component/scripting.hpp"
|
||||
#include "component/scheduler.hpp"
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
namespace
|
||||
{
|
||||
game::VariableValue* allocate_argument()
|
||||
{
|
||||
game::VariableValue* value_ptr = ++game::scr_VmPub->top;
|
||||
++game::scr_VmPub->inparamcount;
|
||||
return value_ptr;
|
||||
}
|
||||
|
||||
script_value get_return_value()
|
||||
{
|
||||
if (game::scr_VmPub->inparamcount == 0)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
game::Scr_ClearOutParams();
|
||||
game::scr_VmPub->outparamcount = game::scr_VmPub->inparamcount;
|
||||
game::scr_VmPub->inparamcount = 0;
|
||||
|
||||
return script_value(game::scr_VmPub->top[1 - game::scr_VmPub->outparamcount]);
|
||||
}
|
||||
|
||||
int get_field_id(const int classnum, const std::string& field)
|
||||
{
|
||||
if (scripting::fields_table[classnum].find(field) != scripting::fields_table[classnum].end())
|
||||
{
|
||||
return scripting::fields_table[classnum][field];
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void scr_notify_id(int id, unsigned int stringValue, unsigned int paramcount)
|
||||
{
|
||||
if (game::scr_VmPub->outparamcount)
|
||||
{
|
||||
game::Scr_ClearOutParams();
|
||||
}
|
||||
|
||||
auto v6 = game::scr_VmPub->top;
|
||||
auto v7 = game::scr_VmPub->inparamcount - paramcount;
|
||||
auto v8 = &game::scr_VmPub->top[-paramcount];
|
||||
|
||||
if (id)
|
||||
{
|
||||
const auto v9 = v8->type;
|
||||
v8->type = game::scriptType_e::SCRIPT_END;
|
||||
|
||||
game::scr_VmPub->inparamcount = 0;
|
||||
game::VM_Notify(id, stringValue, game::scr_VmPub->top);
|
||||
|
||||
v8->type = v9;
|
||||
v6 = game::scr_VmPub->top;
|
||||
}
|
||||
|
||||
for (; v6 != v8; game::scr_VmPub->top = v6)
|
||||
{
|
||||
game::RemoveRefToValue(v6->type, v6->u);
|
||||
v6 = game::scr_VmPub->top - 1;
|
||||
}
|
||||
|
||||
game::scr_VmPub->inparamcount = v7;
|
||||
}
|
||||
}
|
||||
|
||||
void push_value(const script_value& value)
|
||||
{
|
||||
auto* value_ptr = allocate_argument();
|
||||
*value_ptr = value.get_raw();
|
||||
|
||||
game::AddRefToValue(value_ptr->type, value_ptr->u);
|
||||
}
|
||||
|
||||
void notify(const entity& entity, const std::string& event, const std::vector<script_value>& arguments)
|
||||
{
|
||||
stack_isolation _;
|
||||
for (auto i = arguments.rbegin(); i != arguments.rend(); ++i)
|
||||
{
|
||||
push_value(*i);
|
||||
}
|
||||
|
||||
const auto event_id = game::SL_GetString(event.data(), 0);
|
||||
scr_notify_id(entity.get_entity_id(), event_id, game::scr_VmPub->inparamcount);
|
||||
}
|
||||
|
||||
script_value call_function(const std::string& name, const entity& entity,
|
||||
const std::vector<script_value>& arguments)
|
||||
{
|
||||
const auto entref = entity.get_entity_reference();
|
||||
|
||||
const auto is_method_call = *reinterpret_cast<const int*>(&entref) != -1;
|
||||
const auto function = find_function(name, !is_method_call);
|
||||
if (!function)
|
||||
{
|
||||
throw std::runtime_error("Unknown function '" + name + "'");
|
||||
}
|
||||
|
||||
stack_isolation _;
|
||||
|
||||
for (auto i = arguments.rbegin(); i != arguments.rend(); ++i)
|
||||
{
|
||||
push_value(*i);
|
||||
}
|
||||
|
||||
game::scr_VmPub->outparamcount = game::scr_VmPub->inparamcount;
|
||||
game::scr_VmPub->inparamcount = 0;
|
||||
|
||||
if (!safe_execution::call(function, entref))
|
||||
{
|
||||
throw std::runtime_error("Error executing function '" + name + "'");
|
||||
}
|
||||
|
||||
return get_return_value();
|
||||
}
|
||||
|
||||
script_value call_function(const std::string& name, const std::vector<script_value>& arguments)
|
||||
{
|
||||
return call_function(name, entity(), arguments);
|
||||
}
|
||||
|
||||
template <>
|
||||
script_value call(const std::string& name, const std::vector<script_value>& arguments)
|
||||
{
|
||||
return call_function(name, arguments);
|
||||
}
|
||||
|
||||
script_value exec_ent_thread(const entity& entity, const char* pos, const std::vector<script_value>& arguments)
|
||||
{
|
||||
const auto id = entity.get_entity_id();
|
||||
|
||||
for (auto i = arguments.rbegin(); i != arguments.rend(); ++i)
|
||||
{
|
||||
push_value(*i);
|
||||
}
|
||||
|
||||
game::AddReftoObject(id);
|
||||
|
||||
const auto local_id = game::AllocThread(id);
|
||||
const auto result = game::VM_Execute(local_id, pos, arguments.size());
|
||||
|
||||
const auto value = get_return_value();
|
||||
|
||||
game::RemoveRefToValue(game::scr_VmPub->top->type, game::scr_VmPub->top->u);
|
||||
game::scr_VmPub->top->type = (game::scriptType_e)0;
|
||||
|
||||
--game::scr_VmPub->top;
|
||||
--game::scr_VmPub->inparamcount;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
script_value call_script_function(const entity& entity, const std::string& filename,
|
||||
const std::string& function, const std::vector<script_value>& arguments)
|
||||
{
|
||||
if (scripting::script_function_table.find(filename) == scripting::script_function_table.end())
|
||||
{
|
||||
throw std::runtime_error("File '" + filename + "' not found");
|
||||
};
|
||||
|
||||
const auto functions = scripting::script_function_table[filename];
|
||||
|
||||
if (functions.find(function) == functions.end())
|
||||
{
|
||||
throw std::runtime_error("Function '" + function + "' in file '" + filename + "' not found");
|
||||
}
|
||||
|
||||
const auto pos = functions.at(function);
|
||||
|
||||
return exec_ent_thread(entity, pos, arguments);
|
||||
}
|
||||
|
||||
static std::unordered_map<unsigned int, std::unordered_map<std::string, script_value>> custom_fields;
|
||||
|
||||
script_value get_custom_field(const entity& entity, const std::string& field)
|
||||
{
|
||||
auto fields = custom_fields[entity.get_entity_id()];
|
||||
const auto _field = fields.find(field);
|
||||
if (_field != fields.end())
|
||||
{
|
||||
return _field->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void set_custom_field(const entity& entity, const std::string& field, const script_value& value)
|
||||
{
|
||||
const auto id = entity.get_entity_id();
|
||||
|
||||
if (custom_fields[id].find(field) != custom_fields[id].end())
|
||||
{
|
||||
custom_fields[id][field] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
custom_fields[id].insert(std::make_pair(field, value));
|
||||
}
|
||||
|
||||
void clear_entity_fields(const entity& entity)
|
||||
{
|
||||
const auto id = entity.get_entity_id();
|
||||
|
||||
if (custom_fields.find(id) != custom_fields.end())
|
||||
{
|
||||
custom_fields[id].clear();
|
||||
}
|
||||
}
|
||||
|
||||
void clear_custom_fields()
|
||||
{
|
||||
custom_fields.clear();
|
||||
}
|
||||
|
||||
void set_entity_field(const entity& entity, const std::string& field, const script_value& value)
|
||||
{
|
||||
const auto entref = entity.get_entity_reference();
|
||||
const int id = get_field_id(entref.classnum, field);
|
||||
|
||||
if (id != -1)
|
||||
{
|
||||
stack_isolation _;
|
||||
push_value(value);
|
||||
|
||||
game::scr_VmPub->outparamcount = game::scr_VmPub->inparamcount;
|
||||
game::scr_VmPub->inparamcount = 0;
|
||||
|
||||
if (!safe_execution::set_entity_field(entref, id))
|
||||
{
|
||||
throw std::runtime_error("Failed to set value for field '" + field + "'");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
set_custom_field(entity, field, value);
|
||||
}
|
||||
}
|
||||
|
||||
script_value get_entity_field(const entity& entity, const std::string& field)
|
||||
{
|
||||
const auto entref = entity.get_entity_reference();
|
||||
const auto id = get_field_id(entref.classnum, field);
|
||||
|
||||
if (id != -1)
|
||||
{
|
||||
stack_isolation _;
|
||||
|
||||
game::VariableValue value{};
|
||||
if (!safe_execution::get_entity_field(entref, id, &value))
|
||||
{
|
||||
throw std::runtime_error("Failed to get value for field '" + field + "'");
|
||||
}
|
||||
|
||||
const auto __ = gsl::finally([value]()
|
||||
{
|
||||
game::RemoveRefToValue(value.type, value.u);
|
||||
});
|
||||
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
return get_custom_field(entity, field);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
37
src/game/scripting/execution.hpp
Normal file
37
src/game/scripting/execution.hpp
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
#include "entity.hpp"
|
||||
#include "script_value.hpp"
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
void push_value(const script_value& value);
|
||||
|
||||
script_value call_function(const std::string& name, const std::vector<script_value>& arguments);
|
||||
script_value call_function(const std::string& name, const entity& entity,
|
||||
const std::vector<script_value>& arguments);
|
||||
|
||||
template <typename T = script_value>
|
||||
T call(const std::string& name, const std::vector<script_value>& arguments = {});
|
||||
|
||||
template <>
|
||||
script_value call(const std::string& name, const std::vector<script_value>& arguments);
|
||||
|
||||
template <typename T>
|
||||
T call(const std::string& name, const std::vector<script_value>& arguments)
|
||||
{
|
||||
return call<script_value>(name, arguments).as<T>();
|
||||
}
|
||||
|
||||
script_value exec_ent_thread(const entity& entity, const char* pos, const std::vector<script_value>& arguments);
|
||||
script_value call_script_function(const entity& entity, const std::string& filename,
|
||||
const std::string& function, const std::vector<script_value>& arguments);
|
||||
|
||||
void clear_entity_fields(const entity& entity);
|
||||
void clear_custom_fields();
|
||||
|
||||
void set_entity_field(const entity& entity, const std::string& field, const script_value& value);
|
||||
script_value get_entity_field(const entity& entity, const std::string& field);
|
||||
|
||||
void notify(const entity& entity, const std::string& event, const std::vector<script_value>& arguments);
|
||||
}
|
7483
src/game/scripting/function_tables.cpp
Normal file
7483
src/game/scripting/function_tables.cpp
Normal file
File diff suppressed because it is too large
Load Diff
93
src/game/scripting/functions.cpp
Normal file
93
src/game/scripting/functions.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "functions.hpp"
|
||||
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
namespace
|
||||
{
|
||||
std::unordered_map<std::string, unsigned> lowercase_map(
|
||||
const std::unordered_map<std::string, unsigned>& old_map)
|
||||
{
|
||||
std::unordered_map<std::string, unsigned> new_map{};
|
||||
for (auto& entry : old_map)
|
||||
{
|
||||
new_map[utils::string::to_lower(entry.first)] = entry.second;
|
||||
}
|
||||
|
||||
return new_map;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, unsigned>& get_methods()
|
||||
{
|
||||
static auto methods = lowercase_map(method_map);
|
||||
return methods;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, unsigned>& get_functions()
|
||||
{
|
||||
static auto function = lowercase_map(function_map);
|
||||
return function;
|
||||
}
|
||||
|
||||
int find_function_index(const std::string& name, const bool prefer_global)
|
||||
{
|
||||
const auto target = utils::string::to_lower(name);
|
||||
|
||||
const auto& primary_map = prefer_global
|
||||
? get_functions()
|
||||
: get_methods();
|
||||
const auto& secondary_map = !prefer_global
|
||||
? get_functions()
|
||||
: get_methods();
|
||||
|
||||
auto function_entry = primary_map.find(target);
|
||||
if (function_entry != primary_map.end())
|
||||
{
|
||||
return function_entry->second;
|
||||
}
|
||||
|
||||
function_entry = secondary_map.find(target);
|
||||
if (function_entry != secondary_map.end())
|
||||
{
|
||||
return function_entry->second;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
script_function get_function_by_index(const unsigned index)
|
||||
{
|
||||
static const auto function_table = 0x1D6EB34;
|
||||
static const auto method_table = 0x1D4F258;
|
||||
|
||||
if (index < 0x1C7)
|
||||
{
|
||||
return reinterpret_cast<script_function*>(function_table)[index];
|
||||
}
|
||||
|
||||
return reinterpret_cast<script_function*>(method_table)[index];
|
||||
}
|
||||
}
|
||||
|
||||
int find_token_id(const std::string& name)
|
||||
{
|
||||
const auto result = token_map.find(name);
|
||||
|
||||
if (result != token_map.end())
|
||||
{
|
||||
return result->second;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
script_function find_function(const std::string& name, const bool prefer_global)
|
||||
{
|
||||
const auto index = find_function_index(name, prefer_global);
|
||||
if (index < 0) return nullptr;
|
||||
|
||||
return get_function_by_index(index);
|
||||
}
|
||||
}
|
15
src/game/scripting/functions.hpp
Normal file
15
src/game/scripting/functions.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
extern std::unordered_map<std::string, unsigned> method_map;
|
||||
extern std::unordered_map<std::string, unsigned> function_map;
|
||||
extern std::unordered_map<std::string, unsigned> token_map;
|
||||
extern std::unordered_map<unsigned, std::string> file_list;
|
||||
|
||||
using script_function = void(*)(game::scr_entref_t);
|
||||
|
||||
script_function find_function(const std::string& name, const bool prefer_global);
|
||||
int find_token_id(const std::string& name);
|
||||
}
|
74
src/game/scripting/safe_execution.cpp
Normal file
74
src/game/scripting/safe_execution.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "safe_execution.hpp"
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4611)
|
||||
|
||||
namespace scripting::safe_execution
|
||||
{
|
||||
namespace
|
||||
{
|
||||
bool execute_with_seh(const script_function function, const game::scr_entref_t& entref)
|
||||
{
|
||||
__try
|
||||
{
|
||||
function(entref);
|
||||
return true;
|
||||
}
|
||||
__except (EXCEPTION_EXECUTE_HANDLER)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool call(const script_function function, const game::scr_entref_t& entref)
|
||||
{
|
||||
*game::g_script_error_level += 1;
|
||||
if (game::_setjmp(&game::g_script_error[*game::g_script_error_level]))
|
||||
{
|
||||
*game::g_script_error_level -= 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto result = execute_with_seh(function, entref);
|
||||
*game::g_script_error_level -= 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool set_entity_field(const game::scr_entref_t& entref, const int offset)
|
||||
{
|
||||
*game::g_script_error_level += 1;
|
||||
if (game::_setjmp(&game::g_script_error[*game::g_script_error_level]))
|
||||
{
|
||||
*game::g_script_error_level -= 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
game::Scr_SetObjectField(entref.classnum, entref.entnum, offset);
|
||||
|
||||
*game::g_script_error_level -= 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool get_entity_field(const game::scr_entref_t& entref, const int offset, game::VariableValue* value)
|
||||
{
|
||||
*game::g_script_error_level += 1;
|
||||
if (game::_setjmp(&game::g_script_error[*game::g_script_error_level]))
|
||||
{
|
||||
value->type = game::SCRIPT_NONE;
|
||||
value->u.intValue = 0;
|
||||
*game::g_script_error_level -= 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto _value = game::GetEntityFieldValue(entref.classnum, entref.entnum, offset);
|
||||
value->type = _value.type;
|
||||
value->u = _value.u;
|
||||
|
||||
*game::g_script_error_level -= 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning(pop)
|
10
src/game/scripting/safe_execution.hpp
Normal file
10
src/game/scripting/safe_execution.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include "functions.hpp"
|
||||
|
||||
namespace scripting::safe_execution
|
||||
{
|
||||
bool call(script_function function, const game::scr_entref_t& entref);
|
||||
|
||||
bool set_entity_field(const game::scr_entref_t& entref, int offset);
|
||||
bool get_entity_field(const game::scr_entref_t& entref, int offset, game::VariableValue* value);
|
||||
}
|
287
src/game/scripting/script_value.cpp
Normal file
287
src/game/scripting/script_value.cpp
Normal file
@ -0,0 +1,287 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "script_value.hpp"
|
||||
#include "entity.hpp"
|
||||
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
/***************************************************************
|
||||
* Constructors
|
||||
**************************************************************/
|
||||
|
||||
script_value::script_value(const game::VariableValue& value)
|
||||
: value_(value)
|
||||
{
|
||||
}
|
||||
|
||||
script_value::script_value(void* value)
|
||||
{
|
||||
game::VariableValue variable{};
|
||||
variable.type = game::SCRIPT_INTEGER;
|
||||
variable.u.intValue = reinterpret_cast<uintptr_t>(value);
|
||||
|
||||
this->value_ = variable;
|
||||
}
|
||||
|
||||
script_value::script_value(const int value)
|
||||
{
|
||||
game::VariableValue variable{};
|
||||
variable.type = game::SCRIPT_INTEGER;
|
||||
variable.u.intValue = value;
|
||||
|
||||
this->value_ = variable;
|
||||
}
|
||||
|
||||
script_value::script_value(const unsigned int value)
|
||||
{
|
||||
game::VariableValue variable{};
|
||||
variable.type = game::SCRIPT_INTEGER;
|
||||
variable.u.uintValue = value;
|
||||
|
||||
this->value_ = variable;
|
||||
}
|
||||
|
||||
script_value::script_value(const bool value)
|
||||
: script_value(static_cast<unsigned>(value))
|
||||
{
|
||||
}
|
||||
|
||||
script_value::script_value(const float value)
|
||||
{
|
||||
game::VariableValue variable{};
|
||||
variable.type = game::SCRIPT_FLOAT;
|
||||
variable.u.floatValue = value;
|
||||
|
||||
this->value_ = variable;
|
||||
}
|
||||
|
||||
script_value::script_value(const double value)
|
||||
: script_value(static_cast<float>(value))
|
||||
{
|
||||
}
|
||||
|
||||
script_value::script_value(const char* value)
|
||||
{
|
||||
game::VariableValue variable{};
|
||||
variable.type = game::SCRIPT_STRING;
|
||||
variable.u.stringValue = game::SL_GetString(value, 0);
|
||||
|
||||
const auto _ = gsl::finally([&variable]()
|
||||
{
|
||||
game::RemoveRefToValue(variable.type, variable.u);
|
||||
});
|
||||
|
||||
this->value_ = variable;
|
||||
}
|
||||
|
||||
script_value::script_value(const std::string& value)
|
||||
: script_value(value.data())
|
||||
{
|
||||
}
|
||||
|
||||
script_value::script_value(const entity& value)
|
||||
{
|
||||
game::VariableValue variable{};
|
||||
variable.type = game::SCRIPT_OBJECT;
|
||||
variable.u.pointerValue = value.get_entity_id();
|
||||
|
||||
this->value_ = variable;
|
||||
}
|
||||
|
||||
script_value::script_value(const vector& value)
|
||||
{
|
||||
game::VariableValue variable{};
|
||||
variable.type = game::SCRIPT_VECTOR;
|
||||
variable.u.vectorValue = game::Scr_AllocVector(value);
|
||||
|
||||
const auto _ = gsl::finally([&variable]()
|
||||
{
|
||||
game::RemoveRefToValue(variable.type, variable.u);
|
||||
});
|
||||
|
||||
this->value_ = variable;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Integer
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<int>() const
|
||||
{
|
||||
return this->get_raw().type == game::SCRIPT_INTEGER;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool script_value::is<unsigned int>() const
|
||||
{
|
||||
return this->is<int>();
|
||||
}
|
||||
|
||||
template <>
|
||||
bool script_value::is<bool>() const
|
||||
{
|
||||
return this->is<int>();
|
||||
}
|
||||
|
||||
template <>
|
||||
int script_value::get() const
|
||||
{
|
||||
return this->get_raw().u.intValue;
|
||||
}
|
||||
|
||||
template <>
|
||||
unsigned int script_value::get() const
|
||||
{
|
||||
return this->get_raw().u.uintValue;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool script_value::get() const
|
||||
{
|
||||
return this->get_raw().u.uintValue != 0;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Float
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<float>() const
|
||||
{
|
||||
return this->get_raw().type == game::SCRIPT_FLOAT;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool script_value::is<double>() const
|
||||
{
|
||||
return this->is<float>();
|
||||
}
|
||||
|
||||
template <>
|
||||
float script_value::get() const
|
||||
{
|
||||
return this->get_raw().u.floatValue;
|
||||
}
|
||||
|
||||
template <>
|
||||
double script_value::get() const
|
||||
{
|
||||
return static_cast<double>(this->get_raw().u.floatValue);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* String
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<const char*>() const
|
||||
{
|
||||
return this->get_raw().type == game::SCRIPT_STRING;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool script_value::is<std::string>() const
|
||||
{
|
||||
return this->is<const char*>();
|
||||
}
|
||||
|
||||
template <>
|
||||
const char* script_value::get() const
|
||||
{
|
||||
return game::SL_ConvertToString(static_cast<unsigned int>(this->get_raw().u.stringValue));
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string script_value::get() const
|
||||
{
|
||||
return this->get<const char*>();
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Entity
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<entity>() const
|
||||
{
|
||||
return this->get_raw().type == game::SCRIPT_OBJECT;
|
||||
}
|
||||
|
||||
template <>
|
||||
entity script_value::get() const
|
||||
{
|
||||
return entity(this->get_raw().u.pointerValue);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Array
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<std::vector<script_value>>() const
|
||||
{
|
||||
if (this->get_raw().type != game::SCRIPT_OBJECT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto id = this->get_raw().u.uintValue;
|
||||
const auto type = game::scr_VarGlob->objectVariableValue[id].w.type;
|
||||
|
||||
return type == game::SCRIPT_ARRAY;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Struct
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<std::map<std::string, script_value>>() const
|
||||
{
|
||||
if (this->get_raw().type != game::SCRIPT_OBJECT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto id = this->get_raw().u.uintValue;
|
||||
const auto type = game::scr_VarGlob->objectVariableValue[id].w.type;
|
||||
|
||||
return type == game::SCRIPT_STRUCT;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Function
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<std::function<void()>>() const
|
||||
{
|
||||
return this->get_raw().type == game::SCRIPT_FUNCTION;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
* Vector
|
||||
**************************************************************/
|
||||
|
||||
template <>
|
||||
bool script_value::is<vector>() const
|
||||
{
|
||||
return this->get_raw().type == game::SCRIPT_VECTOR;
|
||||
}
|
||||
|
||||
template <>
|
||||
vector script_value::get() const
|
||||
{
|
||||
return this->get_raw().u.vectorValue;
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
*
|
||||
**************************************************************/
|
||||
|
||||
const game::VariableValue& script_value::get_raw() const
|
||||
{
|
||||
return this->value_.get();
|
||||
}
|
||||
}
|
65
src/game/scripting/script_value.hpp
Normal file
65
src/game/scripting/script_value.hpp
Normal file
@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
#include "variable_value.hpp"
|
||||
#include "vector.hpp"
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
class entity;
|
||||
|
||||
class script_value
|
||||
{
|
||||
public:
|
||||
script_value() = default;
|
||||
script_value(const game::VariableValue& value);
|
||||
|
||||
script_value(void* value);
|
||||
|
||||
script_value(int value);
|
||||
script_value(unsigned int value);
|
||||
script_value(bool value);
|
||||
|
||||
script_value(float value);
|
||||
script_value(double value);
|
||||
|
||||
script_value(const char* value);
|
||||
script_value(const std::string& value);
|
||||
|
||||
script_value(const entity& value);
|
||||
|
||||
script_value(const vector& value);
|
||||
|
||||
template <typename T>
|
||||
bool is() const;
|
||||
|
||||
template <typename T>
|
||||
T as() const
|
||||
{
|
||||
if (!this->is<T>())
|
||||
{
|
||||
throw std::runtime_error("Invalid type");
|
||||
}
|
||||
|
||||
return get<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* as_ptr()
|
||||
{
|
||||
if (!this->is<int>())
|
||||
{
|
||||
throw std::runtime_error("Invalid type");
|
||||
}
|
||||
|
||||
return reinterpret_cast<T*>(this->get<int>());
|
||||
}
|
||||
|
||||
const game::VariableValue& get_raw() const;
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
T get() const;
|
||||
|
||||
variable_value value_{};
|
||||
};
|
||||
}
|
27
src/game/scripting/stack_isolation.cpp
Normal file
27
src/game/scripting/stack_isolation.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "stack_isolation.hpp"
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
stack_isolation::stack_isolation()
|
||||
{
|
||||
this->in_param_count_ = game::scr_VmPub->inparamcount;
|
||||
this->out_param_count_ = game::scr_VmPub->outparamcount;
|
||||
this->top_ = game::scr_VmPub->top;
|
||||
this->max_stack_ = game::scr_VmPub->maxstack;
|
||||
|
||||
game::scr_VmPub->top = this->stack_;
|
||||
game::scr_VmPub->maxstack = &this->stack_[ARRAYSIZE(this->stack_) - 1];
|
||||
game::scr_VmPub->inparamcount = 0;
|
||||
game::scr_VmPub->outparamcount = 0;
|
||||
}
|
||||
|
||||
stack_isolation::~stack_isolation()
|
||||
{
|
||||
game::Scr_ClearOutParams();
|
||||
game::scr_VmPub->inparamcount = this->in_param_count_;
|
||||
game::scr_VmPub->outparamcount = this->out_param_count_;
|
||||
game::scr_VmPub->top = this->top_;
|
||||
game::scr_VmPub->maxstack = this->max_stack_;
|
||||
}
|
||||
}
|
25
src/game/scripting/stack_isolation.hpp
Normal file
25
src/game/scripting/stack_isolation.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
class stack_isolation final
|
||||
{
|
||||
public:
|
||||
stack_isolation();
|
||||
~stack_isolation();
|
||||
|
||||
stack_isolation(stack_isolation&&) = delete;
|
||||
stack_isolation(const stack_isolation&) = delete;
|
||||
stack_isolation& operator=(stack_isolation&&) = delete;
|
||||
stack_isolation& operator=(const stack_isolation&) = delete;
|
||||
|
||||
private:
|
||||
game::VariableValue stack_[512]{};
|
||||
|
||||
game::VariableValue* max_stack_;
|
||||
game::VariableValue* top_;
|
||||
unsigned int in_param_count_;
|
||||
unsigned int out_param_count_;
|
||||
};
|
||||
}
|
68
src/game/scripting/variable_value.cpp
Normal file
68
src/game/scripting/variable_value.cpp
Normal file
@ -0,0 +1,68 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "variable_value.hpp"
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
variable_value::variable_value(const game::VariableValue& value)
|
||||
{
|
||||
this->assign(value);
|
||||
}
|
||||
|
||||
variable_value::variable_value(const variable_value& other) noexcept
|
||||
{
|
||||
this->operator=(other);
|
||||
}
|
||||
|
||||
variable_value::variable_value(variable_value&& other) noexcept
|
||||
{
|
||||
this->operator=(std::move(other));
|
||||
}
|
||||
|
||||
variable_value& variable_value::operator=(const variable_value& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
this->release();
|
||||
this->assign(other.value_);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
variable_value& variable_value::operator=(variable_value&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
this->release();
|
||||
this->value_ = other.value_;
|
||||
other.value_.type = game::SCRIPT_NONE;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
variable_value::~variable_value()
|
||||
{
|
||||
this->release();
|
||||
}
|
||||
|
||||
const game::VariableValue& variable_value::get() const
|
||||
{
|
||||
return this->value_;
|
||||
}
|
||||
|
||||
void variable_value::assign(const game::VariableValue& value)
|
||||
{
|
||||
this->value_ = value;
|
||||
game::AddRefToValue(this->value_.type, this->value_.u);
|
||||
}
|
||||
|
||||
void variable_value::release()
|
||||
{
|
||||
if (this->value_.type != game::SCRIPT_NONE)
|
||||
{
|
||||
game::RemoveRefToValue(this->value_.type, this->value_.u);
|
||||
this->value_.type = game::SCRIPT_NONE;
|
||||
}
|
||||
}
|
||||
}
|
27
src/game/scripting/variable_value.hpp
Normal file
27
src/game/scripting/variable_value.hpp
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
class variable_value
|
||||
{
|
||||
public:
|
||||
variable_value() = default;
|
||||
variable_value(const game::VariableValue& value);
|
||||
variable_value(const variable_value& other) noexcept;
|
||||
variable_value(variable_value&& other) noexcept;
|
||||
|
||||
variable_value& operator=(const variable_value& other) noexcept;
|
||||
variable_value& operator=(variable_value&& other) noexcept;
|
||||
|
||||
~variable_value();
|
||||
|
||||
const game::VariableValue& get() const;
|
||||
|
||||
private:
|
||||
void assign(const game::VariableValue& value);
|
||||
void release();
|
||||
|
||||
game::VariableValue value_{{0}, game::SCRIPT_NONE};
|
||||
};
|
||||
}
|
85
src/game/scripting/vector.cpp
Normal file
85
src/game/scripting/vector.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include <stdinc.hpp>
|
||||
#include "vector.hpp"
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
vector::vector(const float* value)
|
||||
{
|
||||
for (auto i = 0; i < 3; ++i)
|
||||
{
|
||||
this->value_[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
vector::vector(const game::vec3_t& value)
|
||||
: vector(&value[0])
|
||||
{
|
||||
}
|
||||
|
||||
vector::vector(const float x, const float y, const float z)
|
||||
{
|
||||
this->value_[0] = x;
|
||||
this->value_[1] = y;
|
||||
this->value_[2] = z;
|
||||
}
|
||||
|
||||
vector::operator game::vec3_t& ()
|
||||
{
|
||||
return this->value_;
|
||||
}
|
||||
|
||||
vector::operator const game::vec3_t& () const
|
||||
{
|
||||
return this->value_;
|
||||
}
|
||||
|
||||
game::vec_t& vector::operator[](const size_t i)
|
||||
{
|
||||
if (i >= 3)
|
||||
{
|
||||
throw std::runtime_error("Out of bounds.");
|
||||
}
|
||||
|
||||
return this->value_[i];
|
||||
}
|
||||
|
||||
const game::vec_t& vector::operator[](const size_t i) const
|
||||
{
|
||||
if (i >= 3)
|
||||
{
|
||||
throw std::runtime_error("Out of bounds.");
|
||||
}
|
||||
|
||||
return this->value_[i];
|
||||
}
|
||||
|
||||
float vector::get_x() const
|
||||
{
|
||||
return this->operator[](0);
|
||||
}
|
||||
|
||||
float vector::get_y() const
|
||||
{
|
||||
return this->operator[](1);
|
||||
}
|
||||
|
||||
float vector::get_z() const
|
||||
{
|
||||
return this->operator[](2);
|
||||
}
|
||||
|
||||
void vector::set_x(const float value)
|
||||
{
|
||||
this->operator[](0) = value;
|
||||
}
|
||||
|
||||
void vector::set_y(const float value)
|
||||
{
|
||||
this->operator[](1) = value;
|
||||
}
|
||||
|
||||
void vector::set_z(const float value)
|
||||
{
|
||||
this->operator[](2) = value;
|
||||
}
|
||||
}
|
31
src/game/scripting/vector.hpp
Normal file
31
src/game/scripting/vector.hpp
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "game/game.hpp"
|
||||
|
||||
namespace scripting
|
||||
{
|
||||
class vector final
|
||||
{
|
||||
public:
|
||||
vector() = default;
|
||||
vector(const float* value);
|
||||
vector(const game::vec3_t& value);
|
||||
vector(float x, float y, float z);
|
||||
|
||||
operator game::vec3_t& ();
|
||||
operator const game::vec3_t& () const;
|
||||
|
||||
game::vec_t& operator[](size_t i);
|
||||
const game::vec_t& operator[](size_t i) const;
|
||||
|
||||
float get_x() const;
|
||||
float get_y() const;
|
||||
float get_z() const;
|
||||
|
||||
void set_x(float value);
|
||||
void set_y(float value);
|
||||
void set_z(float value);
|
||||
|
||||
private:
|
||||
game::vec3_t value_{ 0 };
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user