Compare commits
8 Commits
d18ec4e1ca
...
master
Author | SHA1 | Date | |
---|---|---|---|
161f605b20 | |||
6aa90a1852 | |||
f69923cbbb | |||
b62ab60366 | |||
117e40dc9e | |||
050c7f3be1 | |||
4c6beb592c | |||
a91b4d41dd |
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024-2025 Erik Scholz
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
@ -34,13 +34,13 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api)
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
auto* conf = PLUG_RESOLVE_INSTANCE(ConfigModelI);
|
auto* conf = PLUG_RESOLVE_INSTANCE(ConfigModelI);
|
||||||
auto* cr = PLUG_RESOLVE_INSTANCE_VERSIONED(Contact3Registry, "1");
|
auto* cs = PLUG_RESOLVE_INSTANCE(ContactStore4I);
|
||||||
auto* rmm = PLUG_RESOLVE_INSTANCE(RegistryMessageModel);
|
auto* rmm = PLUG_RESOLVE_INSTANCE(RegistryMessageModelI);
|
||||||
|
|
||||||
// static store, could be anywhere tho
|
// static store, could be anywhere tho
|
||||||
// construct with fetched dependencies
|
// construct with fetched dependencies
|
||||||
g_flp = std::make_unique<FactorioLogParser>(*conf);
|
g_flp = std::make_unique<FactorioLogParser>(*conf);
|
||||||
g_f = std::make_unique<Factorio>(*conf, *cr, *rmm, *g_flp);
|
g_f = std::make_unique<Factorio>(*conf, *cs, *rmm, *g_flp);
|
||||||
|
|
||||||
// register types
|
// register types
|
||||||
PLUG_PROVIDE_INSTANCE(FactorioLogParser, plugin_name, g_flp.get());
|
PLUG_PROVIDE_INSTANCE(FactorioLogParser, plugin_name, g_flp.get());
|
||||||
|
129
src/factorio.cpp
129
src/factorio.cpp
@ -3,13 +3,28 @@
|
|||||||
#include <solanaceae/util/config_model.hpp>
|
#include <solanaceae/util/config_model.hpp>
|
||||||
#include <solanaceae/util/utils.hpp>
|
#include <solanaceae/util/utils.hpp>
|
||||||
|
|
||||||
|
#include <solanaceae/contact/contact_store_i.hpp>
|
||||||
|
|
||||||
#include <solanaceae/message3/components.hpp>
|
#include <solanaceae/message3/components.hpp>
|
||||||
#include <solanaceae/contact/components.hpp>
|
#include <solanaceae/contact/components.hpp>
|
||||||
|
|
||||||
Factorio::Factorio(ConfigModelI& conf, Contact3Registry& cr, RegistryMessageModel& rmm, FactorioLogParser& flp) :
|
void Factorio::sendToLinked(const std::string& message) {
|
||||||
_cr(cr),
|
for (const auto& h : _linked_contacts) {
|
||||||
|
if (!static_cast<bool>(h)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
_rmm.sendText(h, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Factorio::Factorio(ConfigModelI& conf, ContactStore4I& cs, RegistryMessageModelI& rmm, FactorioLogParser& flp) :
|
||||||
|
_conf(conf),
|
||||||
|
_cs(cs),
|
||||||
_rmm(rmm),
|
_rmm(rmm),
|
||||||
_flp(flp)
|
_rmm_sr(_rmm.newSubRef(this)),
|
||||||
|
_flp(flp),
|
||||||
|
_flp_sr(_flp.newSubRef(this))
|
||||||
{
|
{
|
||||||
// config
|
// config
|
||||||
for (const auto&& [contact_id, enabled] : conf.entries_bool("Factorio", "link_to_contact")) {
|
for (const auto&& [contact_id, enabled] : conf.entries_bool("Factorio", "link_to_contact")) {
|
||||||
@ -18,34 +33,29 @@ Factorio::Factorio(ConfigModelI& conf, Contact3Registry& cr, RegistryMessageMode
|
|||||||
const auto id_vec = hex2bin(contact_id);
|
const auto id_vec = hex2bin(contact_id);
|
||||||
|
|
||||||
// search
|
// search
|
||||||
Contact3Handle h;
|
ContactHandle4 h = _cs.getOneContactByID(ByteSpan{id_vec});
|
||||||
auto view = _cr.view<Contact::Components::ID>();
|
|
||||||
for (const auto c : view) {
|
|
||||||
if (view.get<Contact::Components::ID>(c).data == id_vec) {
|
|
||||||
h = Contact3Handle{_cr, c};
|
|
||||||
std::cout << "Factorio: found contact for link.\n";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!static_cast<bool>(h)) {
|
if (!static_cast<bool>(h)) {
|
||||||
// not found, create thin contact with just id
|
// not found, create thin contact with just id
|
||||||
h = {_cr, _cr.create()};
|
h = _cs.contactHandle(_cs.registry().create());
|
||||||
h.emplace<Contact::Components::ID>(id_vec);
|
h.emplace<Contact::Components::ID>(id_vec);
|
||||||
|
_cs.throwEventConstruct(h);
|
||||||
std::cout << "Factorio: contact not found, created thin contact from ID. (" << contact_id << ")\n";
|
std::cout << "Factorio: contact not found, created thin contact from ID. (" << contact_id << ")\n";
|
||||||
}
|
}
|
||||||
_linked_contacts.push_back(h);
|
_linked_contacts.push_back(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
_rmm.subscribe(this, RegistryMessageModel_Event::message_construct);
|
_rmm_sr.subscribe(RegistryMessageModel_Event::message_construct);
|
||||||
|
|
||||||
_flp.subscribe(this, FactorioLogParser_Event::join);
|
_flp_sr
|
||||||
_flp.subscribe(this, FactorioLogParser_Event::leave);
|
.subscribe(FactorioLogParser_Event::join)
|
||||||
_flp.subscribe(this, FactorioLogParser_Event::chat);
|
.subscribe(FactorioLogParser_Event::leave)
|
||||||
_flp.subscribe(this, FactorioLogParser_Event::died);
|
.subscribe(FactorioLogParser_Event::chat)
|
||||||
_flp.subscribe(this, FactorioLogParser_Event::evolution);
|
.subscribe(FactorioLogParser_Event::died)
|
||||||
_flp.subscribe(this, FactorioLogParser_Event::research_started);
|
.subscribe(FactorioLogParser_Event::evolution)
|
||||||
_flp.subscribe(this, FactorioLogParser_Event::research_finished);
|
.subscribe(FactorioLogParser_Event::research_started)
|
||||||
_flp.subscribe(this, FactorioLogParser_Event::research_cancelled);
|
.subscribe(FactorioLogParser_Event::research_finished)
|
||||||
|
.subscribe(FactorioLogParser_Event::research_cancelled)
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
Factorio::~Factorio(void) {
|
Factorio::~Factorio(void) {
|
||||||
@ -57,41 +67,116 @@ bool Factorio::onEvent(const Message::Events::MessageConstruct& e) {
|
|||||||
|
|
||||||
bool Factorio::onEvent(const FactorioLog::Events::Join& e) {
|
bool Factorio::onEvent(const FactorioLog::Events::Join& e) {
|
||||||
std::cout << "Factorio: event join " << e.player_name << "\n";
|
std::cout << "Factorio: event join " << e.player_name << "\n";
|
||||||
|
|
||||||
|
if (!_conf.get_bool("Factorio", "forward", "join").value_or(true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string message{e.player_name};
|
||||||
|
message += " joined";
|
||||||
|
|
||||||
|
sendToLinked(message);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Factorio::onEvent(const FactorioLog::Events::Leave& e) {
|
bool Factorio::onEvent(const FactorioLog::Events::Leave& e) {
|
||||||
std::cout << "Factorio: event leave " << e.player_name << " " << e.reason << "\n";
|
std::cout << "Factorio: event leave " << e.player_name << " " << e.reason << "\n";
|
||||||
|
|
||||||
|
if (!_conf.get_bool("Factorio", "forward", "leave").value_or(true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string message{e.player_name};
|
||||||
|
message += " left";
|
||||||
|
|
||||||
|
sendToLinked(message);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Factorio::onEvent(const FactorioLog::Events::Chat& e) {
|
bool Factorio::onEvent(const FactorioLog::Events::Chat& e) {
|
||||||
std::cout << "Factorio: event chat " << e.player_name << ": " << e.message << "\n";
|
std::cout << "Factorio: event chat " << e.player_name << ": " << e.message << "\n";
|
||||||
|
|
||||||
|
if (!_conf.get_bool("Factorio", "forward", "chat").value_or(true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ignore pings
|
||||||
|
constexpr std::string_view ping_prefix{"[gps="};
|
||||||
|
if (e.message.size() > ping_prefix.size() && e.message.substr(0, ping_prefix.size()) == ping_prefix) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string message{"<"};
|
||||||
|
message += e.player_name;
|
||||||
|
message += ">: ";
|
||||||
|
message += e.message;
|
||||||
|
|
||||||
|
sendToLinked(message);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Factorio::onEvent(const FactorioLog::Events::Died& e) {
|
bool Factorio::onEvent(const FactorioLog::Events::Died& e) {
|
||||||
std::cout << "Factorio: event died " << e.player_name << ": " << e.reason << "\n";
|
std::cout << "Factorio: event died " << e.player_name << ": " << e.reason << "\n";
|
||||||
|
|
||||||
|
if (!_conf.get_bool("Factorio", "forward", "died").value_or(true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string message{e.player_name};
|
||||||
|
message += " died from ";
|
||||||
|
message += e.reason;
|
||||||
|
|
||||||
|
sendToLinked(message);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Factorio::onEvent(const FactorioLog::Events::Evolution& e) {
|
bool Factorio::onEvent(const FactorioLog::Events::Evolution& e) {
|
||||||
std::cout << "Factorio: event evolution " << e.evo << "\n";
|
std::cout << "Factorio: event evolution " << e.evo << "\n";
|
||||||
|
|
||||||
|
//if (!_conf.get_bool("Factorio", "forward", "evolution").value_or(true)) {
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Factorio::onEvent(const FactorioLog::Events::ResearchStarted& e) {
|
bool Factorio::onEvent(const FactorioLog::Events::ResearchStarted& e) {
|
||||||
std::cout << "Factorio: event research started " << e.name << "\n";
|
std::cout << "Factorio: event research started " << e.name << "\n";
|
||||||
|
|
||||||
|
//if (!_conf.get_bool("Factorio", "forward", "research_started").value_or(true)) {
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Factorio::onEvent(const FactorioLog::Events::ResearchFinished& e) {
|
bool Factorio::onEvent(const FactorioLog::Events::ResearchFinished& e) {
|
||||||
std::cout << "Factorio: event research finished " << e.name << "\n";
|
std::cout << "Factorio: event research finished " << e.name << "\n";
|
||||||
|
|
||||||
|
if (!_conf.get_bool("Factorio", "forward", "research_finished").value_or(true)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string message{"Research "};
|
||||||
|
message += e.name;
|
||||||
|
message += " finished!";
|
||||||
|
|
||||||
|
sendToLinked(message);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Factorio::onEvent(const FactorioLog::Events::ResearchCancelled& e) {
|
bool Factorio::onEvent(const FactorioLog::Events::ResearchCancelled& e) {
|
||||||
std::cout << "Factorio: event research cancelled " << e.name << "\n";
|
std::cout << "Factorio: event research cancelled " << e.name << "\n";
|
||||||
|
|
||||||
|
//if (!_conf.get_bool("Factorio", "forward", "research_cancelled").value_or(true)) {
|
||||||
|
// return false;
|
||||||
|
//}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <solanaceae/contact/fwd.hpp>
|
||||||
#include <solanaceae/message3/registry_message_model.hpp>
|
#include <solanaceae/message3/registry_message_model.hpp>
|
||||||
|
|
||||||
#include "./factorio_log_parser.hpp"
|
#include "./factorio_log_parser.hpp"
|
||||||
@ -10,14 +11,19 @@
|
|||||||
struct ConfigModelI;
|
struct ConfigModelI;
|
||||||
|
|
||||||
class Factorio : public RegistryMessageModelEventI, public FactorioLogParserEventI {
|
class Factorio : public RegistryMessageModelEventI, public FactorioLogParserEventI {
|
||||||
Contact3Registry& _cr;
|
ConfigModelI& _conf;
|
||||||
RegistryMessageModel& _rmm;
|
ContactStore4I& _cs;
|
||||||
|
RegistryMessageModelI& _rmm;
|
||||||
|
RegistryMessageModelI::SubscriptionReference _rmm_sr;
|
||||||
FactorioLogParser& _flp;
|
FactorioLogParser& _flp;
|
||||||
|
FactorioLogParser::SubscriptionReference _flp_sr;
|
||||||
|
|
||||||
std::vector<Contact3Handle> _linked_contacts;
|
std::vector<ContactHandle4> _linked_contacts;
|
||||||
|
|
||||||
|
void sendToLinked(const std::string& message);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Factorio(ConfigModelI& conf, Contact3Registry& cr, RegistryMessageModel& rmm, FactorioLogParser& flp);
|
Factorio(ConfigModelI& conf, ContactStore4I& cs, RegistryMessageModelI& rmm, FactorioLogParser& flp);
|
||||||
virtual ~Factorio(void);
|
virtual ~Factorio(void);
|
||||||
|
|
||||||
protected: // rmm
|
protected: // rmm
|
||||||
|
@ -14,7 +14,17 @@ FactorioLogParser::FactorioLogParser(ConfigModelI& conf) :
|
|||||||
FactorioLogParser::~FactorioLogParser(void) {
|
FactorioLogParser::~FactorioLogParser(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
float FactorioLogParser::tick(float) {
|
float FactorioLogParser::tick(float delta) {
|
||||||
|
{ // making sure, incase mod events dont work
|
||||||
|
_manual_timer += delta;
|
||||||
|
if (_manual_timer >= 10.f) {
|
||||||
|
_manual_timer = 0.f;
|
||||||
|
if (_log_file.is_open()) {
|
||||||
|
readLines();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard lg{_event_queue_mutex};
|
std::lock_guard lg{_event_queue_mutex};
|
||||||
while (!_event_queue.empty()) {
|
while (!_event_queue.empty()) {
|
||||||
dispatchRaw(_event_queue.front().event, _event_queue.front().params);
|
dispatchRaw(_event_queue.front().event, _event_queue.front().params);
|
||||||
@ -36,19 +46,7 @@ void FactorioLogParser::onFileEvent(const std::string& path, const filewatch::Ev
|
|||||||
std::cerr << "FLP: modified file not open!\n";
|
std::cerr << "FLP: modified file not open!\n";
|
||||||
//resetLogFile();
|
//resetLogFile();
|
||||||
} else {
|
} else {
|
||||||
std::string line;
|
readLines();
|
||||||
while (std::getline(_log_file, line).good()) {
|
|
||||||
if (line.empty()) {
|
|
||||||
std::cerr << "FLP error: getline empty??\n";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto parse_res = log_parse_line(line);
|
|
||||||
if (parse_res.has_value()) {
|
|
||||||
queueRaw(parse_res.value().event, parse_res.value().params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_log_file.clear(); // reset eof and fail bits
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,6 +63,22 @@ void FactorioLogParser::resetLogFile(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FactorioLogParser::readLines(void) {
|
||||||
|
std::string line;
|
||||||
|
while (std::getline(_log_file, line).good()) {
|
||||||
|
if (line.empty()) {
|
||||||
|
std::cerr << "FLP error: getline empty??\n";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto parse_res = log_parse_line(line);
|
||||||
|
if (parse_res.has_value()) {
|
||||||
|
queueRaw(parse_res.value().event, parse_res.value().params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_log_file.clear(); // reset eof and fail bits
|
||||||
|
}
|
||||||
|
|
||||||
void FactorioLogParser::queueRaw(std::string_view event, std::string_view params) {
|
void FactorioLogParser::queueRaw(std::string_view event, std::string_view params) {
|
||||||
std::lock_guard lg{_event_queue_mutex};
|
std::lock_guard lg{_event_queue_mutex};
|
||||||
_event_queue.push(EventEntry{static_cast<std::string>(event), static_cast<std::string>(params)});
|
_event_queue.push(EventEntry{static_cast<std::string>(event), static_cast<std::string>(params)});
|
||||||
|
@ -94,6 +94,8 @@ class FactorioLogParser : public FactorioLogParserEventProviderI {
|
|||||||
std::queue<EventEntry> _event_queue;
|
std::queue<EventEntry> _event_queue;
|
||||||
std::mutex _event_queue_mutex;
|
std::mutex _event_queue_mutex;
|
||||||
|
|
||||||
|
float _manual_timer {1.f};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FactorioLogParser(ConfigModelI& conf);
|
FactorioLogParser(ConfigModelI& conf);
|
||||||
virtual ~FactorioLogParser(void);
|
virtual ~FactorioLogParser(void);
|
||||||
@ -103,6 +105,8 @@ class FactorioLogParser : public FactorioLogParserEventProviderI {
|
|||||||
protected:
|
protected:
|
||||||
void onFileEvent(const std::string& path, const filewatch::Event change_type);
|
void onFileEvent(const std::string& path, const filewatch::Event change_type);
|
||||||
void resetLogFile(void);
|
void resetLogFile(void);
|
||||||
|
// assumes file is open!
|
||||||
|
void readLines(void);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void queueRaw(std::string_view event, std::string_view params);
|
void queueRaw(std::string_view event, std::string_view params);
|
||||||
|
Reference in New Issue
Block a user