LegacyShell WikiLegacyShell Wiki
Back to LegacyShell
Home
Wiki
Plugins
Docs
Back to LegacyShell
Home
Wiki
Plugins
Docs
  • Documentation

    • Getting Started

      • What is LegacyShell?
      • Speed Setup
      • Requirements
      • Installation
      • First Run
      • Config Files
      • Making an Account
      • Troubleshooting (Getting Started)
    • Running a Server

      • Architecture Overview
      • The Database
      • Users and Ranks
      • Adding Game Servers
      • Client Mirrors
      • Perpetual
      • Backups
      • Rate Limiting
      • Moderation
      • Closed Mode
      • Deployment
      • Troubleshooting (Running a Server)
      • Hosting for Someone Else's Instance
    • Content Creation

      • Maps
      • Dealing with Babylon Models
      • Map Blocks
      • Items and Skins
      • Hats and Stamps
      • Sounds
      • Gamemodes
      • Seasonal Events
    • Plugin Development

      • Quickstart
      • I Want To...
      • Anatomy of a Plugin
      • Lifecycle
      • Dependencies
      • Events (Concept)
      • Event Reference

        • services: events
        • game: events — shared logic (src/shell/)
        • game: events — main-thread server process
        • game: events — per-connection client object
        • game: events — room lifecycle & tick loop
        • game: events — in-browser gameplay
        • client: events — client server & build pipeline
      • Commands
      • Client-Side Code
      • Static Assets
      • Content Packs
      • Networking
      • Workers and State
      • Prediction and Authority
      • Recipes

        • Recipe: Killstreaks
        • Recipe: New Pickup Item
        • Recipe: New Gamemode
        • Recipe: Custom Weapon
        • Recipe: UI Modification
        • Recipe: Discord Integration
        • Recipe: Replacing Core Behaviour
        • Recipe: Persistent Plugin Storage
        • Recipe: Rewarding Players with Currency
        • Recipe: Custom Per-Player Data
        • Recipe: Custom Theme
      • Publishing
      • Pitfalls
      • Modifiers
      • Sound and Apollo
    • Codebase Reference

      • Repo Layout
      • Shared Shell Layer
      • Server-Only Markers
      • The ss Object
      • Build Pipeline
      • Stamps and Babylons
      • Game Loop
      • Rooms and Workers
      • Wire Protocol
      • Generated

        • Wire Protocol Opcodes
        • Enums & Lookup Tables
        • Database Schema
        • Config Reference
        • Slash Command Reference
      • Services Internals
      • Catalog and Items
      • Permissions Internals
      • Physics and Collision
      • Known Quirks
      • Codebase Anecdotes
      • Development Timeline
    • Contributing

      • Documentation Style Guide
      • Generators
      • For AI Agents

Seasonal Events

Audience: Content creators · Prereqs: Items and Skins

Canonical source: src/shell/events.js (defaultEvents)

How the shop's seasonal rotation actually decides what's available, and what you can hook into as a content creator without touching gameplay code.

The date-range event system

events.js defines a list of named date ranges - a start ("MM-DD"), a duration ("2w", "13w", "999w" for the always-on default), and a data.shop block of item pools:

{
    name: 'groundhog-day',
    start: "02-02",
    duration: "2w",
    data: {
        shop: {
            temp: ["GroundhogDay"],   // items tagged this way appear in the shop for these 2 weeks only
        }
    },
},

The shop pools per event:

PoolMeaning
permItem tags that should always be shop-available (not actually event-scoped - used by the always-on _default event).
tempItem tags available only while this specific event is active.
tier1poolOne item chosen probabilistically from this pool each week (the "rare" gacha-style slot).
tier2pool / tier2countA fixed number (tier2count, default 1) of items always chosen from this pool each week.
tier3pool / tier3countA fixed number (tier3count, default 5) of items always chosen from this pool each week.

The actual connection point: item tags

Notice the pools are lists of tags, not item IDs directly - this is the same item_data.tags field from Items and Skins. Making an item participate in an existing event is entirely a content task, no coding required:

"item_data": { "class": "...", "meshName": "...", "tags": ["GroundhogDay"] }

Tag an item "GroundhogDay" and it automatically becomes available in the shop for that event's 2-week window every year, without touching events.js at all.

Adding a genuinely new event (not just tagging items into an existing one)

This means adding a new entry to defaultEvents itself - either by editing src/shell/events.js directly (a core-code change) or, the preferred approach per this project's philosophy, via a plugin hooking game:eventsInit/services:eventsInit to push a new event object into data.events at runtime. Either way this is a small coding task, not a pure content one - see Plugin Development if you're doing this as a plugin.

Common Issues

My tagged item never appears in the shop. Tags make an item eligible, not guaranteed - perm/temp tagged items still need the shop-rotation algorithm to actually select them for a given week (see Items and Skins on is_available), and tier1/tier2/tier3 pool items are chosen probabilistically/by count, not all-at-once.

An event isn't activating on the date I expect. Double-check start is genuinely "MM-DD" (no year) and duration is in the Nw/Nd (weeks/days) format matching the other entries - a malformed duration string won't necessarily error loudly.


This page was drafted with AI assistance and reviewed for accuracy. If something looks wrong, please open a PR or flag it.

Edit this page on GitHub
Prev
Gamemodes