#include "game/events/event_log.h" #include #include namespace sots::events { EventPos InvalidEventPos() { EventPos p; p.x = FLT_MAX; p.y = FLT_MAX; p.z = FLT_MAX; return p; } TurnEvents& EventStorage::GetOrCreateTurnBucket(int turn) { // No early exit: the last match wins, as the original's loop does. TurnEvents* found = nullptr; for (TurnEvents& b : turns_) { if (b.turn == turn) found = &b; } if (found) return *found; turns_.push_back(TurnEvents{}); turns_.back().turn = turn; return turns_.back(); } const PlayerEvent* EventStorage::FindDuplicate(const TurnEvents& bucket, const PlayerEvent& candidate) const { for (const PlayerEvent& e : bucket.events) { if (e.action != candidate.action) continue; if (e.location != candidate.location) continue; if (e.pos != candidate.pos) continue; if (e.message != candidate.message) continue; if (e.image != candidate.image) continue; // summary is deliberately not compared. return &e; } return nullptr; } void EventStorage::PruneOldTurns(int turn) { const int cutoff = turn - kPruneWindowTurns; if (turns_.empty()) return; // Index of the last bucket in the LEADING run of stale buckets; turns_.size() means the // run is empty (the original leaves its cursor on _Mylast in that case). std::size_t lastStale = turns_.size(); for (std::size_t i = 0; i < turns_.size(); ++i) { if (turns_[i].turn >= cutoff) break; lastStale = i; } if (lastStale == turns_.size()) return; // nothing stale at the front if (lastStale == 0) return; // a single leading stale bucket is kept turns_.erase(turns_.begin(), turns_.begin() + static_cast(lastStale)); } int EventStorage::Post(std::string summary, std::string message, const EventSubject* subject, const EventPos* pos, int turn, std::string_view image, int action) { PlayerEvent ev; ev.summary = std::move(summary); ev.message = std::move(message); ev.location = subject ? subject->id : 0; ev.image.assign(image); ev.action = (action == 0 && subject == nullptr && pos == nullptr) ? 2 : action; if (subject) { ev.pos = subject->pos; } else if (pos) { ev.pos = *pos; } // else: the constructor's FLT_MAX sentinel PruneOldTurns(turn); TurnEvents& bucket = GetOrCreateTurnBucket(turn); if (const PlayerEvent* dup = FindDuplicate(bucket, ev)) return dup->id; bucket.events.push_back(std::move(ev)); if (nextId_ == 0) nextId_ = 1; const int id = nextId_++; bucket.events.back().id = id; return id; } std::size_t EventStorage::total_events() const { std::size_t n = 0; for (const TurnEvents& b : turns_) n += b.events.size(); return n; } } // namespace sots::events