Skip to content

World Events - #289

Open
jptaylor wants to merge 6 commits into
mainfrom
jpt/world-events
Open

World Events#289
jptaylor wants to merge 6 commits into
mainfrom
jpt/world-events

Conversation

@jptaylor

Copy link
Copy Markdown
Collaborator

Summary

World Events let you run time-bounded competitions inside Gradient Bang. An admin creates an event in the database with a title, description, join code, start/end dates, and a visibility window. Players enter the join code during character creation to link that character to the event — one event per character, join-at-creation only. While the event runs, participants are ranked against each other across all four leaderboard categories. When the event ends, a cron job freezes the leaderboard into a snapshot blob. The event remains visible (with frozen results) until the visibility window expires, typically 48 hours after ending.

On the client side, if your character is in an event, your in-game rank badge automatically reflects event standing (the session polling endpoint resolves scope server-side). The leaderboard dialog shows a scope toggle between the event and global views, and a "World Events" tab lists all visible events with top players per category. The join code is never shown publicly — events are discoverable but joining requires the code, which can be distributed via external channels (e.g. a Product Hunt page linked from the event description).

Changes

Database:

  • world_events table (title, description, join code, dates, frozen results blob, image/link URLs)
  • world_event_participants junction with unique-per-character constraint
  • Extended leaderboard_cache with event_id column for event-scoped caching
  • validate_event_join_code() and freeze_world_event_results() functions
  • Cron job to auto-freeze ended events every minute

Edge functions:

  • user_character_create — accepts optional event_join_code, validates early, inserts late, rolls back on failure, returns event_id + event_title
  • leaderboard_resources — accepts optional event_id, 1-min TTL for event cache, returns frozen blob for ended events
  • leaderboard_session — new session-aware endpoint, resolves event vs global by character_id
  • world_events_list — new public endpoint, returns visible events with top 3 per category across all four leaderboard dimensions
  • user_character_list and login — return event membership per character

Client:

  • CreateCharacter — "Have an event code?" disclosure input, sets playerEvent from create response (or clears it for non-event characters)
  • usePlayerRank — polls leaderboard_session with character_id instead of raw leaderboard_resources
  • Leaderboard dialog — separate dialog data slot with TTL freshness (5min global, 1min event), fetches world events list, scope-aware refetch on toggle
  • LeaderboardPanel — scope toggle (event name / Global), World Events tab with event cards, frozen results indicator
  • Store — playerEvent, leaderboardScope, leaderboardDialogData with timestamp, worldEvents
  • Title — sets playerEvent on character select, skips overwrite for new characters

@github-actions

Copy link
Copy Markdown

Preview deployed: https://gradient-bang-m7zdoqs0x-daily-co.vercel.app

Time-bounded competitive events joined via secret code at character creation.
Event-scoped leaderboard with 1-min cache, frozen results on event end,
and 48h post-event visibility. New session-aware ranking endpoint so
in-game rank reflects event standing automatically.
- Separate dialog leaderboard data from session poll data so scope
  toggle actually refetches from the correct endpoint
- Wire up setPlayerEvent in login flow (login endpoint now returns
  event membership, Title.tsx sets it on character select)
- Fail character creation if event participant insert fails (clean up
  character + ship on failure since join is only possible at creation)
- Surface errors in world_events_list instead of silent HTTP 200 with
  empty data
- Add territory to world events top players (endpoint, types, and UI)
- World events client cache TTL set to 1 minute
- Add TTL to dialog leaderboard data (5min global, 1min event) so
  reopening the dialog refetches stale data instead of showing it
  indefinitely
- Return event_title from character create endpoint so newly created
  event characters get setPlayerEvent called immediately from the
  create handler, without needing a re-login
CreateCharacter already sets playerEvent from the create response.
Title.tsx was unconditionally re-deriving it from the characters store,
which doesn't contain the just-created character, clearing the event.
Now only does the store lookup for existing character selection.
CreateCharacter now calls setPlayerEvent(null) for non-event characters,
clearing any stale event state from a previously selected character and
resetting leaderboardScope back to global.
@github-actions

Copy link
Copy Markdown

Preview deployed: https://gradient-bang-3dwkf3md1-daily-co.vercel.app

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant