Random cleanup

This commit is contained in:
momo5502 2019-09-27 22:35:57 +02:00
parent 320d57599e
commit 9f98190944
37 changed files with 2965 additions and 3080 deletions

View File

@ -1,38 +1,35 @@
#include "std_include.hpp" #include "std_include.hpp"
#include "context_initializer.hpp" #include "context_initializer.hpp"
namespace game namespace game::scripting
{ {
namespace scripting context::context() : executer_(this), scheduler_(this), parameters_(this), event_handler_(this)
{ {
context::context() : executer_(this), scheduler_(this), parameters_(this), event_handler_(this) context_initializer::initialize(this);
{ }
context_initializer::initialize(this);
} executer* context::get_executer()
{
executer* context::get_executer() return &this->executer_;
{ }
return &this->executer_;
} scheduler* context::get_scheduler()
{
scheduler* context::get_scheduler() return &this->scheduler_;
{ }
return &this->scheduler_;
} parameters* context::get_parameters()
{
parameters* context::get_parameters() return &this->parameters_;
{ }
return &this->parameters_;
} event_handler* context::get_event_handler()
{
event_handler* context::get_event_handler() return &this->event_handler_;
{ }
return &this->event_handler_;
} chaiscript::ChaiScript* context::get_chai()
{
chaiscript::ChaiScript* context::get_chai() return &this->chai_;
{ }
return &this->chai_; }
}
}
}

View File

@ -1,32 +1,29 @@
#pragma once #pragma once
#include "executer.hpp" #include "executer.hpp"
#include "scheduler.hpp" #include "scheduler.hpp"
#include "parameters.hpp" #include "parameters.hpp"
#include "event_handler.hpp" #include "event_handler.hpp"
namespace game namespace game::scripting
{ {
namespace scripting class context final
{ {
class context final public:
{ context();
public:
context(); chaiscript::ChaiScript* get_chai();
chaiscript::ChaiScript* get_chai(); executer* get_executer();
scheduler* get_scheduler();
executer* get_executer(); parameters* get_parameters();
scheduler* get_scheduler(); event_handler* get_event_handler();
parameters* get_parameters();
event_handler* get_event_handler(); private:
chaiscript::ChaiScript chai_;
private:
chaiscript::ChaiScript chai_; executer executer_;
scheduler scheduler_;
executer executer_; parameters parameters_;
scheduler scheduler_; event_handler event_handler_;
parameters parameters_; };
event_handler event_handler_; }
};
}
}

View File

@ -1,244 +1,238 @@
#include "std_include.hpp" #include "std_include.hpp"
#include "context_initializer.hpp" #include "context_initializer.hpp"
namespace game namespace game::scripting::context_initializer
{ {
namespace scripting void initialize_entity(context* context)
{ {
namespace context_initializer const auto chai = context->get_chai();
{
void initialize_entity(context* context) chai->add(chaiscript::user_type<entity>(), "_entity");
{ chai->add(chaiscript::constructor<entity()>(), "_entity");
const auto chai = context->get_chai(); chai->add(chaiscript::constructor<entity(const entity&)>(), "_entity");
chai->add(chaiscript::user_type<entity>(), "_entity"); chai->add(chaiscript::fun([](entity& lhs, const entity& rhs) -> entity&
chai->add(chaiscript::constructor<entity()>(), "_entity"); {
chai->add(chaiscript::constructor<entity(const entity&)>(), "_entity"); return lhs = rhs;
}), "=");
chai->add(chaiscript::fun([](entity& lhs, const entity& rhs) -> entity&
{ chai->add(chaiscript::fun(&entity::get), "get");
return lhs = rhs; chai->add(chaiscript::fun(&entity::set), "set");
}), "=");
chai->add(chaiscript::fun(&entity::on_notify), "onNotify");
chai->add(chaiscript::fun(&entity::get), "get"); chai->add(chaiscript::fun([](const entity& ent, const std::string& event,
chai->add(chaiscript::fun(&entity::set), "set"); const std::function<void(
std::vector<chaiscript::Boxed_Value>)>&
chai->add(chaiscript::fun(&entity::on_notify), "onNotify"); callback)
chai->add(chaiscript::fun([](const entity& ent, const std::string& event, {
const std::function<void( return ent.on_notify(event, callback, false);
std::vector<chaiscript::Boxed_Value>)>& }), "onNotify");
callback)
{ chai->add(chaiscript::fun([context](const std::string& event,
return ent.on_notify(event, callback, false); const std::function<void(
}), "onNotify"); entity, std::vector<chaiscript::Boxed_Value>)>&
callback)
chai->add(chaiscript::fun([context](const std::string& event, {
const std::function<void( generic_event_listener listener;
entity, std::vector<chaiscript::Boxed_Value>)>& listener.event = event;
callback) listener.is_volatile = false;
{ listener.callback = callback;
generic_event_listener listener;
listener.event = event; return context->get_event_handler()->add_event_listener(listener);
listener.is_volatile = false; }), "onNotify");
listener.callback = callback;
chai->add(chaiscript::fun([context](const std::string& event,
return context->get_event_handler()->add_event_listener(listener); const std::function<void(
}), "onNotify"); entity, std::vector<chaiscript::Boxed_Value>)>&
callback, const bool is_volatile)
chai->add(chaiscript::fun([context](const std::string& event, {
const std::function<void( generic_event_listener listener;
entity, std::vector<chaiscript::Boxed_Value>)>& listener.event = event;
callback, const bool is_volatile) listener.is_volatile = is_volatile;
{ listener.callback = callback;
generic_event_listener listener;
listener.event = event; return context->get_event_handler()->add_event_listener(listener);
listener.is_volatile = is_volatile; }), "onNotify");
listener.callback = callback;
// Notification
return context->get_event_handler()->add_event_listener(listener); chai->add(chaiscript::fun(&entity::notify), "vectorNotify");
}), "onNotify"); chai->add(chaiscript::fun([](const entity& ent, const std::string& event)
{
// Notification return ent.notify(event, {});
chai->add(chaiscript::fun(&entity::notify), "vectorNotify"); }), "notify");
chai->add(chaiscript::fun([](const entity& ent, const std::string& event)
{ chai->add(chaiscript::fun(
return ent.notify(event, {}); [](const entity& ent, const std::string& event,
}), "notify"); const chaiscript::Boxed_Value& a1)
{
chai->add(chaiscript::fun( return ent.notify(event, {a1});
[](const entity& ent, const std::string& event, }), "notify");
const chaiscript::Boxed_Value& a1)
{ chai->add(chaiscript::fun(
return ent.notify(event, {a1}); [](const entity& ent, const std::string& event,
}), "notify"); const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2)
chai->add(chaiscript::fun( {
[](const entity& ent, const std::string& event, return ent.notify(event, {a1, a2});
const chaiscript::Boxed_Value& a1, }), "notify");
const chaiscript::Boxed_Value& a2)
{ chai->add(chaiscript::fun(
return ent.notify(event, {a1, a2}); [](const entity& ent, const std::string& event,
}), "notify"); const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2,
chai->add(chaiscript::fun( const chaiscript::Boxed_Value& a3)
[](const entity& ent, const std::string& event, {
const chaiscript::Boxed_Value& a1, return ent.notify(event, {a1, a2, a3});
const chaiscript::Boxed_Value& a2, }), "notify");
const chaiscript::Boxed_Value& a3)
{ chai->add(chaiscript::fun(
return ent.notify(event, {a1, a2, a3}); [](const entity& ent, const std::string& event,
}), "notify"); const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2,
chai->add(chaiscript::fun( const chaiscript::Boxed_Value& a3,
[](const entity& ent, const std::string& event, const chaiscript::Boxed_Value& a4)
const chaiscript::Boxed_Value& a1, {
const chaiscript::Boxed_Value& a2, return ent.notify(event, {a1, a2, a3, a4});
const chaiscript::Boxed_Value& a3, }), "notify");
const chaiscript::Boxed_Value& a4)
{ chai->add(chaiscript::fun(
return ent.notify(event, {a1, a2, a3, a4}); [](const entity& ent, const std::string& event,
}), "notify"); const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2,
chai->add(chaiscript::fun( const chaiscript::Boxed_Value& a3,
[](const entity& ent, const std::string& event, const chaiscript::Boxed_Value& a4,
const chaiscript::Boxed_Value& a1, const chaiscript::Boxed_Value& a5)
const chaiscript::Boxed_Value& a2, {
const chaiscript::Boxed_Value& a3, return ent.notify(event, {a1, a2, a3, a4, a5});
const chaiscript::Boxed_Value& a4, }), "notify");
const chaiscript::Boxed_Value& a5)
{ // Instance call
return ent.notify(event, {a1, a2, a3, a4, a5}); chai->add(chaiscript::fun(&entity::call), "vectorCall");
}), "notify"); chai->add(chaiscript::fun([](const entity& ent, const std::string& function)
{
// Instance call return ent.call(function, {});
chai->add(chaiscript::fun(&entity::call), "vectorCall"); }), "call");
chai->add(chaiscript::fun([](const entity& ent, const std::string& function)
{ chai->add(chaiscript::fun(
return ent.call(function, {}); [](const entity& ent, const std::string& function,
}), "call"); const chaiscript::Boxed_Value& a1)
{
chai->add(chaiscript::fun( return ent.call(function, {a1});
[](const entity& ent, const std::string& function, }), "call");
const chaiscript::Boxed_Value& a1)
{ chai->add(chaiscript::fun(
return ent.call(function, {a1}); [](const entity& ent, const std::string& function,
}), "call"); const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2)
chai->add(chaiscript::fun( {
[](const entity& ent, const std::string& function, return ent.call(function, {a1, a2});
const chaiscript::Boxed_Value& a1, }), "call");
const chaiscript::Boxed_Value& a2)
{ chai->add(chaiscript::fun(
return ent.call(function, {a1, a2}); [](const entity& ent, const std::string& function,
}), "call"); const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2,
chai->add(chaiscript::fun( const chaiscript::Boxed_Value& a3)
[](const entity& ent, const std::string& function, {
const chaiscript::Boxed_Value& a1, return ent.call(function, {a1, a2, a3});
const chaiscript::Boxed_Value& a2, }), "call");
const chaiscript::Boxed_Value& a3)
{ chai->add(chaiscript::fun(
return ent.call(function, {a1, a2, a3}); [](const entity& ent, const std::string& function,
}), "call"); const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2,
chai->add(chaiscript::fun( const chaiscript::Boxed_Value& a3,
[](const entity& ent, const std::string& function, const chaiscript::Boxed_Value& a4)
const chaiscript::Boxed_Value& a1, {
const chaiscript::Boxed_Value& a2, return ent.call(function, {a1, a2, a3, a4});
const chaiscript::Boxed_Value& a3, }), "call");
const chaiscript::Boxed_Value& a4)
{ chai->add(chaiscript::fun(
return ent.call(function, {a1, a2, a3, a4}); [](const entity& ent, const std::string& function,
}), "call"); const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2,
chai->add(chaiscript::fun( const chaiscript::Boxed_Value& a3,
[](const entity& ent, const std::string& function, const chaiscript::Boxed_Value& a4,
const chaiscript::Boxed_Value& a1, const chaiscript::Boxed_Value& a5)
const chaiscript::Boxed_Value& a2, {
const chaiscript::Boxed_Value& a3, return ent.call(function, {a1, a2, a3, a4, a5});
const chaiscript::Boxed_Value& a4, }), "call");
const chaiscript::Boxed_Value& a5)
{ // Global call
return ent.call(function, {a1, a2, a3, a4, a5}); chai->add(chaiscript::fun(
}), "call"); [context](const std::string& function,
const std::vector<chaiscript::Boxed_Value>& arguments)
// Global call {
chai->add(chaiscript::fun( return context->get_executer()->call(function, 0, arguments);
[context](const std::string& function, }), "vectorCall");
const std::vector<chaiscript::Boxed_Value>& arguments) chai->add(chaiscript::fun([context](const std::string& function)
{ {
return context->get_executer()->call(function, 0, arguments); return context->get_executer()->call(function, 0, {});
}), "vectorCall"); }), "call");
chai->add(chaiscript::fun([context](const std::string& function)
{ chai->add(chaiscript::fun(
return context->get_executer()->call(function, 0, {}); [context](const std::string& function,
}), "call"); const chaiscript::Boxed_Value& a1)
{
chai->add(chaiscript::fun( return context->get_executer()->call(function, 0, {a1});
[context](const std::string& function, }), "call");
const chaiscript::Boxed_Value& a1)
{ chai->add(chaiscript::fun(
return context->get_executer()->call(function, 0, {a1}); [context](const std::string& function,
}), "call"); const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2)
chai->add(chaiscript::fun( {
[context](const std::string& function, return context->get_executer()->call(function, 0, {a1, a2});
const chaiscript::Boxed_Value& a1, }), "call");
const chaiscript::Boxed_Value& a2)
{ chai->add(chaiscript::fun(
return context->get_executer()->call(function, 0, {a1, a2}); [context](const std::string& function,
}), "call"); const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2,
chai->add(chaiscript::fun( const chaiscript::Boxed_Value& a3)
[context](const std::string& function, {
const chaiscript::Boxed_Value& a1, return context->get_executer()->call(function, 0, {a1, a2, a3});
const chaiscript::Boxed_Value& a2, }), "call");
const chaiscript::Boxed_Value& a3)
{ chai->add(chaiscript::fun(
return context->get_executer()->call(function, 0, {a1, a2, a3}); [context](const std::string& function,
}), "call"); const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2,
chai->add(chaiscript::fun( const chaiscript::Boxed_Value& a3,
[context](const std::string& function, const chaiscript::Boxed_Value& a4)
const chaiscript::Boxed_Value& a1, {
const chaiscript::Boxed_Value& a2, return context->get_executer()->call(function, 0, {a1, a2, a3, a4});
const chaiscript::Boxed_Value& a3, }), "call");
const chaiscript::Boxed_Value& a4)
{ chai->add(chaiscript::fun(
return context->get_executer()->call(function, 0, {a1, a2, a3, a4}); [context](const std::string& function,
}), "call"); const chaiscript::Boxed_Value& a1,
const chaiscript::Boxed_Value& a2,
chai->add(chaiscript::fun( const chaiscript::Boxed_Value& a3,
[context](const std::string& function, const chaiscript::Boxed_Value& a4,
const chaiscript::Boxed_Value& a1, const chaiscript::Boxed_Value& a5)
const chaiscript::Boxed_Value& a2, {
const chaiscript::Boxed_Value& a3, return context->get_executer()->call(function, 0, {a1, a2, a3, a4, a5});
const chaiscript::Boxed_Value& a4, }), "call");
const chaiscript::Boxed_Value& a5) }
{
return context->get_executer()->call(function, 0, {a1, a2, a3, a4, a5}); void initialize(context* context)
}), "call"); {
} initialize_entity(context);
void initialize(context* context) const auto chai = context->get_chai();
{
initialize_entity(context); chai->add(chaiscript::fun([](const std::string& string)
{
const auto chai = context->get_chai(); printf("%s\n", string.data());
}), "print");
chai->add(chaiscript::fun([](const std::string& string)
{ chai->add(chaiscript::fun([](const std::string& string)
printf("%s\n", string.data()); {
}), "print"); MessageBoxA(nullptr, string.data(), nullptr, 0);
}), "alert");
chai->add(chaiscript::fun([](const std::string& string)
{ const auto level_id = *native::levelEntityId;
MessageBoxA(nullptr, string.data(), nullptr, 0); chai->add_global(chaiscript::var(entity(context, level_id)), "level");
}), "alert"); }
}
const auto level_id = *native::levelEntityId;
chai->add_global(chaiscript::var(entity(context, level_id)), "level");
}
}
}
}

View File

@ -1,13 +1,7 @@
#pragma once #pragma once
#include "context.hpp" #include "context.hpp"
namespace game namespace game::scripting::context_initializer
{ {
namespace scripting void initialize(context* context);
{ }
namespace context_initializer
{
void initialize(context* context);
}
}
}

View File

@ -1,21 +1,57 @@
#include "std_include.hpp" #include "std_include.hpp"
#include "context.hpp" #include "context.hpp"
namespace game namespace game::scripting
{ {
namespace scripting entity::entity() : entity(nullptr, 0)
{ {
entity::entity() : entity(nullptr, 0) }
entity::entity(const entity& other) : entity(other.context_, other.entity_id_)
{
}
entity::entity(entity&& other) noexcept
{
if (&other == this) return;
this->context_ = other.context_;
this->entity_id_ = other.entity_id_;
other.context_ = nullptr;
other.entity_id_ = 0;
}
entity::entity(context* context, const unsigned int entity_id) : context_(context), entity_id_(entity_id)
{
this->add();
}
entity::~entity()
{
this->release();
}
entity& entity::operator=(const entity& other)
{
if (&other != this)
{ {
this->release();
this->context_ = other.context_;
this->entity_id_ = other.entity_id_;
this->add();
} }
entity::entity(const entity& other) : entity(other.context_, other.entity_id_) return *this;
{ }
}
entity::entity(entity&& other) noexcept entity& entity::operator=(entity&& other) noexcept
{
if (&other != this)
{ {
if (&other == this) return; this->release();
this->context_ = other.context_; this->context_ = other.context_;
this->entity_id_ = other.entity_id_; this->entity_id_ = other.entity_id_;
@ -24,111 +60,72 @@ namespace game
other.entity_id_ = 0; other.entity_id_ = 0;
} }
entity::entity(context* context, const unsigned int entity_id) : context_(context), entity_id_(entity_id) return *this;
}
event_listener_handle entity::on_notify(const std::string& event,
const std::function<void(std::vector<chaiscript::Boxed_Value>)>&
callback,
const bool is_volatile)
const
{
event_listener listener;
listener.event = event;
listener.callback = callback;
listener.entity_id = this->entity_id_;
listener.is_volatile = is_volatile;
return this->context_->get_event_handler()->add_event_listener(listener);
}
unsigned int entity::get_entity_id() const
{
return this->entity_id_;
}
native::scr_entref_t entity::get_entity_reference() const
{
return game::native::Scr_GetEntityIdRef(this->get_entity_id());
}
chaiscript::Boxed_Value entity::call(const std::string& function,
const std::vector<chaiscript::Boxed_Value>& arguments) const
{
return this->context_->get_executer()->call(function, this->get_entity_id(), arguments);
}
void entity::notify(const std::string& event,
const std::vector<chaiscript::Boxed_Value>& arguments) const
{
this->context_->get_executer()->notify(event, this->get_entity_id(), arguments);
}
void entity::set(const std::string& field, const chaiscript::Boxed_Value& value) const
{
this->context_->get_executer()->set_entity_field(field, this->get_entity_id(), value);
}
chaiscript::Boxed_Value entity::get(const std::string& field) const
{
return this->context_->get_executer()->get_entity_field(field, this->get_entity_id());
}
void entity::add() const
{
if (this->entity_id_)
{ {
this->add(); native::VariableValue value;
value.type = native::SCRIPT_OBJECT;
value.u.entityId = this->entity_id_;
native::AddRefToValue(&value);
} }
}
entity::~entity() void entity::release() const
{
if (this->entity_id_)
{ {
this->release(); native::RemoveRefToValue(native::SCRIPT_OBJECT, {static_cast<int>(this->entity_id_)});
}
entity& entity::operator=(const entity& other)
{
if (&other != this)
{
this->release();
this->context_ = other.context_;
this->entity_id_ = other.entity_id_;
this->add();
}
return *this;
}
entity& entity::operator=(entity&& other) noexcept
{
if (&other != this)
{
this->release();
this->context_ = other.context_;
this->entity_id_ = other.entity_id_;
other.context_ = nullptr;
other.entity_id_ = 0;
}
return *this;
}
event_listener_handle entity::on_notify(const std::string& event,
const std::function<void(std::vector<chaiscript::Boxed_Value>)>&
callback,
const bool is_volatile)
const
{
event_listener listener;
listener.event = event;
listener.callback = callback;
listener.entity_id = this->entity_id_;
listener.is_volatile = is_volatile;
return this->context_->get_event_handler()->add_event_listener(listener);
}
unsigned int entity::get_entity_id() const
{
return this->entity_id_;
}
native::scr_entref_t entity::get_entity_reference() const
{
return game::native::Scr_GetEntityIdRef(this->get_entity_id());
}
chaiscript::Boxed_Value entity::call(const std::string& function,
const std::vector<chaiscript::Boxed_Value>& arguments) const
{
return this->context_->get_executer()->call(function, this->get_entity_id(), arguments);
}
void entity::notify(const std::string& event,
const std::vector<chaiscript::Boxed_Value>& arguments) const
{
this->context_->get_executer()->notify(event, this->get_entity_id(), arguments);
}
void entity::set(const std::string& field, const chaiscript::Boxed_Value& value) const
{
this->context_->get_executer()->set_entity_field(field, this->get_entity_id(), value);
}
chaiscript::Boxed_Value entity::get(const std::string& field) const
{
return this->context_->get_executer()->get_entity_field(field, this->get_entity_id());
}
void entity::add() const
{
if (this->entity_id_)
{
native::VariableValue value;
value.type = native::SCRIPT_OBJECT;
value.u.entityId = this->entity_id_;
native::AddRefToValue(&value);
}
}
void entity::release() const
{
if (this->entity_id_)
{
native::RemoveRefToValue(native::SCRIPT_OBJECT, {static_cast<int>(this->entity_id_)});
}
} }
} }
} }

View File

@ -1,45 +1,42 @@
#pragma once #pragma once
#include "game/game.hpp" #include "game/game.hpp"
namespace game namespace game::scripting
{ {
namespace scripting class context;
{ class event_listener_handle;
class context;
class event_listener_handle; class entity final
{
class entity final public:
{ entity();
public: entity(const entity& other);
entity(); entity(entity&& other) noexcept;
entity(const entity& other); entity(context* context, unsigned int entity_id);
entity(entity&& other) noexcept; ~entity();
entity(context* context, unsigned int entity_id);
~entity(); entity& operator=(const entity& other);
entity& operator=(entity&& other) noexcept;
entity& operator=(const entity& other);
entity& operator=(entity&& other) noexcept; event_listener_handle on_notify(const std::string& event,
const std::function<void(std::vector<chaiscript::Boxed_Value>)>& callback,
event_listener_handle on_notify(const std::string& event, bool is_volatile) const;
const std::function<void(std::vector<chaiscript::Boxed_Value>)>& callback,
bool is_volatile) const; unsigned int get_entity_id() const;
game::native::scr_entref_t get_entity_reference() const;
unsigned int get_entity_id() const;
game::native::scr_entref_t get_entity_reference() const; chaiscript::Boxed_Value call(const std::string& function,
const std::vector<chaiscript::Boxed_Value>& arguments) const;
chaiscript::Boxed_Value call(const std::string& function, void notify(const std::string& event, const std::vector<chaiscript::Boxed_Value>& arguments) const;
const std::vector<chaiscript::Boxed_Value>& arguments) const;
void notify(const std::string& event, const std::vector<chaiscript::Boxed_Value>& arguments) const; void set(const std::string& field, const chaiscript::Boxed_Value& value) const;
chaiscript::Boxed_Value get(const std::string& field) const;
void set(const std::string& field, const chaiscript::Boxed_Value& value) const;
chaiscript::Boxed_Value get(const std::string& field) const; private:
context* context_;
private: unsigned int entity_id_;
context* context_;
unsigned int entity_id_; void add() const;
void release() const;
void add() const; };
void release() const; }
};
}
}

View File

@ -1,16 +1,13 @@
#pragma once #pragma once
#include "game/game.hpp" #include "game/game.hpp"
namespace game namespace game::scripting
{ {
namespace scripting class event final
{ {
class event final public:
{ std::string name;
public: unsigned int entity_id;
std::string name; std::vector<native::VariableValue> arguments;
unsigned int entity_id; };
std::vector<native::VariableValue> arguments; }
};
}
}

View File

@ -1,123 +1,120 @@
#include "std_include.hpp" #include "std_include.hpp"
#include "context.hpp" #include "context.hpp"
namespace game namespace game::scripting
{ {
namespace scripting event_handler::event_handler(context* context) : context_(context)
{ {
event_handler::event_handler(context* context) : context_(context) const auto chai = this->context_->get_chai();
chai->add(chaiscript::user_type<event_listener_handle>(), "_event_listener_handle");
chai->add(chaiscript::constructor<event_listener_handle()>(), "_event_listener_handle");
chai->add(chaiscript::constructor<event_listener_handle(const event_listener_handle&)>(),
"_event_listener_handle");
chai->add(chaiscript::fun(
[](event_listener_handle& lhs, const event_listener_handle& rhs) -> event_listener_handle&
{
return lhs = rhs;
}), "=");
chai->add(chaiscript::fun([this](const event_listener_handle& handle)
{ {
const auto chai = this->context_->get_chai(); this->remove(handle);
}), "clear");
}
chai->add(chaiscript::user_type<event_listener_handle>(), "_event_listener_handle"); void event_handler::dispatch(event* event)
chai->add(chaiscript::constructor<event_listener_handle()>(), "_event_listener_handle"); {
chai->add(chaiscript::constructor<event_listener_handle(const event_listener_handle&)>(), try
"_event_listener_handle"); {
std::vector<chaiscript::Boxed_Value> arguments;
chai->add(chaiscript::fun( for (auto argument : event->arguments)
[](event_listener_handle& lhs, const event_listener_handle& rhs) -> event_listener_handle&
{
return lhs = rhs;
}), "=");
chai->add(chaiscript::fun([this](const event_listener_handle& handle)
{ {
this->remove(handle); arguments.push_back(this->context_->get_parameters()->load(argument));
}), "clear"); }
this->dispatch_to_specific_listeners(event, arguments);
this->dispatch_to_generic_listeners(event, arguments);
} }
catch (chaiscript::exception::eval_error& e)
void event_handler::dispatch(event* event)
{ {
try throw std::runtime_error(e.pretty_print());
{ }
std::vector<chaiscript::Boxed_Value> arguments; }
for (auto argument : event->arguments) void event_handler::dispatch_to_specific_listeners(event* event,
const std::vector<chaiscript::Boxed_Value>& arguments)
{
for (auto listener : this->event_listeners_)
{
if (listener->event == event->name && listener->entity_id == event->entity_id)
{
if (listener->is_volatile)
{ {
arguments.push_back(this->context_->get_parameters()->load(argument)); this->event_listeners_.remove(listener);
} }
this->dispatch_to_specific_listeners(event, arguments); listener->callback(arguments);
this->dispatch_to_generic_listeners(event, arguments);
} }
catch (chaiscript::exception::eval_error& e) }
}
void event_handler::dispatch_to_generic_listeners(event* event,
const std::vector<chaiscript::Boxed_Value>& arguments)
{
for (auto listener : this->generic_event_listeners_)
{
if (listener->event == event->name)
{ {
throw std::runtime_error(e.pretty_print()); if (listener->is_volatile)
{
this->generic_event_listeners_.remove(listener);
}
listener->callback(entity(this->context_, event->entity_id), arguments);
}
}
}
event_listener_handle event_handler::add_event_listener(event_listener listener)
{
listener.id = ++this->current_listener_id_;
this->event_listeners_.add(listener);
return {listener.id};
}
event_listener_handle event_handler::add_event_listener(generic_event_listener listener)
{
listener.id = ++this->current_listener_id_;
this->generic_event_listeners_.add(listener);
return {listener.id};
}
void event_handler::clear()
{
this->event_listeners_.clear();
this->generic_event_listeners_.clear();
}
void event_handler::remove(const event_listener_handle& handle)
{
for (const auto task : this->event_listeners_)
{
if (task->id == handle.id)
{
this->event_listeners_.remove(task);
return;
} }
} }
void event_handler::dispatch_to_specific_listeners(event* event, for (const auto task : this->generic_event_listeners_)
const std::vector<chaiscript::Boxed_Value>& arguments)
{ {
for (auto listener : this->event_listeners_) if (task->id == handle.id)
{ {
if (listener->event == event->name && listener->entity_id == event->entity_id) this->generic_event_listeners_.remove(task);
{ return;
if (listener->is_volatile)
{
this->event_listeners_.remove(listener);
}
listener->callback(arguments);
}
}
}
void event_handler::dispatch_to_generic_listeners(event* event,
const std::vector<chaiscript::Boxed_Value>& arguments)
{
for (auto listener : this->generic_event_listeners_)
{
if (listener->event == event->name)
{
if (listener->is_volatile)
{
this->generic_event_listeners_.remove(listener);
}
listener->callback(entity(this->context_, event->entity_id), arguments);
}
}
}
event_listener_handle event_handler::add_event_listener(event_listener listener)
{
listener.id = ++this->current_listener_id_;
this->event_listeners_.add(listener);
return {listener.id};
}
event_listener_handle event_handler::add_event_listener(generic_event_listener listener)
{
listener.id = ++this->current_listener_id_;
this->generic_event_listeners_.add(listener);
return {listener.id};
}
void event_handler::clear()
{
this->event_listeners_.clear();
this->generic_event_listeners_.clear();
}
void event_handler::remove(const event_listener_handle& handle)
{
for (const auto task : this->event_listeners_)
{
if (task->id == handle.id)
{
this->event_listeners_.remove(task);
return;
}
}
for (const auto task : this->generic_event_listeners_)
{
if (task->id == handle.id)
{
this->generic_event_listeners_.remove(task);
return;
}
} }
} }
} }

View File

@ -1,60 +1,57 @@
#pragma once #pragma once
#include "utils/concurrent_list.hpp" #include "utils/concurrent_list.hpp"
#include "entity.hpp" #include "entity.hpp"
#include "event.hpp" #include "event.hpp"
namespace game namespace game::scripting
{ {
namespace scripting class context;
{
class context; class event_listener_handle
{
class event_listener_handle public:
{ unsigned long long id = 0;
public: };
unsigned long long id = 0;
}; class event_listener final : public event_listener_handle
{
class event_listener final : public event_listener_handle public:
{ std::string event = {};
public: unsigned int entity_id = 0;
std::string event = {}; std::function<void(std::vector<chaiscript::Boxed_Value>)> callback = {};
unsigned int entity_id = 0; bool is_volatile = false;
std::function<void(std::vector<chaiscript::Boxed_Value>)> callback = {}; };
bool is_volatile = false;
}; class generic_event_listener final : public event_listener_handle
{
class generic_event_listener final : public event_listener_handle public:
{ std::string event = {};
public: std::function<void(entity, std::vector<chaiscript::Boxed_Value>)> callback = {};
std::string event = {}; bool is_volatile = false;
std::function<void(entity, std::vector<chaiscript::Boxed_Value>)> callback = {}; };
bool is_volatile = false;
}; class event_handler final
{
class event_handler final public:
{ explicit event_handler(context* context);
public:
explicit event_handler(context* context); void dispatch(event* event);
void dispatch(event* event); event_listener_handle add_event_listener(event_listener listener);
event_listener_handle add_event_listener(generic_event_listener listener);
event_listener_handle add_event_listener(event_listener listener);
event_listener_handle add_event_listener(generic_event_listener listener); void clear();
void clear(); private:
context* context_;
private: std::atomic_int64_t current_listener_id_ = 0;
context* context_;
std::atomic_int64_t current_listener_id_ = 0; utils::concurrent_list<event_listener> event_listeners_;
utils::concurrent_list<generic_event_listener> generic_event_listeners_;
utils::concurrent_list<event_listener> event_listeners_;
utils::concurrent_list<generic_event_listener> generic_event_listeners_; void dispatch_to_specific_listeners(event* event, const std::vector<chaiscript::Boxed_Value>& arguments);
void dispatch_to_generic_listeners(event* event, const std::vector<chaiscript::Boxed_Value>& arguments);
void dispatch_to_specific_listeners(event* event, const std::vector<chaiscript::Boxed_Value>& arguments);
void dispatch_to_generic_listeners(event* event, const std::vector<chaiscript::Boxed_Value>& arguments); void remove(const event_listener_handle& handle);
};
void remove(const event_listener_handle& handle); }
};
}
}

View File

@ -6,167 +6,164 @@
#include "safe_executer.hpp" #include "safe_executer.hpp"
#include "context.hpp" #include "context.hpp"
namespace game namespace game::scripting
{ {
namespace scripting executer::executer(context* context) : context_(context)
{ {
executer::executer(context* context) : context_(context) }
int executer::get_field_id(const int classnum, const std::string& field) const
{
const auto field_name = utils::string::to_lower(field);
const auto class_id = native::g_classMap[classnum].id;
const auto field_str = native::SL_GetString(field_name.data(), 1);
const auto _ = gsl::finally([field_str]()
{ {
native::RemoveRefToValue(native::SCRIPT_STRING, {int(field_str)});
});
const auto offset = native::FindVariable(class_id, field_str);
if (offset)
{
const auto index = 4 * (offset + 0xC800 * (class_id & 1));
return PINT(SELECT_VALUE(0x1A3BC80, 0x1EFE180, 0x1DC8800))[index];
} }
int executer::get_field_id(const int classnum, const std::string& field) const return -1;
{ }
const auto field_name = utils::string::to_lower(field);
const auto class_id = native::g_classMap[classnum].id;
const auto field_str = native::SL_GetString(field_name.data(), 1);
const auto _ = gsl::finally([field_str]()
{
native::RemoveRefToValue(native::SCRIPT_STRING, {int(field_str)});
});
const auto offset = native::FindVariable(class_id, field_str); void executer::set_entity_field(const std::string& field, const unsigned int entity_id,
if (offset) const chaiscript::Boxed_Value& value)
{ {
const auto index = 4 * (offset + 0xC800 * (class_id & 1)); const auto entref = native::Scr_GetEntityIdRef(entity_id);
return PINT(SELECT_VALUE(0x1A3BC80, 0x1EFE180, 0x1DC8800))[index]; const int id = get_field_id(entref.raw.classnum, field);
}
return -1; if (id != -1)
}
void executer::set_entity_field(const std::string& field, const unsigned int entity_id,
const chaiscript::Boxed_Value& value)
{
const auto entref = native::Scr_GetEntityIdRef(entity_id);
const int id = get_field_id(entref.raw.classnum, field);
if (id != -1)
{
stack_isolation _;
this->context_->get_parameters()->push(value);
native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount;
native::scr_VmPub->inparamcount = 0;
if (!safe_executer::set_entity_field(entref, id))
{
throw std::runtime_error("Failed to set value for field '" + field + "'");
}
}
else
{
this->entity_fields_[entity_id][field] = value;
}
}
chaiscript::Boxed_Value executer::get_entity_field(const std::string& field, const unsigned int entity_id)
{
const auto entref = native::Scr_GetEntityIdRef(entity_id);
const auto id = this->get_field_id(entref.raw.classnum, field);
if (id != -1)
{
stack_isolation _;
native::VariableValue value{};
if (!safe_executer::get_entity_field(entref, id, &value))
{
throw std::runtime_error("Failed to get value for field '" + field + "'");
}
const auto $ = gsl::finally([value]()
{
native::RemoveRefToValue(value.type, value.u);
});
return this->context_->get_parameters()->load(value);
}
else
{
const auto& map = this->entity_fields_[entity_id];
const auto value = map.find(field);
if (value != map.end())
{
return value->second;
}
}
return {};
}
void executer::notify(const std::string& event, const unsigned int entity_id,
std::vector<chaiscript::Boxed_Value> arguments) const
{ {
stack_isolation _; stack_isolation _;
this->context_->get_parameters()->push(value);
std::reverse(arguments.begin(), arguments.end());
for (auto argument : arguments)
{
this->context_->get_parameters()->push(argument);
}
const auto event_id = native::SL_GetString(event.data(), 0);
native::Scr_NotifyId(entity_id, event_id, native::scr_VmPub->inparamcount);
}
chaiscript::Boxed_Value executer::call(const std::string& function, const unsigned int entity_id,
std::vector<chaiscript::Boxed_Value> arguments) const
{
const auto function_index = find_function_index(function, entity_id == 0);
if (function_index < 0)
{
throw std::runtime_error("No function found for name '" + function + "'");
}
const auto entity = function_index > 0x1C7
? native::Scr_GetEntityIdRef(entity_id)
: native::scr_entref_t{~0u};
const auto function_ptr = native::Scr_GetFunc(function_index);
stack_isolation _;
std::reverse(arguments.begin(), arguments.end());
for (const auto& argument : arguments)
{
this->context_->get_parameters()->push(argument);
}
native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount; native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount;
native::scr_VmPub->inparamcount = 0; native::scr_VmPub->inparamcount = 0;
if (!safe_executer::call(function_ptr, entity)) if (!safe_executer::set_entity_field(entref, id))
{ {
throw std::runtime_error("Error executing function '" + function + "'"); throw std::runtime_error("Failed to set value for field '" + field + "'");
} }
return this->context_->get_parameters()->get_return_value();
} }
else
int executer::find_function_index(const std::string& function, const bool prefer_global)
{ {
const auto target = utils::string::to_lower(function); this->entity_fields_[entity_id][field] = value;
const auto primary_map = prefer_global
? &global_function_map
: &instance_function_map;
const auto secondary_map = !prefer_global
? &global_function_map
: &instance_function_map;
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;
} }
} }
chaiscript::Boxed_Value executer::get_entity_field(const std::string& field, const unsigned int entity_id)
{
const auto entref = native::Scr_GetEntityIdRef(entity_id);
const auto id = this->get_field_id(entref.raw.classnum, field);
if (id != -1)
{
stack_isolation _;
native::VariableValue value{};
if (!safe_executer::get_entity_field(entref, id, &value))
{
throw std::runtime_error("Failed to get value for field '" + field + "'");
}
const auto $ = gsl::finally([value]()
{
native::RemoveRefToValue(value.type, value.u);
});
return this->context_->get_parameters()->load(value);
}
else
{
const auto& map = this->entity_fields_[entity_id];
const auto value = map.find(field);
if (value != map.end())
{
return value->second;
}
}
return {};
}
void executer::notify(const std::string& event, const unsigned int entity_id,
std::vector<chaiscript::Boxed_Value> arguments) const
{
stack_isolation _;
std::reverse(arguments.begin(), arguments.end());
for (auto argument : arguments)
{
this->context_->get_parameters()->push(argument);
}
const auto event_id = native::SL_GetString(event.data(), 0);
native::Scr_NotifyId(entity_id, event_id, native::scr_VmPub->inparamcount);
}
chaiscript::Boxed_Value executer::call(const std::string& function, const unsigned int entity_id,
std::vector<chaiscript::Boxed_Value> arguments) const
{
const auto function_index = find_function_index(function, entity_id == 0);
if (function_index < 0)
{
throw std::runtime_error("No function found for name '" + function + "'");
}
const auto entity = function_index > 0x1C7
? native::Scr_GetEntityIdRef(entity_id)
: native::scr_entref_t{~0u};
const auto function_ptr = native::Scr_GetFunc(function_index);
stack_isolation _;
std::reverse(arguments.begin(), arguments.end());
for (const auto& argument : arguments)
{
this->context_->get_parameters()->push(argument);
}
native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount;
native::scr_VmPub->inparamcount = 0;
if (!safe_executer::call(function_ptr, entity))
{
throw std::runtime_error("Error executing function '" + function + "'");
}
return this->context_->get_parameters()->get_return_value();
}
int executer::find_function_index(const std::string& function, const bool prefer_global)
{
const auto target = utils::string::to_lower(function);
const auto primary_map = prefer_global
? &global_function_map
: &instance_function_map;
const auto secondary_map = !prefer_global
? &global_function_map
: &instance_function_map;
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;
}
} }

View File

@ -1,34 +1,31 @@
#pragma once #pragma once
namespace game namespace game::scripting
{ {
namespace scripting class context;
{
class context; class executer final
{
class executer final public:
{ explicit executer(context* context);
public:
explicit executer(context* context); void set_entity_field(const std::string& field, unsigned int entity_id,
const chaiscript::Boxed_Value& value);
void set_entity_field(const std::string& field, unsigned int entity_id, chaiscript::Boxed_Value get_entity_field(const std::string& field, unsigned int entity_id);
const chaiscript::Boxed_Value& value);
chaiscript::Boxed_Value get_entity_field(const std::string& field, unsigned int entity_id); void notify(const std::string& event, unsigned int entity_id,
std::vector<chaiscript::Boxed_Value> arguments) const;
void notify(const std::string& event, unsigned int entity_id,
std::vector<chaiscript::Boxed_Value> arguments) const; chaiscript::Boxed_Value call(const std::string& function, unsigned int entity_id,
std::vector<chaiscript::Boxed_Value> arguments) const;
chaiscript::Boxed_Value call(const std::string& function, unsigned int entity_id,
std::vector<chaiscript::Boxed_Value> arguments) const; private:
context* context_;
private:
context* context_; std::unordered_map<unsigned int, std::unordered_map<std::string, chaiscript::Boxed_Value>> entity_fields_;
std::unordered_map<unsigned int, std::unordered_map<std::string, chaiscript::Boxed_Value>> entity_fields_; int get_field_id(int classnum, const std::string& field) const;
int get_field_id(int classnum, const std::string& field) const; static int find_function_index(const std::string& function, bool prefer_global);
};
static int find_function_index(const std::string& function, bool prefer_global); }
};
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,7 @@
#pragma once #pragma once
namespace game namespace game::scripting
{ {
namespace scripting extern std::map<std::string, int> instance_function_map;
{ extern std::map<std::string, int> global_function_map;
extern std::map<std::string, int> instance_function_map;
extern std::map<std::string, int> global_function_map;
}
} }

View File

@ -1,153 +1,150 @@
#include "std_include.hpp" #include "std_include.hpp"
#include "context.hpp" #include "context.hpp"
namespace game namespace game::scripting
{ {
namespace scripting parameters::parameters(context* context) : context_(context)
{ {
parameters::parameters(context* context) : context_(context) }
chaiscript::Boxed_Value parameters::load(const native::VariableValue value) const
{
if (value.type == native::SCRIPT_STRING)
{ {
const std::string string = native::SL_ConvertToString(value.u.stringValue);
return chaiscript::var(string);
}
else if (value.type == native::SCRIPT_FLOAT)
{
return chaiscript::var(value.u.floatValue);
}
else if (value.type == native::SCRIPT_INTEGER)
{
return chaiscript::var(value.u.intValue);
}
else if (value.type == native::SCRIPT_OBJECT)
{
return chaiscript::var(entity(this->context_, value.u.entityId));
}
else if (value.type == native::SCRIPT_VECTOR)
{
std::vector<chaiscript::Boxed_Value> values;
values.push_back(chaiscript::var(value.u.vectorValue[0]));
values.push_back(chaiscript::var(value.u.vectorValue[1]));
values.push_back(chaiscript::var(value.u.vectorValue[2]));
return chaiscript::var(values);
} }
chaiscript::Boxed_Value parameters::load(const native::VariableValue value) const return {};
}
void parameters::push(const chaiscript::Boxed_Value& value) const
{
if (native::scr_VmPub->outparamcount)
{ {
if (value.type == native::SCRIPT_STRING) native::Scr_ClearOutParams();
{
const std::string string = native::SL_ConvertToString(value.u.stringValue);
return chaiscript::var(string);
}
else if (value.type == native::SCRIPT_FLOAT)
{
return chaiscript::var(value.u.floatValue);
}
else if (value.type == native::SCRIPT_INTEGER)
{
return chaiscript::var(value.u.intValue);
}
else if (value.type == native::SCRIPT_OBJECT)
{
return chaiscript::var(entity(this->context_, value.u.entityId));
}
else if (value.type == native::SCRIPT_VECTOR)
{
std::vector<chaiscript::Boxed_Value> values;
values.push_back(chaiscript::var(value.u.vectorValue[0]));
values.push_back(chaiscript::var(value.u.vectorValue[1]));
values.push_back(chaiscript::var(value.u.vectorValue[2]));
return chaiscript::var(values);
}
return {};
} }
void parameters::push(const chaiscript::Boxed_Value& value) const if (native::scr_VmPub->top == native::scr_VmPub->maxstack)
{ {
if (native::scr_VmPub->outparamcount) throw std::runtime_error("Internal script stack overflow");
}
native::VariableValue* value_ptr = ++native::scr_VmPub->top;
++native::scr_VmPub->inparamcount;
value_ptr->type = native::SCRIPT_NONE;
value_ptr->u.intValue = 0;
if (value.get_type_info() == typeid(float))
{
const auto real_value = this->context_->get_chai()->boxed_cast<float>(value);
value_ptr->type = native::SCRIPT_FLOAT;
value_ptr->u.floatValue = real_value;
}
else if (value.get_type_info() == typeid(double))
{
const auto real_value = this->context_->get_chai()->boxed_cast<double>(value);
value_ptr->type = native::SCRIPT_FLOAT;
value_ptr->u.floatValue = static_cast<float>(real_value);
}
else if (value.get_type_info() == typeid(int))
{
const auto real_value = this->context_->get_chai()->boxed_cast<int>(value);
value_ptr->type = native::SCRIPT_INTEGER;
value_ptr->u.intValue = real_value;
}
else if (value.get_type_info() == typeid(bool))
{
const auto real_value = this->context_->get_chai()->boxed_cast<bool>(value);
value_ptr->type = native::SCRIPT_INTEGER;
value_ptr->u.intValue = real_value;
}
else if (value.get_type_info() == typeid(entity))
{
const auto real_value = this->context_->get_chai()->boxed_cast<entity>(value);
value_ptr->type = native::SCRIPT_OBJECT;
value_ptr->u.entityId = real_value.get_entity_id();
game::native::AddRefToValue(value_ptr);
}
else if (value.get_type_info() == typeid(std::string))
{
const auto real_value = this->context_->get_chai()->boxed_cast<std::string>(value);
value_ptr->type = native::SCRIPT_STRING;
value_ptr->u.stringValue = game::native::SL_GetString(real_value.data(), 0);
}
else if (value.get_type_info() == typeid(std::vector<chaiscript::Boxed_Value>))
{
float values[3];
const auto real_value = this->context_->get_chai()->boxed_cast<std::vector<chaiscript::Boxed_Value>
>(value);
if (real_value.size() != 3)
{ {
native::Scr_ClearOutParams(); throw std::runtime_error("Invalid vector length. Size must be exactly 3");
} }
if (native::scr_VmPub->top == native::scr_VmPub->maxstack) const auto unbox_float = [&real_value, this](const size_t index) -> float
{ {
throw std::runtime_error("Internal script stack overflow"); const auto value = real_value[index];
} if (value.get_type_info() == typeid(float))
native::VariableValue* value_ptr = ++native::scr_VmPub->top;
++native::scr_VmPub->inparamcount;
value_ptr->type = native::SCRIPT_NONE;
value_ptr->u.intValue = 0;
if (value.get_type_info() == typeid(float))
{
const auto real_value = this->context_->get_chai()->boxed_cast<float>(value);
value_ptr->type = native::SCRIPT_FLOAT;
value_ptr->u.floatValue = real_value;
}
else if (value.get_type_info() == typeid(double))
{
const auto real_value = this->context_->get_chai()->boxed_cast<double>(value);
value_ptr->type = native::SCRIPT_FLOAT;
value_ptr->u.floatValue = static_cast<float>(real_value);
}
else if (value.get_type_info() == typeid(int))
{
const auto real_value = this->context_->get_chai()->boxed_cast<int>(value);
value_ptr->type = native::SCRIPT_INTEGER;
value_ptr->u.intValue = real_value;
}
else if (value.get_type_info() == typeid(bool))
{
const auto real_value = this->context_->get_chai()->boxed_cast<bool>(value);
value_ptr->type = native::SCRIPT_INTEGER;
value_ptr->u.intValue = real_value;
}
else if (value.get_type_info() == typeid(entity))
{
const auto real_value = this->context_->get_chai()->boxed_cast<entity>(value);
value_ptr->type = native::SCRIPT_OBJECT;
value_ptr->u.entityId = real_value.get_entity_id();
game::native::AddRefToValue(value_ptr);
}
else if (value.get_type_info() == typeid(std::string))
{
const auto real_value = this->context_->get_chai()->boxed_cast<std::string>(value);
value_ptr->type = native::SCRIPT_STRING;
value_ptr->u.stringValue = game::native::SL_GetString(real_value.data(), 0);
}
else if (value.get_type_info() == typeid(std::vector<chaiscript::Boxed_Value>))
{
float values[3];
const auto real_value = this->context_->get_chai()->boxed_cast<std::vector<chaiscript::Boxed_Value>
>(value);
if (real_value.size() != 3)
{ {
throw std::runtime_error("Invalid vector length. Size must be exactly 3"); return this->context_->get_chai()->boxed_cast<float>(value);
}
if (value.get_type_info() == typeid(double))
{
return float(this->context_->get_chai()->boxed_cast<double>(value));
}
if (value.get_type_info() == typeid(int))
{
return float(this->context_->get_chai()->boxed_cast<int>(value));
} }
const auto unbox_float = [&real_value, this](const size_t index) -> float throw std::runtime_error("Vector element at index " + std::to_string(index) + " is not a number");
{ };
const auto value = real_value[index];
if (value.get_type_info() == typeid(float))
{
return this->context_->get_chai()->boxed_cast<float>(value);
}
if (value.get_type_info() == typeid(double))
{
return float(this->context_->get_chai()->boxed_cast<double>(value));
}
if (value.get_type_info() == typeid(int))
{
return float(this->context_->get_chai()->boxed_cast<int>(value));
}
throw std::runtime_error("Vector element at index " + std::to_string(index) + " is not a number"); values[0] = unbox_float(0);
}; values[1] = unbox_float(1);
values[2] = unbox_float(2);
values[0] = unbox_float(0); value_ptr->type = native::SCRIPT_VECTOR;
values[1] = unbox_float(1); value_ptr->u.vectorValue = native::Scr_AllocVector(values);
values[2] = unbox_float(2);
value_ptr->type = native::SCRIPT_VECTOR;
value_ptr->u.vectorValue = native::Scr_AllocVector(values);
}
else
{
throw std::runtime_error("Unable to unbox value of type '" + value.get_type_info().bare_name() + "'");
}
} }
else
chaiscript::Boxed_Value parameters::get_return_value() const
{ {
if (native::scr_VmPub->inparamcount == 0) return {}; throw std::runtime_error("Unable to unbox value of type '" + value.get_type_info().bare_name() + "'");
native::Scr_ClearOutParams();
native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount;
native::scr_VmPub->inparamcount = 0;
return this->load(native::scr_VmPub->top[1 - native::scr_VmPub->outparamcount]);
} }
} }
chaiscript::Boxed_Value parameters::get_return_value() const
{
if (native::scr_VmPub->inparamcount == 0) return {};
native::Scr_ClearOutParams();
native::scr_VmPub->outparamcount = native::scr_VmPub->inparamcount;
native::scr_VmPub->inparamcount = 0;
return this->load(native::scr_VmPub->top[1 - native::scr_VmPub->outparamcount]);
}
} }

View File

@ -1,23 +1,20 @@
#pragma once #pragma once
#include "game/game.hpp" #include "game/game.hpp"
namespace game namespace game::scripting
{ {
namespace scripting class context;
{
class context; class parameters final
{
class parameters final public:
{ explicit parameters(context* context);
public:
explicit parameters(context* context); void push(const chaiscript::Boxed_Value& value) const;
chaiscript::Boxed_Value load(native::VariableValue value) const;
void push(const chaiscript::Boxed_Value& value) const;
chaiscript::Boxed_Value load(native::VariableValue value) const; chaiscript::Boxed_Value get_return_value() const;
private:
chaiscript::Boxed_Value get_return_value() const; context* context_;
private: };
context* context_; }
};
}
}

View File

@ -1,63 +1,59 @@
#include "std_include.hpp" #include "std_include.hpp"
#include "safe_executer.hpp" #include "safe_executer.hpp"
#pragma warning(push) #pragma warning(push)
#pragma warning(disable: 4611) #pragma warning(disable: 4611)
namespace game
{ namespace game::scripting::safe_executer
namespace scripting {
{ static_assert(sizeof(jmp_buf) == 64);
namespace safe_executer
{ bool call(const native::scr_call_t function, const native::scr_entref_t entref)
static_assert(sizeof(jmp_buf) == 64); {
*native::g_script_error_level += 1;
bool call(const native::scr_call_t function, const native::scr_entref_t entref) if (setjmp(native::g_script_error[*native::g_script_error_level]))
{ {
*native::g_script_error_level += 1; *native::g_script_error_level -= 1;
if (setjmp(native::g_script_error[*native::g_script_error_level])) return false;
{ }
*native::g_script_error_level -= 1;
return false; function(entref.val);
}
*native::g_script_error_level -= 1;
function(entref.val); return true;
}
*native::g_script_error_level -= 1;
return true; bool set_entity_field(const native::scr_entref_t entref, const int offset)
} {
*native::g_script_error_level += 1;
bool set_entity_field(const native::scr_entref_t entref, const int offset) if (setjmp(native::g_script_error[*native::g_script_error_level]))
{ {
*native::g_script_error_level += 1; *native::g_script_error_level -= 1;
if (setjmp(native::g_script_error[*native::g_script_error_level])) return false;
{ }
*native::g_script_error_level -= 1;
return false; native::Scr_SetObjectField(entref.raw.classnum, entref.raw.entnum, offset);
}
*native::g_script_error_level -= 1;
native::Scr_SetObjectField(entref.raw.classnum, entref.raw.entnum, offset); return true;
}
*native::g_script_error_level -= 1;
return true; bool get_entity_field(const native::scr_entref_t entref, const int offset, native::VariableValue* value)
} {
*native::g_script_error_level += 1;
bool get_entity_field(const native::scr_entref_t entref, const int offset, native::VariableValue* value) if (setjmp(native::g_script_error[*native::g_script_error_level]))
{ {
*native::g_script_error_level += 1; value->type = native::SCRIPT_NONE;
if (setjmp(native::g_script_error[*native::g_script_error_level])) value->u.intValue = 0;
{ *native::g_script_error_level -= 1;
value->type = native::SCRIPT_NONE; return false;
value->u.intValue = 0; }
*native::g_script_error_level -= 1;
return false; *value = native::GetEntityFieldValue(entref.raw.classnum, entref.raw.entnum, offset);
}
*native::g_script_error_level -= 1;
*value = native::GetEntityFieldValue(entref.raw.classnum, entref.raw.entnum, offset); return true;
}
*native::g_script_error_level -= 1; }
return true;
} #pragma warning(pop)
}
}
}
#pragma warning(pop)

View File

@ -1,15 +1,9 @@
#pragma once #pragma once
#include "game/game.hpp" #include "game/game.hpp"
namespace game namespace game::scripting::safe_executer
{ {
namespace scripting bool call(const native::scr_call_t function, const native::scr_entref_t entref);
{ bool set_entity_field(const native::scr_entref_t entref, const int offset);
namespace safe_executer bool get_entity_field(const native::scr_entref_t entref, const int offset, native::VariableValue* value);
{ }
bool call(const native::scr_call_t function, const native::scr_entref_t entref);
bool set_entity_field(const native::scr_entref_t entref, const int offset);
bool get_entity_field(const native::scr_entref_t entref, const int offset, native::VariableValue* value);
}
}
}

View File

@ -1,98 +1,95 @@
#include "std_include.hpp" #include "std_include.hpp"
#include "context.hpp" #include "context.hpp"
namespace game namespace game::scripting
{ {
namespace scripting scheduler::scheduler(context* context) : context_(context)
{ {
scheduler::scheduler(context* context) : context_(context) const auto chai = this->context_->get_chai();
chai->add(chaiscript::user_type<task_handle>(), "_task_handle");
chai->add(chaiscript::constructor<task_handle()>(), "_task_handle");
chai->add(chaiscript::constructor<task_handle(const task_handle&)>(), "_task_handle");
chai->add(chaiscript::fun([](task_handle& lhs, const task_handle& rhs) -> task_handle&
{ {
const auto chai = this->context_->get_chai(); return lhs = rhs;
}), "=");
chai->add(chaiscript::user_type<task_handle>(), "_task_handle"); chai->add(chaiscript::fun(
chai->add(chaiscript::constructor<task_handle()>(), "_task_handle"); [this](const std::function<void()>& callback, const long long milliseconds) -> task_handle
chai->add(chaiscript::constructor<task_handle(const task_handle&)>(), "_task_handle"); {
return this->add(callback, milliseconds, true);
}), "setTimeout");
chai->add(chaiscript::fun([](task_handle& lhs, const task_handle& rhs) -> task_handle& chai->add(chaiscript::fun(
[this](const std::function<void()>& callback, const long long milliseconds) -> task_handle
{
return this->add(callback, milliseconds, false);
}), "setInterval");
const auto clear = [this](const task_handle& handle)
{
this->remove(handle);
};
chai->add(chaiscript::fun(clear), "clear");
chai->add(chaiscript::fun(clear), "clearTimeout");
chai->add(chaiscript::fun(clear), "clearInterval");
}
void scheduler::run_frame()
{
for (auto task : this->tasks_)
{
const auto now = std::chrono::steady_clock::now();
if ((now - task->last_execution) > task->delay)
{ {
return lhs = rhs; task->last_execution = now;
}), "="); if (task->is_volatile)
chai->add(chaiscript::fun(
[this](const std::function<void()>& callback, const long long milliseconds) -> task_handle
{
return this->add(callback, milliseconds, true);
}), "setTimeout");
chai->add(chaiscript::fun(
[this](const std::function<void()>& callback, const long long milliseconds) -> task_handle
{
return this->add(callback, milliseconds, false);
}), "setInterval");
const auto clear = [this](const task_handle& handle)
{
this->remove(handle);
};
chai->add(chaiscript::fun(clear), "clear");
chai->add(chaiscript::fun(clear), "clearTimeout");
chai->add(chaiscript::fun(clear), "clearInterval");
}
void scheduler::run_frame()
{
for (auto task : this->tasks_)
{
const auto now = std::chrono::steady_clock::now();
if ((now - task->last_execution) > task->delay)
{
task->last_execution = now;
if (task->is_volatile)
{
this->tasks_.remove(task);
}
task->callback();
}
}
}
void scheduler::clear()
{
this->tasks_.clear();
}
task_handle scheduler::add(const std::function<void()>& callback, const long long milliseconds,
const bool is_volatile)
{
return this->add(callback, std::chrono::milliseconds(milliseconds), is_volatile);
}
task_handle scheduler::add(const std::function<void()>& callback, const std::chrono::milliseconds delay,
const bool is_volatile)
{
task task;
task.is_volatile = is_volatile;
task.callback = callback;
task.delay = delay;
task.last_execution = std::chrono::steady_clock::now();
task.id = ++this->current_task_id_;
this->tasks_.add(task);
return {task.id};
}
void scheduler::remove(const task_handle& handle)
{
for (auto task : this->tasks_)
{
if (task->id == handle.id)
{ {
this->tasks_.remove(task); this->tasks_.remove(task);
break;
} }
task->callback();
}
}
}
void scheduler::clear()
{
this->tasks_.clear();
}
task_handle scheduler::add(const std::function<void()>& callback, const long long milliseconds,
const bool is_volatile)
{
return this->add(callback, std::chrono::milliseconds(milliseconds), is_volatile);
}
task_handle scheduler::add(const std::function<void()>& callback, const std::chrono::milliseconds delay,
const bool is_volatile)
{
task task;
task.is_volatile = is_volatile;
task.callback = callback;
task.delay = delay;
task.last_execution = std::chrono::steady_clock::now();
task.id = ++this->current_task_id_;
this->tasks_.add(task);
return {task.id};
}
void scheduler::remove(const task_handle& handle)
{
for (auto task : this->tasks_)
{
if (task->id == handle.id)
{
this->tasks_.remove(task);
break;
} }
} }
} }

View File

@ -1,45 +1,42 @@
#pragma once #pragma once
#include "utils/concurrent_list.hpp" #include "utils/concurrent_list.hpp"
namespace game namespace game::scripting
{ {
namespace scripting class context;
{
class context; class task_handle
{
class task_handle public:
{ unsigned long long id = 0;
public: };
unsigned long long id = 0;
}; class task final : public task_handle
{
class task final : public task_handle public:
{ std::chrono::steady_clock::time_point last_execution{};
public: std::function<void()> callback{};
std::chrono::steady_clock::time_point last_execution{}; std::chrono::milliseconds delay{};
std::function<void()> callback{}; bool is_volatile = false;
std::chrono::milliseconds delay{}; };
bool is_volatile = false;
}; class scheduler final
{
class scheduler final public:
{ explicit scheduler(context* context);
public:
explicit scheduler(context* context); void run_frame();
void clear();
void run_frame();
void clear(); private:
context* context_;
private:
context* context_; utils::concurrent_list<task> tasks_;
std::atomic_int64_t current_task_id_ = 0;
utils::concurrent_list<task> tasks_;
std::atomic_int64_t current_task_id_ = 0; task_handle add(const std::function<void()>& callback, long long milliseconds, bool is_volatile);
task_handle add(const std::function<void()>& callback, std::chrono::milliseconds delay, bool is_volatile);
task_handle add(const std::function<void()>& callback, long long milliseconds, bool is_volatile);
task_handle add(const std::function<void()>& callback, std::chrono::milliseconds delay, bool is_volatile); void remove(const task_handle& handle);
};
void remove(const task_handle& handle); }
};
}
}

View File

@ -1,30 +1,27 @@
#include "std_include.hpp" #include "std_include.hpp"
#include "stack_isolation.hpp" #include "stack_isolation.hpp"
namespace game namespace game::scripting
{ {
namespace scripting stack_isolation::stack_isolation()
{ {
stack_isolation::stack_isolation() this->in_param_count_ = native::scr_VmPub->inparamcount;
{ this->out_param_count_ = native::scr_VmPub->outparamcount;
this->in_param_count_ = native::scr_VmPub->inparamcount; this->top_ = native::scr_VmPub->top;
this->out_param_count_ = native::scr_VmPub->outparamcount; this->max_stack_ = native::scr_VmPub->maxstack;
this->top_ = native::scr_VmPub->top;
this->max_stack_ = native::scr_VmPub->maxstack; native::scr_VmPub->top = this->stack_;
native::scr_VmPub->maxstack = &this->stack_[ARRAYSIZE(this->stack_) - 1];
native::scr_VmPub->top = this->stack_; native::scr_VmPub->inparamcount = 0;
native::scr_VmPub->maxstack = &this->stack_[ARRAYSIZE(this->stack_) - 1]; native::scr_VmPub->outparamcount = 0;
native::scr_VmPub->inparamcount = 0; }
native::scr_VmPub->outparamcount = 0;
} stack_isolation::~stack_isolation()
{
stack_isolation::~stack_isolation() native::Scr_ClearOutParams();
{ native::scr_VmPub->inparamcount = this->in_param_count_;
native::Scr_ClearOutParams(); native::scr_VmPub->outparamcount = this->out_param_count_;
native::scr_VmPub->inparamcount = this->in_param_count_; native::scr_VmPub->top = this->top_;
native::scr_VmPub->outparamcount = this->out_param_count_; native::scr_VmPub->maxstack = this->max_stack_;
native::scr_VmPub->top = this->top_; }
native::scr_VmPub->maxstack = this->max_stack_; }
}
}
}

View File

@ -1,23 +1,20 @@
#pragma once #pragma once
#include "game/game.hpp" #include "game/game.hpp"
namespace game namespace game::scripting
{ {
namespace scripting class stack_isolation final
{ {
class stack_isolation final public:
{ stack_isolation();
public: ~stack_isolation();
stack_isolation();
~stack_isolation(); private:
native::VariableValue stack_[512]{};
private:
native::VariableValue stack_[512]{}; native::VariableValue* max_stack_;
native::VariableValue* top_;
native::VariableValue* max_stack_; unsigned int in_param_count_;
native::VariableValue* top_; unsigned int out_param_count_;
unsigned int in_param_count_; };
unsigned int out_param_count_; }
};
}
}

View File

@ -1,23 +1,20 @@
#include "std_include.hpp" #include "std_include.hpp"
#include "variable_value.hpp" #include "variable_value.hpp"
namespace game namespace game::scripting
{ {
namespace scripting variable_value::variable_value(native::VariableValue value) : value_(value)
{ {
variable_value::variable_value(native::VariableValue value) : value_(value) native::AddRefToValue(&value);
{ }
native::AddRefToValue(&value);
} variable_value::~variable_value()
{
variable_value::~variable_value() native::RemoveRefToValue(this->value_.type, this->value_.u);
{ }
native::RemoveRefToValue(this->value_.type, this->value_.u);
} variable_value::operator native::VariableValue() const
{
variable_value::operator native::VariableValue() const return this->value_;
{ }
return this->value_; }
}
}
}

View File

@ -1,20 +1,17 @@
#pragma once #pragma once
#include "game/game.hpp" #include "game/game.hpp"
namespace game namespace game::scripting
{ {
namespace scripting class variable_value final
{ {
class variable_value final public:
{ explicit variable_value(native::VariableValue value);
public: ~variable_value();
explicit variable_value(native::VariableValue value);
~variable_value(); explicit operator native::VariableValue() const;
explicit operator native::VariableValue() const; private:
native::VariableValue value_;
private: };
native::VariableValue value_; }
};
}
}

View File

@ -254,7 +254,7 @@ namespace demonware
auto queue = datagram_packets_.find(s); auto queue = datagram_packets_.find(s);
if (queue != datagram_packets_.end()) if (queue != datagram_packets_.end())
{ {
const bool blocking = is_blocking_socket(s, UDP_BLOCKING); const auto blocking = is_blocking_socket(s, UDP_BLOCKING);
lock.unlock(); lock.unlock();
while (blocking && queue->second.empty()) while (blocking && queue->second.empty())

View File

@ -37,7 +37,7 @@
<body> <body>
<div class="content"> <div class="content">
<h1>No settings, yet!</h1> <h3>No settings, yet!</h3>
</div> </div>
</body> </body>

View File

@ -1,73 +1,70 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "memory.hpp" #include "memory.hpp"
#include "compression.hpp" #include "compression.hpp"
namespace utils namespace utils::compression
{ {
namespace compression std::string zlib::compress(const std::string& data)
{ {
std::string zlib::compress(const std::string& data) memory::allocator allocator;
{ unsigned long length = (data.size() * 2);
memory::allocator allocator; if (!length) length = 2;
unsigned long length = (data.size() * 2);
if (!length) length = 2; if (length < 100) length *= 10;
if (length < 100) length *= 10; const auto buffer = allocator.allocate_array<char>(length);
if (compress2(reinterpret_cast<Bytef*>(buffer), &length,
const auto buffer = allocator.allocate_array<char>(length); reinterpret_cast<Bytef*>(const_cast<char*>(data.data())), data.size(),
if (compress2(reinterpret_cast<Bytef*>(buffer), &length, Z_BEST_COMPRESSION) != Z_OK)
reinterpret_cast<Bytef*>(const_cast<char*>(data.data())), data.size(), {
Z_BEST_COMPRESSION) != Z_OK) return {};
{ }
return {};
} return std::string(buffer, length);
}
return std::string(buffer, length);
} std::string zlib::decompress(const std::string& data)
{
std::string zlib::decompress(const std::string& data) z_stream stream;
{ ZeroMemory(&stream, sizeof(stream));
z_stream stream; std::string buffer;
ZeroMemory(&stream, sizeof(stream));
std::string buffer; if (inflateInit(&stream) != Z_OK)
{
if (inflateInit(&stream) != Z_OK) return {};
{ }
return {};
} int ret;
memory::allocator allocator;
int ret;
memory::allocator allocator; const auto dest = allocator.allocate_array<uint8_t>(CHUNK);
auto data_ptr = data.data();
const auto dest = allocator.allocate_array<uint8_t>(CHUNK);
auto data_ptr = data.data(); do
{
do stream.avail_in = std::min(static_cast<size_t>(CHUNK), data.size() - (data_ptr - data.data()));
{ stream.next_in = reinterpret_cast<const uint8_t*>(data_ptr);
stream.avail_in = std::min(static_cast<size_t>(CHUNK), data.size() - (data_ptr - data.data())); data_ptr += stream.avail_in;
stream.next_in = reinterpret_cast<const uint8_t*>(data_ptr);
data_ptr += stream.avail_in; do
{
do stream.avail_out = CHUNK;
{ stream.next_out = dest;
stream.avail_out = CHUNK;
stream.next_out = dest; ret = inflate(&stream, Z_NO_FLUSH);
if (ret != Z_OK && ret != Z_STREAM_END)
ret = inflate(&stream, Z_NO_FLUSH); {
if (ret != Z_OK && ret != Z_STREAM_END) inflateEnd(&stream);
{ return {};
inflateEnd(&stream); }
return {};
} buffer.append(reinterpret_cast<const char*>(dest), CHUNK - stream.avail_out);
}
buffer.append(reinterpret_cast<const char*>(dest), CHUNK - stream.avail_out); while (stream.avail_out == 0);
} }
while (stream.avail_out == 0); while (ret != Z_STREAM_END);
}
while (ret != Z_STREAM_END); inflateEnd(&stream);
return buffer;
inflateEnd(&stream); }
return buffer; }
}
}
}

View File

@ -1,16 +1,13 @@
#pragma once #pragma once
#define CHUNK 16384 #define CHUNK 16384
namespace utils namespace utils::compression
{ {
namespace compression class zlib final
{ {
class zlib final public:
{ static std::string compress(const std::string& data);
public: static std::string decompress(const std::string& data);
static std::string compress(const std::string& data); };
static std::string decompress(const std::string& data); };
};
};
}

View File

@ -4,323 +4,320 @@
/// http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/Source/libtomcrypt/doc/libTomCryptDoc.pdf /// http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/Source/libtomcrypt/doc/libTomCryptDoc.pdf
namespace utils namespace utils::cryptography
{ {
namespace cryptography ecc::key::key()
{ {
ecc::key::key() ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
}
ecc::key::~key()
{
this->free();
}
bool ecc::key::is_valid() const
{
return (!memory::is_set(&this->key_storage_, 0, sizeof(this->key_storage_)));
}
ecc_key* ecc::key::get()
{
return &this->key_storage_;
}
std::string ecc::key::get_public_key() const
{
uint8_t buffer[512] = {0};
DWORD length = sizeof(buffer);
if (ecc_ansi_x963_export(&this->key_storage_, buffer, &length) == CRYPT_OK)
{ {
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
}
ecc::key::~key()
{
this->free();
}
bool ecc::key::is_valid() const
{
return (!memory::is_set(&this->key_storage_, 0, sizeof(this->key_storage_)));
}
ecc_key* ecc::key::get()
{
return &this->key_storage_;
}
std::string ecc::key::get_public_key() const
{
uint8_t buffer[512] = {0};
DWORD length = sizeof(buffer);
if (ecc_ansi_x963_export(&this->key_storage_, buffer, &length) == CRYPT_OK)
{
return std::string(reinterpret_cast<char*>(buffer), length);
}
return {};
}
void ecc::key::set(const std::string& pub_key_buffer)
{
this->free();
if (ecc_ansi_x963_import(reinterpret_cast<const uint8_t*>(pub_key_buffer.data()), pub_key_buffer.size(),
&this->key_storage_) != CRYPT_OK)
{
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
}
}
void ecc::key::deserialize(const std::string& key)
{
this->free();
if (ecc_import(reinterpret_cast<const uint8_t*>(key.data()), key.size(), &this->key_storage_) != CRYPT_OK)
{
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
}
}
std::string ecc::key::serialize(const int type) const
{
uint8_t buffer[4096] = {0};
DWORD length = sizeof(buffer);
if (ecc_export(buffer, &length, type, &this->key_storage_) == CRYPT_OK)
{
return std::string(reinterpret_cast<char*>(buffer), length);
}
return "";
}
void ecc::key::free()
{
if (this->is_valid())
{
ecc_free(&this->key_storage_);
}
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
}
bool ecc::key::operator==(key& key) const
{
return (this->is_valid() && key.is_valid() && this->serialize(PK_PUBLIC) == key.serialize(PK_PUBLIC));
}
ecc::key ecc::generate_key(const int bits)
{
key key;
ltc_mp = ltm_desc;
register_prng(&sprng_desc);
ecc_make_key(nullptr, find_prng("sprng"), bits / 8, key.get());
return key;
}
std::string ecc::sign_message(key key, const std::string& message)
{
if (!key.is_valid()) return "";
uint8_t buffer[512];
DWORD length = sizeof(buffer);
ltc_mp = ltm_desc;
register_prng(&sprng_desc);
ecc_sign_hash(reinterpret_cast<const uint8_t*>(message.data()), message.size(), buffer, &length, nullptr,
find_prng("sprng"), key.get());
return std::string(reinterpret_cast<char*>(buffer), length); return std::string(reinterpret_cast<char*>(buffer), length);
} }
bool ecc::verify_message(key key, const std::string& message, const std::string& signature) return {};
}
void ecc::key::set(const std::string& pub_key_buffer)
{
this->free();
if (ecc_ansi_x963_import(reinterpret_cast<const uint8_t*>(pub_key_buffer.data()), pub_key_buffer.size(),
&this->key_storage_) != CRYPT_OK)
{ {
if (!key.is_valid()) return false; ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
ltc_mp = ltm_desc;
auto result = 0;
return (ecc_verify_hash(reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
reinterpret_cast<const uint8_t*>(message.data()), message.size(), &result,
key.get()) == CRYPT_OK && result != 0);
}
std::string rsa::encrypt(const std::string& data, const std::string& hash, const std::string& key)
{
initialize();
const auto prng_id = find_prng("yarrow");
rsa_key new_key;
rsa_import(PBYTE(key.data()), key.size(), &new_key);
prng_state yarrow;
rng_make_prng(128, prng_id, &yarrow, nullptr);
unsigned char buffer[0x80];
unsigned long length = sizeof(buffer);
const auto rsa_result = rsa_encrypt_key( //
PBYTE(data.data()), //
data.size(), //
buffer, //
&length, //
PBYTE(hash.data()), //
hash.size(), //
&yarrow, //
prng_id, //
find_hash("sha1"), //
&new_key);
rsa_free(&new_key);
if (rsa_result == CRYPT_OK)
{
return std::string(PCHAR(buffer), length);
}
return {};
}
void rsa::initialize()
{
static auto initialized = false;
if (initialized) return;
initialized = true;
ltc_mp = ltm_desc;
register_hash(&sha1_desc);
register_prng(&yarrow_desc);
}
std::string des3::encrypt(const std::string& data, const std::string& iv, const std::string& key)
{
initialize();
std::string enc_data;
enc_data.resize(data.size());
symmetric_CBC cbc;
const auto des3 = find_cipher("3des");
cbc_start(des3, reinterpret_cast<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()),
key.size(), 0, &cbc);
cbc_encrypt(reinterpret_cast<const uint8_t*>(data.data()),
reinterpret_cast<uint8_t*>(const_cast<char*>(enc_data.data())), data.size(), &cbc);
cbc_done(&cbc);
return enc_data;
}
std::string des3::decrypt(const std::string& data, const std::string& iv, const std::string& key)
{
initialize();
std::string dec_data;
dec_data.resize(data.size());
symmetric_CBC cbc;
const auto des3 = find_cipher("3des");
cbc_start(des3, reinterpret_cast<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()),
key.size(), 0, &cbc);
cbc_decrypt(reinterpret_cast<const uint8_t*>(data.data()),
reinterpret_cast<uint8_t*>(const_cast<char*>(dec_data.data())), data.size(), &cbc);
cbc_done(&cbc);
return dec_data;
}
void des3::initialize()
{
static auto initialized = false;
if (initialized) return;
initialized = true;
register_cipher(&des3_desc);
}
std::string tiger::compute(const std::string& data, const bool hex)
{
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
}
std::string tiger::compute(const uint8_t* data, const size_t length, const bool hex)
{
uint8_t buffer[24] = {0};
hash_state state;
tiger_init(&state);
tiger_process(&state, data, length);
tiger_done(&state, buffer);
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
if (!hex) return hash;
return string::dump_hex(hash, "");
}
std::string sha1::compute(const std::string& data, const bool hex)
{
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
}
std::string sha1::compute(const uint8_t* data, const size_t length, const bool hex)
{
uint8_t buffer[20] = {0};
hash_state state;
sha1_init(&state);
sha1_process(&state, data, length);
sha1_done(&state, buffer);
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
if (!hex) return hash;
return string::dump_hex(hash, "");
}
std::string sha256::compute(const std::string& data, const bool hex)
{
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
}
std::string sha256::compute(const uint8_t* data, const size_t length, const bool hex)
{
uint8_t buffer[32] = {0};
hash_state state;
sha256_init(&state);
sha256_process(&state, data, length);
sha256_done(&state, buffer);
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
if (!hex) return hash;
return string::dump_hex(hash, "");
}
std::string sha512::compute(const std::string& data, const bool hex)
{
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
}
std::string sha512::compute(const uint8_t* data, const size_t length, const bool hex)
{
uint8_t buffer[64] = {0};
hash_state state;
sha512_init(&state);
sha512_process(&state, data, length);
sha512_done(&state, buffer);
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
if (!hex) return hash;
return string::dump_hex(hash, "");
}
unsigned int jenkins_one_at_a_time::compute(const std::string& data)
{
return compute(data.data(), data.size());
}
unsigned int jenkins_one_at_a_time::compute(const char* key, const size_t len)
{
unsigned int hash, i;
for (hash = i = 0; i < len; ++i)
{
hash += key[i];
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
} }
} }
void ecc::key::deserialize(const std::string& key)
{
this->free();
if (ecc_import(reinterpret_cast<const uint8_t*>(key.data()), key.size(), &this->key_storage_) != CRYPT_OK)
{
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
}
}
std::string ecc::key::serialize(const int type) const
{
uint8_t buffer[4096] = {0};
DWORD length = sizeof(buffer);
if (ecc_export(buffer, &length, type, &this->key_storage_) == CRYPT_OK)
{
return std::string(reinterpret_cast<char*>(buffer), length);
}
return "";
}
void ecc::key::free()
{
if (this->is_valid())
{
ecc_free(&this->key_storage_);
}
ZeroMemory(&this->key_storage_, sizeof(this->key_storage_));
}
bool ecc::key::operator==(key& key) const
{
return (this->is_valid() && key.is_valid() && this->serialize(PK_PUBLIC) == key.serialize(PK_PUBLIC));
}
ecc::key ecc::generate_key(const int bits)
{
key key;
ltc_mp = ltm_desc;
register_prng(&sprng_desc);
ecc_make_key(nullptr, find_prng("sprng"), bits / 8, key.get());
return key;
}
std::string ecc::sign_message(key key, const std::string& message)
{
if (!key.is_valid()) return "";
uint8_t buffer[512];
DWORD length = sizeof(buffer);
ltc_mp = ltm_desc;
register_prng(&sprng_desc);
ecc_sign_hash(reinterpret_cast<const uint8_t*>(message.data()), message.size(), buffer, &length, nullptr,
find_prng("sprng"), key.get());
return std::string(reinterpret_cast<char*>(buffer), length);
}
bool ecc::verify_message(key key, const std::string& message, const std::string& signature)
{
if (!key.is_valid()) return false;
ltc_mp = ltm_desc;
auto result = 0;
return (ecc_verify_hash(reinterpret_cast<const uint8_t*>(signature.data()), signature.size(),
reinterpret_cast<const uint8_t*>(message.data()), message.size(), &result,
key.get()) == CRYPT_OK && result != 0);
}
std::string rsa::encrypt(const std::string& data, const std::string& hash, const std::string& key)
{
initialize();
const auto prng_id = find_prng("yarrow");
rsa_key new_key;
rsa_import(PBYTE(key.data()), key.size(), &new_key);
prng_state yarrow;
rng_make_prng(128, prng_id, &yarrow, nullptr);
unsigned char buffer[0x80];
unsigned long length = sizeof(buffer);
const auto rsa_result = rsa_encrypt_key( //
PBYTE(data.data()), //
data.size(), //
buffer, //
&length, //
PBYTE(hash.data()), //
hash.size(), //
&yarrow, //
prng_id, //
find_hash("sha1"), //
&new_key);
rsa_free(&new_key);
if (rsa_result == CRYPT_OK)
{
return std::string(PCHAR(buffer), length);
}
return {};
}
void rsa::initialize()
{
static auto initialized = false;
if (initialized) return;
initialized = true;
ltc_mp = ltm_desc;
register_hash(&sha1_desc);
register_prng(&yarrow_desc);
}
std::string des3::encrypt(const std::string& data, const std::string& iv, const std::string& key)
{
initialize();
std::string enc_data;
enc_data.resize(data.size());
symmetric_CBC cbc;
const auto des3 = find_cipher("3des");
cbc_start(des3, reinterpret_cast<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()),
key.size(), 0, &cbc);
cbc_encrypt(reinterpret_cast<const uint8_t*>(data.data()),
reinterpret_cast<uint8_t*>(const_cast<char*>(enc_data.data())), data.size(), &cbc);
cbc_done(&cbc);
return enc_data;
}
std::string des3::decrypt(const std::string& data, const std::string& iv, const std::string& key)
{
initialize();
std::string dec_data;
dec_data.resize(data.size());
symmetric_CBC cbc;
const auto des3 = find_cipher("3des");
cbc_start(des3, reinterpret_cast<const uint8_t*>(iv.data()), reinterpret_cast<const uint8_t*>(key.data()),
key.size(), 0, &cbc);
cbc_decrypt(reinterpret_cast<const uint8_t*>(data.data()),
reinterpret_cast<uint8_t*>(const_cast<char*>(dec_data.data())), data.size(), &cbc);
cbc_done(&cbc);
return dec_data;
}
void des3::initialize()
{
static auto initialized = false;
if (initialized) return;
initialized = true;
register_cipher(&des3_desc);
}
std::string tiger::compute(const std::string& data, const bool hex)
{
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
}
std::string tiger::compute(const uint8_t* data, const size_t length, const bool hex)
{
uint8_t buffer[24] = {0};
hash_state state;
tiger_init(&state);
tiger_process(&state, data, length);
tiger_done(&state, buffer);
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
if (!hex) return hash;
return string::dump_hex(hash, "");
}
std::string sha1::compute(const std::string& data, const bool hex)
{
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
}
std::string sha1::compute(const uint8_t* data, const size_t length, const bool hex)
{
uint8_t buffer[20] = {0};
hash_state state;
sha1_init(&state);
sha1_process(&state, data, length);
sha1_done(&state, buffer);
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
if (!hex) return hash;
return string::dump_hex(hash, "");
}
std::string sha256::compute(const std::string& data, const bool hex)
{
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
}
std::string sha256::compute(const uint8_t* data, const size_t length, const bool hex)
{
uint8_t buffer[32] = {0};
hash_state state;
sha256_init(&state);
sha256_process(&state, data, length);
sha256_done(&state, buffer);
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
if (!hex) return hash;
return string::dump_hex(hash, "");
}
std::string sha512::compute(const std::string& data, const bool hex)
{
return compute(reinterpret_cast<const uint8_t*>(data.data()), data.size(), hex);
}
std::string sha512::compute(const uint8_t* data, const size_t length, const bool hex)
{
uint8_t buffer[64] = {0};
hash_state state;
sha512_init(&state);
sha512_process(&state, data, length);
sha512_done(&state, buffer);
std::string hash(reinterpret_cast<char*>(buffer), sizeof(buffer));
if (!hex) return hash;
return string::dump_hex(hash, "");
}
unsigned int jenkins_one_at_a_time::compute(const std::string& data)
{
return compute(data.data(), data.size());
}
unsigned int jenkins_one_at_a_time::compute(const char* key, const size_t len)
{
unsigned int hash, i;
for (hash = i = 0; i < len; ++i)
{
hash += key[i];
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
return hash;
}
} }

View File

@ -1,95 +1,92 @@
#pragma once #pragma once
namespace utils namespace utils::cryptography
{ {
namespace cryptography class ecc final
{ {
class ecc final public:
class key final
{ {
public: public:
class key final key();
{ ~key();
public:
key();
~key();
bool is_valid() const; bool is_valid() const;
ecc_key* get(); ecc_key* get();
std::string get_public_key() const; std::string get_public_key() const;
void set(const std::string& pub_key_buffer); void set(const std::string& pub_key_buffer);
void deserialize(const std::string& key); void deserialize(const std::string& key);
std::string serialize(int type = PK_PRIVATE) const; std::string serialize(int type = PK_PRIVATE) const;
void free(); void free();
bool operator==(key& key) const; bool operator==(key& key) const;
private:
ecc_key key_storage_{};
};
static key generate_key(int bits);
static std::string sign_message(key key, const std::string& message);
static bool verify_message(key key, const std::string& message, const std::string& signature);
};
class rsa final
{
public:
static std::string encrypt(const std::string& data, const std::string& hash, const std::string& key);
private: private:
static void initialize(); ecc_key key_storage_{};
}; };
class des3 final static key generate_key(int bits);
{ static std::string sign_message(key key, const std::string& message);
public: static bool verify_message(key key, const std::string& message, const std::string& signature);
static std::string encrypt(const std::string& data, const std::string& iv, const std::string& key); };
static std::string decrypt(const std::string& data, const std::string& iv, const std::string& key);
private: class rsa final
static void initialize(); {
}; public:
static std::string encrypt(const std::string& data, const std::string& hash, const std::string& key);
class tiger final private:
{ static void initialize();
public: };
static std::string compute(const std::string& data, bool hex = false);
static std::string compute(const uint8_t* data, size_t length, bool hex = false);
};
class sha1 final class des3 final
{ {
public: public:
static std::string compute(const std::string& data, bool hex = false); static std::string encrypt(const std::string& data, const std::string& iv, const std::string& key);
static std::string compute(const uint8_t* data, size_t length, bool hex = false); static std::string decrypt(const std::string& data, const std::string& iv, const std::string& key);
};
class sha256 final private:
{ static void initialize();
public: };
static std::string compute(const std::string& data, bool hex = false);
static std::string compute(const uint8_t* data, size_t length, bool hex = false);
};
class sha512 final class tiger final
{ {
public: public:
static std::string compute(const std::string& data, bool hex = false); static std::string compute(const std::string& data, bool hex = false);
static std::string compute(const uint8_t* data, size_t length, bool hex = false); static std::string compute(const uint8_t* data, size_t length, bool hex = false);
}; };
class jenkins_one_at_a_time final class sha1 final
{ {
public: public:
static unsigned int compute(const std::string& data); static std::string compute(const std::string& data, bool hex = false);
static unsigned int compute(const char* key, size_t len); static std::string compute(const uint8_t* data, size_t length, bool hex = false);
}; };
}
class sha256 final
{
public:
static std::string compute(const std::string& data, bool hex = false);
static std::string compute(const uint8_t* data, size_t length, bool hex = false);
};
class sha512 final
{
public:
static std::string compute(const std::string& data, bool hex = false);
static std::string compute(const uint8_t* data, size_t length, bool hex = false);
};
class jenkins_one_at_a_time final
{
public:
static unsigned int compute(const std::string& data);
static unsigned int compute(const char* key, size_t len);
};
} }

View File

@ -2,51 +2,48 @@
#include "flags.hpp" #include "flags.hpp"
#include "string.hpp" #include "string.hpp"
namespace utils namespace utils::flags
{ {
namespace flags void parse_flags(std::vector<std::string>& flags)
{ {
void parse_flags(std::vector<std::string>& flags) int num_args;
const auto argv = CommandLineToArgvW(GetCommandLineW(), &num_args);
flags.clear();
if (argv)
{ {
int num_args; for (auto i = 0; i < num_args; ++i)
const auto argv = CommandLineToArgvW(GetCommandLineW(), &num_args);
flags.clear();
if (argv)
{ {
for (auto i = 0; i < num_args; ++i) std::wstring wide_flag(argv[i]);
if (wide_flag[0] == L'-')
{ {
std::wstring wide_flag(argv[i]); flags.emplace_back(wide_flag.begin() + 1, wide_flag.end());
if (wide_flag[0] == L'-')
{
flags.emplace_back(wide_flag.begin() + 1, wide_flag.end());
}
}
LocalFree(argv);
}
}
bool has_flag(const std::string& flag)
{
static auto parsed = false;
static std::vector<std::string> enabled_flags;
if (!parsed)
{
parse_flags(enabled_flags);
}
for (const auto& entry : enabled_flags)
{
if (string::to_lower(entry) == string::to_lower(flag))
{
return true;
} }
} }
return false; LocalFree(argv);
} }
} }
bool has_flag(const std::string& flag)
{
static auto parsed = false;
static std::vector<std::string> enabled_flags;
if (!parsed)
{
parse_flags(enabled_flags);
}
for (const auto& entry : enabled_flags)
{
if (string::to_lower(entry) == string::to_lower(flag))
{
return true;
}
}
return false;
}
} }

View File

@ -1,9 +1,6 @@
#pragma once #pragma once
namespace utils namespace utils::flags
{ {
namespace flags bool has_flag(const std::string& flag);
{
bool has_flag(const std::string& flag);
}
} }

View File

@ -1,110 +1,107 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "io.hpp" #include "io.hpp"
namespace utils namespace utils::io
{ {
namespace io bool file_exists(const std::string& file)
{ {
bool file_exists(const std::string& file) return std::ifstream(file).good();
}
bool write_file(const std::string& file, const std::string& data, const bool append)
{
const auto pos = file.find_last_of("/\\");
if (pos != std::string::npos)
{ {
return std::ifstream(file).good(); create_directory(file.substr(0, pos));
} }
bool write_file(const std::string& file, const std::string& data, const bool append) std::ofstream stream(
file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : std::ofstream::out));
if (stream.is_open())
{ {
const auto pos = file.find_last_of("/\\"); stream.write(data.data(), data.size());
if (pos != std::string::npos) stream.close();
{ return true;
create_directory(file.substr(0, pos)); }
}
std::ofstream stream( return false;
file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : std::ofstream::out)); }
if (stream.is_open()) std::string read_file(const std::string& file)
{
std::string data;
read_file(file, &data);
return data;
}
bool read_file(const std::string& file, std::string* data)
{
if (!data) return false;
data->clear();
if (file_exists(file))
{
std::ifstream stream(file, std::ios::binary);
if (!stream.is_open()) return false;
stream.seekg(0, std::ios::end);
const std::streamsize size = stream.tellg();
stream.seekg(0, std::ios::beg);
if (size > -1)
{ {
stream.write(data.data(), data.size()); data->resize(static_cast<uint32_t>(size));
stream.read(const_cast<char*>(data->data()), size);
stream.close(); stream.close();
return true; return true;
} }
return false;
} }
std::string read_file(const std::string& file) return false;
{ }
std::string data;
read_file(file, &data);
return data;
}
bool read_file(const std::string& file, std::string* data) size_t file_size(const std::string& file)
{
if (file_exists(file))
{ {
if (!data) return false; std::ifstream stream(file, std::ios::binary);
data->clear();
if (file_exists(file)) if (stream.good())
{ {
std::ifstream stream(file, std::ios::binary);
if (!stream.is_open()) return false;
stream.seekg(0, std::ios::end); stream.seekg(0, std::ios::end);
const std::streamsize size = stream.tellg(); return static_cast<size_t>(stream.tellg());
stream.seekg(0, std::ios::beg);
if (size > -1)
{
data->resize(static_cast<uint32_t>(size));
stream.read(const_cast<char*>(data->data()), size);
stream.close();
return true;
}
} }
return false;
} }
size_t file_size(const std::string& file) return 0;
}
bool create_directory(const std::string& directory)
{
return std::experimental::filesystem::create_directories(directory);
}
bool directory_exists(const std::string& directory)
{
return std::experimental::filesystem::is_directory(directory);
}
bool directory_is_empty(const std::string& directory)
{
return std::experimental::filesystem::is_empty(directory);
}
std::vector<std::string> list_files(const std::string& directory)
{
std::vector<std::string> files;
for (auto& file : std::experimental::filesystem::directory_iterator(directory))
{ {
if (file_exists(file)) files.push_back(file.path().generic_string());
{
std::ifstream stream(file, std::ios::binary);
if (stream.good())
{
stream.seekg(0, std::ios::end);
return static_cast<size_t>(stream.tellg());
}
}
return 0;
} }
bool create_directory(const std::string& directory) return files;
{
return std::experimental::filesystem::create_directories(directory);
}
bool directory_exists(const std::string& directory)
{
return std::experimental::filesystem::is_directory(directory);
}
bool directory_is_empty(const std::string& directory)
{
return std::experimental::filesystem::is_empty(directory);
}
std::vector<std::string> list_files(const std::string& directory)
{
std::vector<std::string> files;
for (auto& file : std::experimental::filesystem::directory_iterator(directory))
{
files.push_back(file.path().generic_string());
}
return files;
}
} }
} }

View File

@ -1,17 +1,14 @@
#pragma once #pragma once
namespace utils namespace utils::io
{ {
namespace io bool file_exists(const std::string& file);
{ bool write_file(const std::string& file, const std::string& data, bool append = false);
bool file_exists(const std::string& file); bool read_file(const std::string& file, std::string* data);
bool write_file(const std::string& file, const std::string& data, bool append = false); std::string read_file(const std::string& file);
bool read_file(const std::string& file, std::string* data); size_t file_size(const std::string& file);
std::string read_file(const std::string& file); bool create_directory(const std::string& directory);
size_t file_size(const std::string& file); bool directory_exists(const std::string& directory);
bool create_directory(const std::string& directory); bool directory_is_empty(const std::string& directory);
bool directory_exists(const std::string& directory); std::vector<std::string> list_files(const std::string& directory);
bool directory_is_empty(const std::string& directory); }
std::vector<std::string> list_files(const std::string& directory);
}
}

View File

@ -1,207 +1,204 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "nt.hpp" #include "nt.hpp"
namespace utils namespace utils::nt
{ {
namespace nt module module::load(const std::string& name)
{ {
module module::load(const std::string& name) return module(LoadLibraryA(name.data()));
}
module module::get_by_address(void* address)
{
HMODULE handle = nullptr;
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<LPCSTR>(address), &handle);
return module(handle);
}
module::module()
{
this->module_ = GetModuleHandleA(nullptr);
}
module::module(const std::string& name)
{
this->module_ = GetModuleHandleA(name.data());
}
module::module(const HMODULE handle)
{
this->module_ = handle;
}
bool module::operator==(const module& obj) const
{
return this->module_ == obj.module_;
}
module::operator bool() const
{
return this->is_valid();
}
module::operator HMODULE() const
{
return this->get_handle();
}
PIMAGE_NT_HEADERS module::get_nt_headers() const
{
if (!this->is_valid()) return nullptr;
return reinterpret_cast<PIMAGE_NT_HEADERS>(this->get_ptr() + this->get_dos_header()->e_lfanew);
}
PIMAGE_DOS_HEADER module::get_dos_header() const
{
return reinterpret_cast<PIMAGE_DOS_HEADER>(this->get_ptr());
}
PIMAGE_OPTIONAL_HEADER module::get_optional_header() const
{
if (!this->is_valid()) return nullptr;
return &this->get_nt_headers()->OptionalHeader;
}
std::vector<PIMAGE_SECTION_HEADER> module::get_section_headers() const
{
std::vector<PIMAGE_SECTION_HEADER> headers;
auto nt_headers = this->get_nt_headers();
auto section = IMAGE_FIRST_SECTION(nt_headers);
for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section)
{ {
return module(LoadLibraryA(name.data())); if (section) headers.push_back(section);
else OutputDebugStringA("There was an invalid section :O");
} }
module module::get_by_address(void* address) return headers;
}
std::uint8_t* module::get_ptr() const
{
return reinterpret_cast<std::uint8_t*>(this->module_);
}
void module::unprotect() const
{
if (!this->is_valid()) return;
DWORD protection;
VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE,
&protection);
}
size_t module::get_relative_entry_point() const
{
if (!this->is_valid()) return 0;
return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint;
}
void* module::get_entry_point() const
{
if (!this->is_valid()) return nullptr;
return this->get_ptr() + this->get_relative_entry_point();
}
bool module::is_valid() const
{
return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE;
}
std::string module::get_name() const
{
if (!this->is_valid()) return "";
auto path = this->get_path();
const auto pos = path.find_last_of("/\\");
if (pos == std::string::npos) return path;
return path.substr(pos + 1);
}
std::string module::get_path() const
{
if (!this->is_valid()) return "";
char name[MAX_PATH] = {0};
GetModuleFileNameA(this->module_, name, sizeof name);
return name;
}
void module::free()
{
if (this->is_valid())
{ {
HMODULE handle = nullptr; FreeLibrary(this->module_);
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, reinterpret_cast<LPCSTR>(address), &handle); this->module_ = nullptr;
return module(handle);
}
module::module()
{
this->module_ = GetModuleHandleA(nullptr);
}
module::module(const std::string& name)
{
this->module_ = GetModuleHandleA(name.data());
}
module::module(const HMODULE handle)
{
this->module_ = handle;
}
bool module::operator==(const module& obj) const
{
return this->module_ == obj.module_;
}
module::operator bool() const
{
return this->is_valid();
}
module::operator HMODULE() const
{
return this->get_handle();
}
PIMAGE_NT_HEADERS module::get_nt_headers() const
{
if (!this->is_valid()) return nullptr;
return reinterpret_cast<PIMAGE_NT_HEADERS>(this->get_ptr() + this->get_dos_header()->e_lfanew);
}
PIMAGE_DOS_HEADER module::get_dos_header() const
{
return reinterpret_cast<PIMAGE_DOS_HEADER>(this->get_ptr());
}
PIMAGE_OPTIONAL_HEADER module::get_optional_header() const
{
if (!this->is_valid()) return nullptr;
return &this->get_nt_headers()->OptionalHeader;
}
std::vector<PIMAGE_SECTION_HEADER> module::get_section_headers() const
{
std::vector<PIMAGE_SECTION_HEADER> headers;
auto nt_headers = this->get_nt_headers();
auto section = IMAGE_FIRST_SECTION(nt_headers);
for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section)
{
if (section) headers.push_back(section);
else OutputDebugStringA("There was an invalid section :O");
}
return headers;
}
std::uint8_t* module::get_ptr() const
{
return reinterpret_cast<std::uint8_t*>(this->module_);
}
void module::unprotect() const
{
if (!this->is_valid()) return;
DWORD protection;
VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE,
&protection);
}
size_t module::get_relative_entry_point() const
{
if (!this->is_valid()) return 0;
return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint;
}
void* module::get_entry_point() const
{
if (!this->is_valid()) return nullptr;
return this->get_ptr() + this->get_relative_entry_point();
}
bool module::is_valid() const
{
return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE;
}
std::string module::get_name() const
{
if (!this->is_valid()) return "";
auto path = this->get_path();
const auto pos = path.find_last_of("/\\");
if (pos == std::string::npos) return path;
return path.substr(pos + 1);
}
std::string module::get_path() const
{
if (!this->is_valid()) return "";
char name[MAX_PATH] = {0};
GetModuleFileNameA(this->module_, name, sizeof name);
return name;
}
void module::free()
{
if (this->is_valid())
{
FreeLibrary(this->module_);
this->module_ = nullptr;
}
}
HMODULE module::get_handle() const
{
return this->module_;
}
void** module::get_iat_entry(const std::string& module_name, const std::string& proc_name) const
{
if (!this->is_valid()) return nullptr;
const module other_module(module_name);
if (!other_module.is_valid()) return nullptr;
const auto target_function = other_module.get_proc<void*>(proc_name);
if (!target_function) return nullptr;
auto* header = this->get_optional_header();
if (!header) return nullptr;
auto* import_descriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(this->get_ptr() + header->DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while (import_descriptor->Name)
{
if (!_stricmp(reinterpret_cast<char*>(this->get_ptr() + import_descriptor->Name), module_name.data()))
{
auto* original_thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->
OriginalFirstThunk + this->get_ptr());
auto* thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->FirstThunk + this->
get_ptr());
while (original_thunk_data->u1.AddressOfData)
{
const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF;
if (ordinal_number > 0xFFFF) continue;
if (GetProcAddress(other_module.module_, reinterpret_cast<char*>(ordinal_number)) ==
target_function)
{
return reinterpret_cast<void**>(&thunk_data->u1.Function);
}
++original_thunk_data;
++thunk_data;
}
//break;
}
++import_descriptor;
}
return nullptr;
}
void raise_hard_exception()
{
int data = false;
const module ntdll("ntdll.dll");
ntdll.invoke_pascal<void>("RtlAdjustPrivilege", 19, true, false, &data);
ntdll.invoke_pascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data);
} }
} }
HMODULE module::get_handle() const
{
return this->module_;
}
void** module::get_iat_entry(const std::string& module_name, const std::string& proc_name) const
{
if (!this->is_valid()) return nullptr;
const module other_module(module_name);
if (!other_module.is_valid()) return nullptr;
const auto target_function = other_module.get_proc<void*>(proc_name);
if (!target_function) return nullptr;
auto* header = this->get_optional_header();
if (!header) return nullptr;
auto* import_descriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(this->get_ptr() + header->DataDirectory
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
while (import_descriptor->Name)
{
if (!_stricmp(reinterpret_cast<char*>(this->get_ptr() + import_descriptor->Name), module_name.data()))
{
auto* original_thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->
OriginalFirstThunk + this->get_ptr());
auto* thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->FirstThunk + this->
get_ptr());
while (original_thunk_data->u1.AddressOfData)
{
const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF;
if (ordinal_number > 0xFFFF) continue;
if (GetProcAddress(other_module.module_, reinterpret_cast<char*>(ordinal_number)) ==
target_function)
{
return reinterpret_cast<void**>(&thunk_data->u1.Function);
}
++original_thunk_data;
++thunk_data;
}
//break;
}
++import_descriptor;
}
return nullptr;
}
void raise_hard_exception()
{
int data = false;
const module ntdll("ntdll.dll");
ntdll.invoke_pascal<void>("RtlAdjustPrivilege", 19, true, false, &data);
ntdll.invoke_pascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data);
}
} }

View File

@ -1,91 +1,88 @@
#pragma once #pragma once
namespace utils namespace utils::nt
{ {
namespace nt class module final
{ {
class module final public:
{ static module load(const std::string& name);
public: static module get_by_address(void* address);
static module load(const std::string& name);
static module get_by_address(void* address); module();
explicit module(const std::string& name);
module(); explicit module(HMODULE handle);
explicit module(const std::string& name);
explicit module(HMODULE handle); module(const module& a) : module_(a.module_)
{
module(const module& a) : module_(a.module_) }
{
} bool operator!=(const module& obj) const { return !(*this == obj); };
bool operator==(const module& obj) const;
bool operator!=(const module& obj) const { return !(*this == obj); };
bool operator==(const module& obj) const; operator bool() const;
operator HMODULE() const;
operator bool() const;
operator HMODULE() const; void unprotect() const;
void* get_entry_point() const;
void unprotect() const; size_t get_relative_entry_point() const;
void* get_entry_point() const;
size_t get_relative_entry_point() const; bool is_valid() const;
std::string get_name() const;
bool is_valid() const; std::string get_path() const;
std::string get_name() const; std::uint8_t* get_ptr() const;
std::string get_path() const; void free();
std::uint8_t* get_ptr() const;
void free(); HMODULE get_handle() const;
HMODULE get_handle() const; template <typename T>
T get_proc(const std::string& process) const
template <typename T> {
T get_proc(const std::string& process) const if (!this->is_valid()) T{};
{ return reinterpret_cast<T>(GetProcAddress(this->module_, process.data()));
if (!this->is_valid()) T{}; }
return reinterpret_cast<T>(GetProcAddress(this->module_, process.data()));
} template <typename T>
std::function<T> get(const std::string& process) const
template <typename T> {
std::function<T> get(const std::string& process) const if (!this->is_valid()) std::function<T>();
{ return reinterpret_cast<T*>(this->get_proc<void*>(process));
if (!this->is_valid()) std::function<T>(); }
return reinterpret_cast<T*>(this->get_proc<void*>(process));
} template <typename T, typename... Args>
T invoke(const std::string& process, Args ... args) const
template <typename T, typename... Args> {
T invoke(const std::string& process, Args ... args) const auto method = this->get<T(__cdecl)(Args ...)>(process);
{ if (method) return method(args...);
auto method = this->get<T(__cdecl)(Args ...)>(process); return T();
if (method) return method(args...); }
return T();
} template <typename T, typename... Args>
T invoke_pascal(const std::string& process, Args ... args) const
template <typename T, typename... Args> {
T invoke_pascal(const std::string& process, Args ... args) const auto method = this->get<T(__stdcall)(Args ...)>(process);
{ if (method) return method(args...);
auto method = this->get<T(__stdcall)(Args ...)>(process); return T();
if (method) return method(args...); }
return T();
} template <typename T, typename... Args>
T invoke_this(const std::string& process, void* this_ptr, Args ... args) const
template <typename T, typename... Args> {
T invoke_this(const std::string& process, void* this_ptr, Args ... args) const auto method = this->get<T(__thiscall)(void*, Args ...)>(this_ptr, process);
{ if (method) return method(args...);
auto method = this->get<T(__thiscall)(void*, Args ...)>(this_ptr, process); return T();
if (method) return method(args...); }
return T();
} std::vector<PIMAGE_SECTION_HEADER> get_section_headers() const;
std::vector<PIMAGE_SECTION_HEADER> get_section_headers() const; PIMAGE_NT_HEADERS get_nt_headers() const;
PIMAGE_DOS_HEADER get_dos_header() const;
PIMAGE_NT_HEADERS get_nt_headers() const; PIMAGE_OPTIONAL_HEADER get_optional_header() const;
PIMAGE_DOS_HEADER get_dos_header() const;
PIMAGE_OPTIONAL_HEADER get_optional_header() const; void** get_iat_entry(const std::string& module_name, const std::string& proc_name) const;
void** get_iat_entry(const std::string& module_name, const std::string& proc_name) const; private:
HMODULE module_;
private: };
HMODULE module_;
}; void raise_hard_exception();
}
void raise_hard_exception();
}
}

View File

@ -1,58 +1,55 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "string.hpp" #include "string.hpp"
namespace utils namespace utils::string
{ {
namespace string const char* va(const char* fmt, ...)
{ {
const char* va(const char* fmt, ...) static thread_local va_provider<8, 256> provider;
{
static thread_local va_provider<8, 256> provider; va_list ap;
va_start(ap, fmt);
va_list ap;
va_start(ap, fmt); const char* result = provider.get(fmt, ap);
const char* result = provider.get(fmt, ap); va_end(ap);
return result;
va_end(ap); }
return result;
} std::string to_lower(std::string text)
{
std::string to_lower(std::string text) std::transform(text.begin(), text.end(), text.begin(), [](const char input)
{ {
std::transform(text.begin(), text.end(), text.begin(), [](const char input) return CHAR(tolower(input));
{ });
return CHAR(tolower(input));
}); return text;
}
return text;
} std::string to_upper(std::string text)
{
std::string to_upper(std::string text) std::transform(text.begin(), text.end(), text.begin(), [](const char input)
{ {
std::transform(text.begin(), text.end(), text.begin(), [](const char input) return CHAR(toupper(input));
{ });
return CHAR(toupper(input));
}); return text;
}
return text;
} std::string dump_hex(const std::string& data, const std::string& separator)
{
std::string dump_hex(const std::string& data, const std::string& separator) std::string result;
{
std::string result; for (unsigned int i = 0; i < data.size(); ++i)
{
for (unsigned int i = 0; i < data.size(); ++i) if (i > 0)
{ {
if (i > 0) result.append(separator);
{ }
result.append(separator);
} result.append(va("%02X", data[i] & 0xFF));
}
result.append(va("%02X", data[i] & 0xFF));
} return result;
}
return result; }
}
}
}

View File

@ -1,84 +1,81 @@
#pragma once #pragma once
#include "memory.hpp" #include "memory.hpp"
namespace utils namespace utils::string
{ {
namespace string template <size_t Buffers, size_t MinBufferSize>
{ class va_provider final
template <size_t Buffers, size_t MinBufferSize> {
class va_provider final public:
{ static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0");
public:
static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0"); va_provider() : current_buffer_(0)
{
va_provider() : current_buffer_(0) }
{
} char* get(const char* format, const va_list ap)
{
char* get(const char* format, const va_list ap) ++this->current_buffer_ %= ARRAYSIZE(this->string_pool_);
{ auto entry = &this->string_pool_[this->current_buffer_];
++this->current_buffer_ %= ARRAYSIZE(this->string_pool_);
auto entry = &this->string_pool_[this->current_buffer_]; if (!entry->size || !entry->buffer)
{
if (!entry->size || !entry->buffer) throw std::runtime_error("String pool not initialized");
{ }
throw std::runtime_error("String pool not initialized");
} while (true)
{
while (true) const int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap);
{ if (res > 0) break; // Success
const int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap); if (res == 0) return nullptr; // Error
if (res > 0) break; // Success
if (res == 0) return nullptr; // Error entry->double_size();
}
entry->double_size();
} return entry->buffer;
}
return entry->buffer;
} private:
class entry final
private: {
class entry final public:
{ explicit entry(size_t _size = MinBufferSize) : size(_size), buffer(nullptr)
public: {
explicit entry(size_t _size = MinBufferSize) : size(_size), buffer(nullptr) if (this->size < MinBufferSize) this->size = MinBufferSize;
{ this->allocate();
if (this->size < MinBufferSize) this->size = MinBufferSize; }
this->allocate();
} ~entry()
{
~entry() if (this->buffer) memory::get_allocator()->free(this->buffer);
{ this->size = 0;
if (this->buffer) memory::get_allocator()->free(this->buffer); this->buffer = nullptr;
this->size = 0; }
this->buffer = nullptr;
} void allocate()
{
void allocate() if (this->buffer) memory::get_allocator()->free(this->buffer);
{ this->buffer = memory::get_allocator()->allocate_array<char>(this->size + 1);
if (this->buffer) memory::get_allocator()->free(this->buffer); }
this->buffer = memory::get_allocator()->allocate_array<char>(this->size + 1);
} void double_size()
{
void double_size() this->size *= 2;
{ this->allocate();
this->size *= 2; }
this->allocate();
} size_t size;
char* buffer;
size_t size; };
char* buffer;
}; size_t current_buffer_;
entry string_pool_[Buffers];
size_t current_buffer_; };
entry string_pool_[Buffers];
}; const char* va(const char* fmt, ...);
const char* va(const char* fmt, ...); std::string to_lower(std::string text);
std::string to_upper(std::string text);
std::string to_lower(std::string text);
std::string to_upper(std::string text); std::string dump_hex(const std::string& data, const std::string& separator = " ");
}
std::string dump_hex(const std::string& data, const std::string& separator = " ");
}
}