Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions example_community_patch_settings_da.toml
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,9 @@ show_station_cargo = true
# Subgroup: Data
# --------------

# Vil du synkronisere landgangsholdsdata?
away_assignments = true

# Vil du synkronisere kamplogge?
battlelogs = true

Expand Down
3 changes: 3 additions & 0 deletions example_community_patch_settings_de.toml
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,9 @@ show_station_cargo = true
# Subgroup: Daten
# ---------------

# Außenteam-Einsatzdaten synchronisieren?
away_assignments = true

# Kampfberichte synchronisieren?
battlelogs = true

Expand Down
3 changes: 3 additions & 0 deletions example_community_patch_settings_en-GB-x-cockney.toml
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,9 @@ show_station_cargo = true
# Subgroup: Data
# --------------

# Do you want to sync away team assignment data?
away_assignments = true

# Do you want to sync battlelogs?
battlelogs = true

Expand Down
3 changes: 3 additions & 0 deletions example_community_patch_settings_en-x-minionese.toml
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,9 @@ show_station_cargo = true
# Subgroup: Data
# --------------

# Do you want to sync away team assignment data?
away_assignments = true

# Do you want to sync battlelogs?
battlelogs = true

Expand Down
3 changes: 3 additions & 0 deletions example_community_patch_settings_en.toml
Original file line number Diff line number Diff line change
Expand Up @@ -833,6 +833,9 @@ show_station_cargo = true
# Subgroup: Data
# --------------

# Do you want to sync away team assignment data?
away_assignments = true

# Do you want to sync battlelogs?
battlelogs = true

Expand Down
3 changes: 3 additions & 0 deletions example_community_patch_settings_es.toml
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,9 @@ show_station_cargo = true
# Subgroup: Data
# --------------

# ¿Quieres sincronizar los datos de asignaciones de equipos de exploración?
away_assignments = true

# ¿Quieres sincronizar los registros de batalla?
battlelogs = true

Expand Down
3 changes: 3 additions & 0 deletions example_community_patch_settings_fr.toml
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,9 @@ show_station_cargo = true
# Subgroup: Data
# --------------

# Voulez-vous synchroniser les données des missions d'équipe d'intervention ?
away_assignments = true

# Voulez-vous synchroniser les journaux de combat ?
battlelogs = true

Expand Down
3 changes: 3 additions & 0 deletions example_community_patch_settings_nl.toml
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,9 @@ show_station_cargo = true
# Subgroup: Data
# --------------

# Wil je data van landingsteam-opdrachten syncen?
away_assignments = true

# Wil je Gevechtslogboeken syncen?
battlelogs = true

Expand Down
3 changes: 3 additions & 0 deletions example_community_patch_settings_ru.toml
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,9 @@ show_station_cargo = true
# Subgroup: Data
# --------------

# Синхронизировать данные заданий десантной группы?
away_assignments = true

# Синхронизировать журналы боёв?
battlelogs = true

Expand Down
3 changes: 3 additions & 0 deletions example_community_patch_settings_tlh.toml
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,9 @@ show_station_cargo = true
# Subgroup: Data
# --------------

# Do you want Daq sync away team assignment De'?
away_assignments = true

# Do you want Daq sync battlelogs?
battlelogs = true

Expand Down
34 changes: 19 additions & 15 deletions mods/src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class SyncConfig
{
public:
enum class Type {
AwayAssignments,
Battles,
Buffs,
Buildings,
Expand All @@ -42,26 +43,29 @@ class SyncConfig

std::string proxy;

bool verify_ssl = true;
bool battlelogs = false;
bool buffs = false;
bool buildings = true;
bool haven = true;
bool inventory = false;
bool jobs = false;
bool missions = false;
bool officer = false;
bool research = true;
bool resources = false;
bool ships = false;
bool slots = false;
bool tech = false;
bool traits = false;
bool verify_ssl = true;
bool away_assignments = false;
bool battlelogs = false;
bool buffs = false;
bool buildings = true;
bool haven = true;
bool inventory = false;
bool jobs = false;
bool missions = false;
bool officer = false;
bool research = true;
bool resources = false;
bool ships = false;
bool slots = false;
bool tech = false;
bool traits = false;

[[nodiscard]] bool enabled(Type type) const;
};

constexpr std::array SyncOptions{
SyncConfig::Option{SyncConfig::Type::AwayAssignments, "away_assignment", "away_assignments",
&SyncConfig::away_assignments},
SyncConfig::Option{SyncConfig::Type::Battles, "battlelog", "battlelogs", &SyncConfig::battlelogs},
SyncConfig::Option{SyncConfig::Type::Buffs, "buff", "buffs", &SyncConfig::buffs},
SyncConfig::Option{SyncConfig::Type::Buildings, "module", "buildings", &SyncConfig::buildings},
Expand Down
1 change: 1 addition & 0 deletions mods/src/defaultconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ namespace Sync
constexpr const char* spocksclub_url = "https://spocks.club/sync/ingress/";
constexpr const char* nextspocksclub_url = "https://next.spocks.club/sync/ingress/";

constexpr bool away_assignments = true;
constexpr bool battlelogs = true;
constexpr bool buffs = true;
constexpr bool buildings = true;
Expand Down
123 changes: 123 additions & 0 deletions mods/src/patches/parts/sync.cc
Original file line number Diff line number Diff line change
Expand Up @@ -796,6 +796,9 @@ static std::mutex resource_states_alliance_mtx;
static std::unordered_map<int64_t, int64_t> slot_states;
static std::mutex slot_states_mtx;

static std::unordered_map<int64_t, size_t> away_assignment_states;
static std::mutex away_assignment_states_mtx;

static std::unordered_map<int64_t, int64_t> structure_states;
static std::mutex structure_states_mtx;

Expand Down Expand Up @@ -1095,6 +1098,110 @@ static void ship_combat_log_data()
namespace processors
{

// Builds the sync event for one away team assignment instance and appends it to `out_array` only if the
// instance's observable state changed since the last time it was emitted. Caller must hold
// trackers::away_assignment_states_mtx.
static void away_assignment_event(const Digit::PrimeServer::Models::AwayAssignmentInstance& instance,
nlohmann::json& out_array)
{
using json = nlohmann::json;
using trackers::away_assignment_states;

// Protobuf map iteration order is not guaranteed to match slot order, so sort by slot index
// before emitting officer_ids to keep the array (and therefore the de-dup hash) stable.
std::vector<std::pair<int64_t, int64_t>> officer_slots(instance.officerids().begin(), instance.officerids().end());
std::ranges::sort(officer_slots, {}, &std::pair<int64_t, int64_t>::first);

auto officer_ids = json::array();
for (const auto& [slot, officer_id] : officer_slots) {
if (officer_id != 0) {
officer_ids.push_back(officer_id);
}
}

json event = {{"type", SyncConfig::Type::AwayAssignments},
{"aid", instance.id()},
{"template_id", instance.awayassignmenttemplateid()},
{"state", instance.state()},
{"officer_ids", officer_ids},
{"job_uuid", instance.jobuuid()},
{"duration", instance.parameters().duration()},
{"rarity", instance.rarity()}};

const auto state_value = std::hash<json>{}(event);

if (const auto& it = away_assignment_states.find(instance.id());
it == away_assignment_states.end() || it->second != state_value) {
away_assignment_states[instance.id()] = state_value;
out_array.push_back(std::move(event));
}
}

static void away_assignments_list(std::unique_ptr<std::string>&& bytes)
{
using json = nlohmann::json;
static std::atomic_bool is_first_sync{true};

if (auto response = Digit::PrimeServer::Models::AwayAssignmentUserListResponse(); response.ParseFromString(*bytes)) {

http::logging::trace("PROCESS", "away assignments",
STR_FORMAT("Processing {} away assignments", response.instances_size()));

std::unordered_set<int64_t> ids_in_response;
ids_in_response.reserve(static_cast<size_t>(response.instances_size()));
auto assignment_array = json::array();

{
std::scoped_lock lk(trackers::away_assignment_states_mtx);

for (const auto& instance : response.instances()) {
ids_in_response.insert(instance.id());
away_assignment_event(instance, assignment_array);
}

// Prune entries that are no longer present to prevent unbounded growth
for (auto it = trackers::away_assignment_states.begin(); it != trackers::away_assignment_states.end();) {
if (!ids_in_response.contains(it->first)) {
assignment_array.push_back({{"type", "collected_" + SyncConfig::Type::AwayAssignments}, {"aid", it->first}});
it = trackers::away_assignment_states.erase(it);
} else {
++it;
}
}
}

if (!assignment_array.empty()) {
const bool first_sync = is_first_sync.exchange(false, std::memory_order_acq_rel);
workers::queue_data(SyncConfig::Type::AwayAssignments, assignment_array, first_sync);
}
} else {
spdlog::error("Failed to parse away assignments");
}
}

static void away_assignment_instance(std::unique_ptr<std::string>&& bytes)
{
using json = nlohmann::json;

if (auto instance = Digit::PrimeServer::Models::AwayAssignmentInstance(); instance.ParseFromString(*bytes)) {

http::logging::trace("PROCESS", "away assignment instance",
STR_FORMAT("Processing away assignment {}", instance.id()));

auto assignment_array = json::array();
{
std::scoped_lock lk(trackers::away_assignment_states_mtx);
away_assignment_event(instance, assignment_array);
}

if (!assignment_array.empty()) {
workers::queue_data(SyncConfig::Type::AwayAssignments, assignment_array);
}
} else {
spdlog::error("Failed to parse away assignment instance");
}
}

static void queue_battle_ids(const std::vector<uint64_t>& battle_ids)
{
std::vector<uint64_t> to_enqueue;
Expand Down Expand Up @@ -1502,6 +1609,10 @@ static void jobs(std::unique_ptr<std::string>&& bytes)
const auto& scrap = job.scrapyardparams();
job_params = {{"psid", scrap.shipid()}, {"hull_id", scrap.hullid()}, {"level", scrap.level()}};
} break;
case Digit::PrimeServer::Models::JOBTYPE_AWAYASSIGNMENT: {
const auto& away_assignment = job.awayassignmentparams();
job_params = {{"aid", away_assignment.awayassignmentinstanceid()}};
} break;
default:
continue;
}
Expand Down Expand Up @@ -2301,6 +2412,18 @@ static void HandleEntityGroup(EntityGroup* entity_group)
const auto& sync_options = Config::Get().sync_options;

switch (entity_group->Type_) {
// away assignments
case EntityGroup::Type::AwayAssignmentsList:
if (sync_options.away_assignments) {
submit_async(processors::away_assignments_list);
}
break;
case EntityGroup::Type::AwayAssignmentsInstance:
if (sync_options.away_assignments) {
submit_async(processors::away_assignment_instance);
}
break;

// battlelogs
case EntityGroup::Type::BattleResultHeaders:
if (sync_options.battlelogs) {
Expand Down
Loading