Initial commit

This commit is contained in:
Federico Cecchetto
2021-05-29 22:07:08 +02:00
parent daf26438b0
commit dc150bb940
55 changed files with 11496 additions and 1 deletions

6
src/game/game.cpp Normal file
View File

@ -0,0 +1,6 @@
#include <stdinc.hpp>
namespace game
{
}

34
src/game/game.hpp Normal file
View File

@ -0,0 +1,34 @@
#pragma once
namespace game
{
template <typename T>
class symbol
{
public:
symbol(const size_t dedi)
: dedi_(reinterpret_cast<T*>(dedi))
{
}
T* get() const
{
return dedi_;
}
operator T* () const
{
return this->get();
}
T* operator->() const
{
return this->get();
}
private:
T* dedi_;
};
}
#include "symbols.hpp"

View 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);
}
}

View 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>();
}
}

View 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;
};
}

View 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 {};
}
}

View 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);
}

File diff suppressed because it is too large Load Diff

View 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);
}
}

View 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);
}

View 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)

View 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);
}

View 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();
}
}

View 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_{};
};
}

View 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_;
}
}

View 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_;
};
}

View 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;
}
}
}

View 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};
};
}

View 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;
}
}

View 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 };
};
}

301
src/game/structs.hpp Normal file
View File

@ -0,0 +1,301 @@
#pragma once
namespace game
{
typedef float vec_t;
typedef vec_t vec2_t[2];
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4];
struct cmd_function_t
{
cmd_function_t* next;
const char* name;
const char* autoCompleteDir;
const char* autoCompleteExt;
void(__cdecl* function)();
int flags;
};
struct msg_t
{
int overflowed;
int readOnly;
char* data;
char* splitData;
int maxsize;
int cursize;
int splitSize;
int readcount;
int bit;
int lastEntityRef;
};
struct XZoneInfo
{
const char* name;
int allocFlags;
int freeFlags;
};
struct scr_entref_t
{
unsigned __int16 entnum;
unsigned __int16 classnum;
};
typedef void(__cdecl* scr_call_t)(int entref);
enum MeansOfDeath
{
MOD_UNKNOWN = 0,
MOD_PISTOL_BULLET = 1,
MOD_RIFLE_BULLET = 2,
MOD_EXPLOSIVE_BULLET = 3,
MOD_GRENADE = 4,
MOD_GRENADE_SPLASH = 5,
MOD_PROJECTILE = 6,
MOD_PROJECTILE_SPLASH = 7,
MOD_MELEE = 8,
MOD_HEAD_SHOT = 9,
MOD_CRUSH = 10,
MOD_FALLING = 11,
MOD_SUICIDE = 12,
MOD_TRIGGER_HURT = 13,
MOD_EXPLOSIVE = 14,
MOD_IMPACT = 15,
MOD_NUM = 16
};
enum scriptType_e
{
SCRIPT_NONE = 0,
SCRIPT_OBJECT = 1,
SCRIPT_STRING = 2,
SCRIPT_ISTRING = 3,
SCRIPT_VECTOR = 4,
SCRIPT_FLOAT = 5,
SCRIPT_INTEGER = 6,
SCRIPT_END = 8,
SCRIPT_FUNCTION = 9,
SCRIPT_STRUCT = 19,
SCRIPT_ARRAY = 22,
};
struct VariableStackBuffer
{
const char* pos;
unsigned __int16 size;
unsigned __int16 bufLen;
unsigned __int16 localId;
char time;
char buf[1];
};
union VariableUnion
{
int intValue;
float floatValue;
unsigned int stringValue;
const float* vectorValue;
const char* codePosValue;
unsigned int pointerValue;
VariableStackBuffer* stackValue;
unsigned int entityId;
unsigned int uintValue;
};
struct VariableValue
{
VariableUnion u;
scriptType_e type;
};
struct function_stack_t
{
const char* pos;
unsigned int localId;
unsigned int localVarCount;
VariableValue* top;
VariableValue* startTop;
};
struct function_frame_t
{
function_stack_t fs;
int topType;
};
struct scrVmPub_t
{
unsigned int* localVars;
VariableValue* maxstack;
int function_count;
function_frame_t* function_frame;
VariableValue* top;
/*bool debugCode;
bool abort_on_error;
bool terminal_error;
bool block_execution;*/
unsigned int inparamcount;
unsigned int outparamcount;
unsigned int breakpointOutparamcount;
bool showError;
function_frame_t function_frame_start[32];
VariableValue stack[2048];
};
struct scr_classStruct_t
{
unsigned __int16 id;
unsigned __int16 entArrayId;
char charId;
const char* name;
};
struct ObjectVariableChildren
{
unsigned __int16 firstChild;
unsigned __int16 lastChild;
};
struct ObjectVariableValue_u_f
{
unsigned __int16 prev;
unsigned __int16 next;
};
union ObjectVariableValue_u_o_u
{
unsigned __int16 size;
unsigned __int16 entnum;
unsigned __int16 nextEntId;
unsigned __int16 self;
};
struct ObjectVariableValue_u_o
{
unsigned __int16 refCount;
ObjectVariableValue_u_o_u u;
};
union ObjectVariableValue_w
{
unsigned int type;
unsigned int classnum;
unsigned int notifyName;
unsigned int waitTime;
unsigned int parentLocalId;
};
struct ChildVariableValue_u_f
{
unsigned __int16 prev;
unsigned __int16 next;
};
union ChildVariableValue_u
{
ChildVariableValue_u_f f;
VariableUnion u;
};
struct ChildBucketMatchKeys_keys
{
unsigned __int16 name_hi;
unsigned __int16 parentId;
};
union ChildBucketMatchKeys
{
ChildBucketMatchKeys_keys keys;
unsigned int match;
};
struct ChildVariableValue
{
ChildVariableValue_u u;
unsigned __int16 next;
char type;
char name_lo;
ChildBucketMatchKeys k;
unsigned __int16 nextSibling;
unsigned __int16 prevSibling;
};
union ObjectVariableValue_u
{
ObjectVariableValue_u_f f;
ObjectVariableValue_u_o o;
};
struct ObjectVariableValue
{
ObjectVariableValue_u u;
ObjectVariableValue_w w;
};
struct scrVarGlob_t
{
ObjectVariableValue objectVariableValue[36864];
ObjectVariableChildren objectVariableChildren[36864];
unsigned __int16 childVariableBucket[65536];
ChildVariableValue childVariableValue[102400];
};
union DvarValue
{
bool enabled;
int integer;
unsigned int unsignedInt;
float value;
float vector[4];
const char* string;
char color[4];
};
struct enum_limit
{
int stringCount;
const char** strings;
};
struct int_limit
{
int min;
int max;
};
struct float_limit
{
float min;
float max;
};
union DvarLimits
{
enum_limit enumeration;
int_limit integer;
float_limit value;
float_limit vector;
};
struct dvar_t
{
const char* name;
unsigned int flags;
char type;
bool modified;
DvarValue current;
DvarValue latched;
DvarValue reset;
DvarLimits domain;
bool(__cdecl* domainFunc)(dvar_t*, DvarValue);
dvar_t* hashNext;
};
struct gentity_s
{
int entnum;
};
}

69
src/game/symbols.hpp Normal file
View File

@ -0,0 +1,69 @@
#pragma once
#define WEAK __declspec(selectany)
namespace game
{
// Functions
WEAK symbol<void(int type, VariableUnion u)> AddRefToValue{0x5656E0};
WEAK symbol<void(unsigned int id)> AddReftoObject{0x5655F0};
WEAK symbol<unsigned int(unsigned int id)> AllocThread{0x565580};
WEAK symbol<unsigned int()> AllocObject{0x565530};
WEAK symbol<void(int type, VariableUnion u)> RemoveRefToValue{0x565730};
WEAK symbol<void(unsigned int weapon, bool isAlternate, char* output, unsigned int maxStringLen)> BG_GetWeaponNameComplete{0x42F760};
WEAK symbol<const char*(int index)> ConcatArgs{0x502150};
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x545680};
WEAK symbol<void(const char* cmdName, void(), cmd_function_t* allocedCmd)> Cmd_AddCommandInternal{0x0};
WEAK symbol<const char*(int index)> Cmd_Argv{0x0};
WEAK symbol<const dvar_t*(const char*)> Dvar_FindVar{0x5BDCC0};
WEAK symbol<char*(const char*)> I_CleanStr{0x0};
WEAK symbol<VariableValue(unsigned int classnum, int entnum, int offset)> GetEntityFieldValue{0x56AF20};
WEAK symbol<unsigned int(unsigned int parentId, unsigned int name)> FindVariable{0x5651F0};
WEAK symbol<unsigned int(unsigned int parentId, unsigned int name)> FindObject{0x565BD0};
WEAK symbol<unsigned int(unsigned int parentId, unsigned int name)> GetVariable{0x5663E0};
WEAK symbol<const float* (const float* v)> Scr_AllocVector{0x565680};
WEAK symbol<void()> Scr_ClearOutParams{0x569010};
WEAK symbol<scr_entref_t(unsigned int entId)> Scr_GetEntityIdRef{0x565F60};
WEAK symbol<void(unsigned int classnum, int entnum, int offset)> Scr_SetObjectField{0x52BCC0};
WEAK symbol<void(int id, unsigned int stringValue, unsigned int paramcount)> Scr_NotifyId{0x56B5E0};
WEAK symbol<int(const char* filename, unsigned int str)> Scr_GetFunctionHandle{0x5618A0};
WEAK symbol<unsigned int(int handle, unsigned int objId, unsigned int paramcount)> Scr_ExecThreadInternal{0x56E1C0};
WEAK symbol<unsigned int(const char* str, unsigned int user)> SL_GetString{0x5649E0};
WEAK symbol<const char*(unsigned int stringValue)> SL_ConvertToString{0x564270};
WEAK symbol<void(int clientNum, int type, const char* command)> SV_GameSendServerCommand{0x573220};
WEAK symbol<void(int arg, char* buffer, int bufferLength)> SV_Cmd_ArgvBuffer{0x5459F0};
WEAK symbol<void(unsigned int notifyListOwnerId, unsigned int stringValue, VariableValue* top)> VM_Notify{0x569720};
WEAK symbol<unsigned int(unsigned int localId, const char* pos, unsigned int paramcount)> VM_Execute{0x56DFE0};
WEAK symbol<void* (jmp_buf* Buf, int Value)> longjmp{0x7363BC};
WEAK symbol<int(jmp_buf* Buf)> _setjmp{0x734CF8};
// Variables
WEAK symbol<int> g_script_error_level{0x20B21FC};
WEAK symbol<jmp_buf> g_script_error{0x20B4218};
WEAK symbol<scrVmPub_t> scr_VmPub{0x20B4A80};
WEAK symbol<scrVarGlob_t> scr_VarGlob{0x1E72180};
WEAK symbol<scr_classStruct_t*> g_classMap{0x8B4300};
WEAK symbol<gentity_s> g_entities{0x0};
WEAK symbol<unsigned int> levelEntityId{0x208E1A4};
namespace plutonium
{
WEAK symbol<std::unordered_map<std::string, std::uint16_t>> function_map_rev{0x205862C0};
WEAK symbol<std::unordered_map<std::string, std::uint16_t>> method_map_rev{0x205862E0};
}
}