Compare commits

..

10 Commits

Author SHA1 Message Date
161f605b20 port to contact4
Some checks failed
ContinuousDelivery / linux-ubuntu (push) Has been cancelled
ContinuousDelivery / windows (push) Has been cancelled
ContinuousIntegration / linux (push) Has been cancelled
ContinuousIntegration / macos (push) Has been cancelled
ContinuousIntegration / windows (push) Has been cancelled
ContinuousDelivery / release (push) Has been cancelled
2025-03-10 22:57:15 +01:00
6aa90a1852 make forwarding configurable
Some checks failed
ContinuousDelivery / linux-ubuntu (push) Has been cancelled
ContinuousDelivery / windows (push) Has been cancelled
ContinuousIntegration / linux (push) Has been cancelled
ContinuousIntegration / macos (push) Has been cancelled
ContinuousIntegration / windows (push) Has been cancelled
ContinuousDelivery / release (push) Has been cancelled
2025-01-12 13:37:35 +01:00
f69923cbbb ignore pings, the polute the chat and are unreadable without context
Some checks failed
ContinuousDelivery / linux-ubuntu (push) Has been cancelled
ContinuousDelivery / windows (push) Has been cancelled
ContinuousIntegration / linux (push) Has been cancelled
ContinuousIntegration / macos (push) Has been cancelled
ContinuousIntegration / windows (push) Has been cancelled
ContinuousDelivery / release (push) Has been cancelled
2025-01-09 19:43:20 +01:00
b62ab60366 Create LICENSE 2025-01-06 18:11:52 +01:00
117e40dc9e use sr
Some checks failed
ContinuousDelivery / linux-ubuntu (push) Has been cancelled
ContinuousDelivery / windows (push) Has been cancelled
ContinuousIntegration / linux (push) Has been cancelled
ContinuousIntegration / macos (push) Has been cancelled
ContinuousIntegration / windows (push) Has been cancelled
ContinuousDelivery / release (push) Has been cancelled
2024-10-25 13:57:14 +02:00
050c7f3be1 update for rmmi
Some checks failed
ContinuousDelivery / linux-ubuntu (push) Has been cancelled
ContinuousDelivery / windows (push) Has been cancelled
ContinuousIntegration / linux (push) Has been cancelled
ContinuousIntegration / macos (push) Has been cancelled
ContinuousIntegration / windows (push) Has been cancelled
ContinuousDelivery / release (push) Has been cancelled
2024-10-06 12:47:04 +02:00
4c6beb592c fallback for no file mod events
Some checks failed
ContinuousDelivery / linux-ubuntu (push) Failing after 21s
ContinuousIntegration / linux (push) Successful in 21s
ContinuousDelivery / windows (push) Has been cancelled
ContinuousIntegration / macos (push) Has been cancelled
ContinuousIntegration / windows (push) Has been cancelled
ContinuousDelivery / release (push) Has been cancelled
2024-06-12 22:24:47 +02:00
a91b4d41dd hardcode some events (working)
Some checks failed
ContinuousDelivery / windows (push) Waiting to run
ContinuousDelivery / release (push) Blocked by required conditions
ContinuousIntegration / macos (push) Waiting to run
ContinuousIntegration / windows (push) Waiting to run
ContinuousDelivery / linux-ubuntu (push) Failing after 22s
ContinuousIntegration / linux (push) Successful in 22s
2024-06-12 21:30:51 +02:00
d18ec4e1ca load linked contacts from config (not sending yet)
Some checks failed
ContinuousDelivery / windows (push) Waiting to run
ContinuousDelivery / release (push) Blocked by required conditions
ContinuousIntegration / macos (push) Waiting to run
ContinuousIntegration / windows (push) Waiting to run
ContinuousDelivery / linux-ubuntu (push) Failing after 21s
ContinuousIntegration / linux (push) Successful in 22s
2024-06-12 21:11:12 +02:00
7c3b867c7c add cd 2024-06-12 20:13:02 +02:00
7 changed files with 366 additions and 43 deletions

159
.github/workflows/cd.yml vendored Normal file
View File

@ -0,0 +1,159 @@
name: ContinuousDelivery
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
env:
BUILD_TYPE: RelWidthDebInfo
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
jobs:
linux-ubuntu:
timeout-minutes: 10
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v4
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 4
- name: Test
working-directory: ${{github.workspace}}/build
run: ctest -C ${{env.BUILD_TYPE}}
- name: Determine tag name
id: tag
shell: bash
# taken from llama.cpp
run: |
SHORT_HASH="$(git rev-parse --short=7 HEAD)"
if [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then
echo "name=dev-${SHORT_HASH}" >> $GITHUB_OUTPUT
else
SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-')
echo "name=dev-${SAFE_NAME}-${SHORT_HASH}" >> $GITHUB_OUTPUT
fi
- name: Compress artifacts
shell: bash
run: |
tar -czvf ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-ubuntu20.04-x86_64.tar.gz -C ${{github.workspace}}/build/bin/ .
- uses: actions/upload-artifact@v4
with:
# TODO: simpler name?
name: ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-ubuntu20.04-x86_64
# TODO: do propper packing
path: |
${{github.workspace}}/${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-ubuntu20.04-x86_64.tar.gz
windows:
timeout-minutes: 15
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
# setup vs env
- uses: ilammy/msvc-dev-cmd@v1
with:
arch: amd64
- name: Configure CMake
run: cmake -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_TOOLCHAIN_FILE=C:/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-windows-static
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Determine tag name
id: tag
shell: bash
# taken from llama.cpp
run: |
SHORT_HASH="$(git rev-parse --short=7 HEAD)"
if [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then
echo "name=dev-${SHORT_HASH}" >> $GITHUB_OUTPUT
else
SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-')
echo "name=dev-${SAFE_NAME}-${SHORT_HASH}" >> $GITHUB_OUTPUT
fi
- name: Compress artifacts
shell: powershell
run: |
Compress-Archive -Path ${{github.workspace}}/build/bin/* -Destination ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-x86_64.zip
- uses: actions/upload-artifact@v4
with:
# TODO: simpler name?
name: ${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-x86_64
# TODO: do propper packing
path: |
${{github.workspace}}/${{ github.event.repository.name }}-${{ steps.tag.outputs.name }}-${{ runner.os }}-msvc-x86_64.zip
release:
if: ${{ ( github.event_name == 'push' && github.ref == 'refs/heads/master' ) }}
runs-on: ubuntu-latest
needs:
- linux-ubuntu
- windows
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Determine tag name
id: tag
shell: bash
# taken from llama.cpp
run: |
SHORT_HASH="$(git rev-parse --short=7 HEAD)"
if [[ "${{ env.BRANCH_NAME }}" == "master" ]]; then
echo "name=dev-${SHORT_HASH}" >> $GITHUB_OUTPUT
else
SAFE_NAME=$(echo "${{ env.BRANCH_NAME }}" | tr '/' '-')
echo "name=dev-${SAFE_NAME}-${SHORT_HASH}" >> $GITHUB_OUTPUT
fi
- name: Download artifacts
id: download-artifact
uses: actions/download-artifact@v4
with:
path: ./artifacts/
- name: Create release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ steps.tag.outputs.name }}
shell: bash
run: |
gh release create "$tag" \
--repo="$GITHUB_REPOSITORY" \
--title="nightly ${tag#v}" \
--notes="nightly build" \
--prerelease
- name: Upload artifacts
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag: ${{ steps.tag.outputs.name }}
shell: bash
run: |
ls -laR ./artifacts
gh release upload "$tag" ./artifacts/*/* \
--repo="$GITHUB_REPOSITORY"

21
LICENSE Normal file
View 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.

View File

@ -34,13 +34,13 @@ SOLANA_PLUGIN_EXPORT uint32_t solana_plugin_start(struct SolanaAPI* solana_api)
try {
auto* conf = PLUG_RESOLVE_INSTANCE(ConfigModelI);
auto* cr = PLUG_RESOLVE_INSTANCE_VERSIONED(Contact3Registry, "1");
auto* rmm = PLUG_RESOLVE_INSTANCE(RegistryMessageModel);
auto* cs = PLUG_RESOLVE_INSTANCE(ContactStore4I);
auto* rmm = PLUG_RESOLVE_INSTANCE(RegistryMessageModelI);
// static store, could be anywhere tho
// construct with fetched dependencies
g_flp = std::make_unique<FactorioLogParser>(*conf);
g_f = std::make_unique<Factorio>(*cr, *rmm, *g_flp);
g_f = std::make_unique<Factorio>(*conf, *cs, *rmm, *g_flp);
// register types
PLUG_PROVIDE_INSTANCE(FactorioLogParser, plugin_name, g_flp.get());

View File

@ -1,24 +1,61 @@
#include "./factorio.hpp"
#include "factorio_log_parser.hpp"
#include <solanaceae/util/config_model.hpp>
#include <solanaceae/util/utils.hpp>
#include <solanaceae/contact/contact_store_i.hpp>
#include <solanaceae/message3/components.hpp>
#include <solanaceae/contact/components.hpp>
Factorio::Factorio(Contact3Registry& cr, RegistryMessageModel& rmm, FactorioLogParser& flp) :
_cr(cr),
_rmm(rmm),
_flp(flp)
{
_rmm.subscribe(this, RegistryMessageModel_Event::message_construct);
void Factorio::sendToLinked(const std::string& message) {
for (const auto& h : _linked_contacts) {
if (!static_cast<bool>(h)) {
continue;
}
_flp.subscribe(this, FactorioLogParser_Event::join);
_flp.subscribe(this, FactorioLogParser_Event::leave);
_flp.subscribe(this, FactorioLogParser_Event::chat);
_flp.subscribe(this, FactorioLogParser_Event::died);
_flp.subscribe(this, FactorioLogParser_Event::evolution);
_flp.subscribe(this, FactorioLogParser_Event::research_started);
_flp.subscribe(this, FactorioLogParser_Event::research_finished);
_flp.subscribe(this, FactorioLogParser_Event::research_cancelled);
_rmm.sendText(h, message);
}
}
Factorio::Factorio(ConfigModelI& conf, ContactStore4I& cs, RegistryMessageModelI& rmm, FactorioLogParser& flp) :
_conf(conf),
_cs(cs),
_rmm(rmm),
_rmm_sr(_rmm.newSubRef(this)),
_flp(flp),
_flp_sr(_flp.newSubRef(this))
{
// config
for (const auto&& [contact_id, enabled] : conf.entries_bool("Factorio", "link_to_contact")) {
//std::cout << "config id:" << contact_id << " e:" << enabled << "\n";
const auto id_vec = hex2bin(contact_id);
// search
ContactHandle4 h = _cs.getOneContactByID(ByteSpan{id_vec});
if (!static_cast<bool>(h)) {
// not found, create thin contact with just id
h = _cs.contactHandle(_cs.registry().create());
h.emplace<Contact::Components::ID>(id_vec);
_cs.throwEventConstruct(h);
std::cout << "Factorio: contact not found, created thin contact from ID. (" << contact_id << ")\n";
}
_linked_contacts.push_back(h);
}
_rmm_sr.subscribe(RegistryMessageModel_Event::message_construct);
_flp_sr
.subscribe(FactorioLogParser_Event::join)
.subscribe(FactorioLogParser_Event::leave)
.subscribe(FactorioLogParser_Event::chat)
.subscribe(FactorioLogParser_Event::died)
.subscribe(FactorioLogParser_Event::evolution)
.subscribe(FactorioLogParser_Event::research_started)
.subscribe(FactorioLogParser_Event::research_finished)
.subscribe(FactorioLogParser_Event::research_cancelled)
;
}
Factorio::~Factorio(void) {
@ -29,42 +66,117 @@ bool Factorio::onEvent(const Message::Events::MessageConstruct& e) {
}
bool Factorio::onEvent(const FactorioLog::Events::Join& e) {
std::cout << "F: 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;
}
bool Factorio::onEvent(const FactorioLog::Events::Leave& e) {
std::cout << "F: 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;
}
bool Factorio::onEvent(const FactorioLog::Events::Chat& e) {
std::cout << "F: 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;
}
bool Factorio::onEvent(const FactorioLog::Events::Died& e) {
std::cout << "F: 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;
}
bool Factorio::onEvent(const FactorioLog::Events::Evolution& e) {
std::cout << "F: 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;
}
bool Factorio::onEvent(const FactorioLog::Events::ResearchStarted& e) {
std::cout << "F: 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;
}
bool Factorio::onEvent(const FactorioLog::Events::ResearchFinished& e) {
std::cout << "F: 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;
}
bool Factorio::onEvent(const FactorioLog::Events::ResearchCancelled& e) {
std::cout << "F: 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;
}

View File

@ -1,16 +1,29 @@
#pragma once
#include <solanaceae/contact/fwd.hpp>
#include <solanaceae/message3/registry_message_model.hpp>
#include "./factorio_log_parser.hpp"
#include <vector>
// fwd
struct ConfigModelI;
class Factorio : public RegistryMessageModelEventI, public FactorioLogParserEventI {
Contact3Registry& _cr;
RegistryMessageModel& _rmm;
ConfigModelI& _conf;
ContactStore4I& _cs;
RegistryMessageModelI& _rmm;
RegistryMessageModelI::SubscriptionReference _rmm_sr;
FactorioLogParser& _flp;
FactorioLogParser::SubscriptionReference _flp_sr;
std::vector<ContactHandle4> _linked_contacts;
void sendToLinked(const std::string& message);
public:
Factorio(Contact3Registry& cr, RegistryMessageModel& rmm, FactorioLogParser& flp);
Factorio(ConfigModelI& conf, ContactStore4I& cs, RegistryMessageModelI& rmm, FactorioLogParser& flp);
virtual ~Factorio(void);
protected: // rmm

View File

@ -14,7 +14,17 @@ FactorioLogParser::FactorioLogParser(ConfigModelI& conf) :
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};
while (!_event_queue.empty()) {
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";
//resetLogFile();
} else {
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
readLines();
}
}
}
@ -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) {
std::lock_guard lg{_event_queue_mutex};
_event_queue.push(EventEntry{static_cast<std::string>(event), static_cast<std::string>(params)});

View File

@ -94,6 +94,8 @@ class FactorioLogParser : public FactorioLogParserEventProviderI {
std::queue<EventEntry> _event_queue;
std::mutex _event_queue_mutex;
float _manual_timer {1.f};
public:
FactorioLogParser(ConfigModelI& conf);
virtual ~FactorioLogParser(void);
@ -103,6 +105,8 @@ class FactorioLogParser : public FactorioLogParserEventProviderI {
protected:
void onFileEvent(const std::string& path, const filewatch::Event change_type);
void resetLogFile(void);
// assumes file is open!
void readLines(void);
protected:
void queueRaw(std::string_view event, std::string_view params);