> For the complete documentation index, see [llms.txt](https://airdevelopment.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://airdevelopment.gitbook.io/docs/aircore/configuration/modules/announcements.md).

# Announcements

## General

### Managing

| Command                             | Effect                                                                                                                                |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `/announcement trigger <id> [args]` | Fires the announcement immediately, ignoring its schedule. `[args]` is optional free text. See [Arguments](#arguments) for more info. |
| `/announcement enable <id>`         | Enables an announcement without editing the config.                                                                                   |
| `/announcement disable <id>`        | Disables an announcement without editing the config.                                                                                  |

### Arguments

When an announcement is fired via `/announcement trigger <id> [args]`, the free text after the id becomes available inside that firing's components as `%announcement_arg_1%`, `%announcement_arg_2%`, etc. (blank if not provided).

```yaml
staff_alert:
  schedule:
    type: MANUAL
  sequence: ORDERED
  entries:
    - title:
        title: "SERVER ALERT"
        subtitle: "%announcement_arg_1%"
      chat: "[ALERT] %announcement_arg_1%"
```

```
/announcement trigger staff_alert "Restarting in 5 minutes"
```

### Creating your own file

Files can be split across `/announcements/` subdirectories (e.g. `/announcements/vip/tips.yml`). Everything defined in split files is merged into the same list at startup.

```yaml
enabled: true

announcements:
  welcome_tip:
    ...
```

Setting the top-level `enabled: false` disables every announcement defined in that file.

## Configuration

### Schedule

Every announcement defines **when** it fires via `schedule.type`:

| Type       | Behavior                                                        |
| ---------- | --------------------------------------------------------------- |
| `INTERVAL` | Fires every `interval` seconds.                                 |
| `CRON`     | Fires at fixed `times` of day.                                  |
| `MANUAL`   | Never fires on its own (only via `/announcement trigger <id>`). |

{% hint style="info" %}
To delay the first firing, set `delay` (seconds). Later firings still follow the normal `interval`. Defaults to `0`; useful to avoid collisions between announcements on server startup.

```yaml
schedule:
  type: INTERVAL
  interval: 900
  delay: 0
```

{% endhint %}

### Sequence

`sequence` decides **which entries fire, and how they're timed**, each time the schedule fires.

| Sequence  | Behavior                                                                                                   |
| --------- | ---------------------------------------------------------------------------------------------------------- |
| `ORDERED` | One entry per firing. Walks through the entry list in order, looping back to the start after the last one. |
| `RANDOM`  | One entry per firing, chosen by `weight`.                                                                  |
| `CHAIN`   | Every entry fires from a single firing, each delayed by its own `offset` (seconds) from that firing.       |

An entry can contain any combination of [Components](#components). Everything inside the entry fires together, in the order listed.

### Force

```yaml
force: true
```

Announcement-level field, alongside `enabled`. When `true`, the announcement is delivered even to players who have disabled announcements via `/announcetoggle`.

Reserve this for announcements players genuinely need to see (warnings, security notices, etc).

### Conditions

Conditions restrict who an announcement is sent to. They're evaluated per playe**r**, every time the announcement fires. A player who fails a condition simply doesn't receive that firing; nobody else is affected.

```yaml
conditions:
  - "%aircore_player_balance_RAW% < 100"
```

Conditions are evaluated as strings. See [Conditions](/docs/global-features/conditions.md) for more information.

### Components

Components are the actual message fields inside an entry. All components in an entry fire together, in the order listed.

<table><thead><tr><th>Component</th><th>Example</th></tr></thead><tbody><tr><td><code>chat</code></td><td><p></p><pre class="language-yaml"><code class="lang-yaml">chat: "&#x3C;red>single line"
</code></pre><pre class="language-yaml"><code class="lang-yaml">chat:
  - "&#x3C;red>line 1"
  - "&#x3C;blue>line 2"
</code></pre></td></tr><tr><td><code>actionbar</code></td><td><pre class="language-yaml"><code class="lang-yaml">actionbar: "text"
</code></pre></td></tr><tr><td><code>title</code></td><td><pre class="language-yaml"><code class="lang-yaml">title:
  text: "text"
  fade-in: 5
  stay: 60
  fade-out: 5
</code></pre></td></tr><tr><td><code>subtitle</code></td><td><pre class="language-yaml"><code class="lang-yaml">subtitle: "text"
</code></pre></td></tr><tr><td><code>bossbar</code></td><td><pre class="language-yaml"><code class="lang-yaml">bossbar:
  enabled: true
  text: "text"
  duration: 0places it
  color: RED
  overlay: PROGRESS
  progress: 1.0
  countdown: false
</code></pre></td></tr><tr><td><code>sound</code></td><td><pre class="language-yaml"><code class="lang-yaml">sound:
  key: "entity.wither.spawn"
  volume: 1.0
  pitch: 1.0
</code></pre></td></tr><tr><td><code>command</code></td><td><pre class="language-yaml"><code class="lang-yaml">command:
  run-as: CONSOLE # or PLAYER
  command: "restart"
</code></pre></td></tr></tbody></table>

Every component supports PlaceholderAPI (if installed), MiniMessage formatting (see [**Messages**](/docs/global-features/messages.md)), and the following built-in placeholders:

| Placeholder            | Resolves to                                                                                            |
| ---------------------- | ------------------------------------------------------------------------------------------------------ |
| `%player%`             | The targeted player's name.                                                                            |
| `%announcement_arg_N%` | The Nth word/quoted-string passed to `/announcement trigger <id> [args]`. See [Arguments](#arguments). |

## Examples

{% tabs %}
{% tab title="Example 1" %}
**Rotating chat tips**

One entry, repeated on a fixed interval, to everyone.

```yaml
welcome_tip:
  enabled: true

  schedule:
    type: INTERVAL
    interval: 900
    delay: 0

  sequence: ORDERED

  entries:
    - chat: "Type /help to see all available commands."
    - chat: "Don't forget to vote! Use /vote for rewards."
    - chat: "Join our Discord for updates and giveaways."
```

{% endtab %}

{% tab title="Example 2" %}
**Conditional, weighted, multi-component**

Only sent to players who qualify, random weighted pick, one entry fires actionbar + sound together.

```yaml
low_balance:
  enabled: true

  schedule:
    type: INTERVAL
    interval: 1800
    delay: 45

  conditions:
    - "%aircore_player_balance_RAW% < 100"

  sequence: RANDOM

  entries:
    - weight: 60
      actionbar: "Running low on cash? Try /jobs to start earning!"
      sound:
        key: "entity.experience_orb.pickup"
        volume: 0.6
        pitch: 1.4

    - weight: 20
      title:
        title: "Need Money?"
        subtitle: "Check out /shop and /jobs"
        fade-in: 10
        stay: 60
        fade-out: 10

    - weight: 20
      actionbar: "Tip: selling items at /shop is an easy way to top up your balance."
```

{% endtab %}

{% tab title="Example 3" %}
**Paired start/end event, date-scoped**

`pvp_weekend_start` and `pvp_weekend_end` are two independent `CRON` announcements, kept in sync by hand — there's no linkage between them in config or code.

```yaml
pvp_weekend_start:
  enabled: false

  schedule:
    type: CRON
    times:
      - "18:00"
    dates:
      - "05/07"
      - "22/12/26"

  sequence: ORDERED

  entries:
    - chat:
        - " "
        - "PVP WEEKEND is now active! Friendly fire is ON server-wide."
        - " "
      bossbar:
        enabled: true
        text: "PvP Weekend Active!"
        duration: 0
        color: RED
        overlay: SEGMENTED_6
        progress: 1.0
        countdown: false
      sound:
        key: "entity.wither.spawn"
        volume: 1.0
        pitch: 1.0
      command:
        run-as: CONSOLE
        command: "pvpmanager zone enable spawn"

pvp_weekend_end:
  enabled: false

  schedule:
    type: CRON
    times:
      - "18:00"
    dates:
      - "07/07"
      - "24/12/26"

  sequence: ORDERED

  entries:
    - chat: "[PvP Weekend] Friendly fire is now OFF. Thanks for playing!"
      command:
        run-as: CONSOLE
        command: "pvpmanager zone disable spawn"
```

{% endtab %}

{% tab title="Example 4" %}
**Manual, argument-driven alert**

Never fires on its own — only via `/announcement trigger staff_alert "..."`, making it usable as a webstore executable command.

```yaml
staff_alert:
  enabled: true

  schedule:
    type: MANUAL

  sequence: ORDERED

  entries:
    - title:
        title: "SERVER ALERT"
        subtitle: "%announcement_arg_1%"
        fade-in: 5
        stay: 60
        fade-out: 5
      sound:
        key: "block.note_block.pling"
        volume: 1.0
        pitch: 0.5
      chat: "[ALERT] %announcement_arg_1%"
```

{% endtab %}

{% tab title="Example 5" %}
**Forced restart countdown**

Bypasses `/announcetoggle`, single `CRON` trigger unrolls into a staged countdown via `CHAIN`.

```yaml
restart_warning:
  enabled: true
  force: true

  schedule:
    type: CRON
    times:
      - "03:00"

  sequence: CHAIN

  entries:
    - offset: 0
      chat: "[Restart] Server restarting in 5 minutes."
      actionbar: "Restart in 5 minutes"
      sound:
        key: "block.note_block.pling"
        volume: 0.8
        pitch: 1.0

    - offset: 120
      chat: "[Restart] Server restarting in 3 minutes."
      actionbar: "Restart in 3 minutes"
      sound:
        key: "block.note_block.pling"
        volume: 0.8
        pitch: 1.2

    - offset: 240
      chat:
        - " "
        - "[Restart] Server restarting in 1 minute. Wrap it up!"
        - " "
      title:
        title: "RESTARTING"
        subtitle: "In 1 minute"
        fade-in: 5
        stay: 40
        fade-out: 5
      bossbar:
        enabled: true
        text: "Restarting in 1 minute..."
        duration: 60
        color: RED
        overlay: PROGRESS
        progress: 1.0
        countdown: true
      sound:
        key: "entity.wither.spawn"
        volume: 1.0
        pitch: 1.5

    - offset: 300
      chat: "[Restart] Restarting now..."
      command:
        run-as: CONSOLE
        command: "restart"
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://airdevelopment.gitbook.io/docs/aircore/configuration/modules/announcements.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
