# MPP - Auto Megaphone Package V1.5.1 - Documentation

Automatic **Megaphone** control for your experience: switch the Sansar Megaphone (the voice mode heard by everyone in the experience) on or off for your visitors when they arrive, when they enter or leave a zone, when they touch an object, or when someone presses a button. Two scripts delivered as one asset: the **Policy**, which decides who and when, and optional **Zones**, trigger volumes that ask the Policy for a change.

This package is **standalone** - it does not require any other MPP script to function. It works with **MPP - Action Button** for buttons (Megaphone on/off for yourself, or for everyone).

**New in V1.5:** the latest request always wins, visitor by visitor: a request that arrives during the cooldown is kept and applied when the cooldown ends, and requests of the same instant (a visitor stepping back and forth on a zone edge) count as one, so no more bursts of public messages. The state remembered for a visitor follows Sansar's answers, so a refused change never leaves a wrong state. "... is no longer in Megaphone mode" is only announced for a visitor the Policy had turned on. All On / All Off send one summary instead of a copy per visitor. The lists accept avatar handles as well as UUIDs. VR hands are ignored by zones. Warnings in the script console for inconsistent settings. Settings grouped by category. V1.5.1 renames labels and groups and names the modules "MPP - Auto Megaphone Policy" and "MPP - Auto Megaphone Zone". Your settings are kept when you update: see "Updating from V1.4.4".

---

## What You Get

The asset holds two script modules. When you add the script to an object, Sansar asks which module to use:

| Module | Put it on | Role |
|---|---|---|
| **MPP - Auto Megaphone Policy** | One object of the scene (any object, even a hidden one) | The controller: applies the rules (who is affected, cooldown, messages) and makes every Megaphone change. **Always needed.** |
| **MPP - Auto Megaphone Zone** | Trigger volumes, as many as you like | Asks the Policy to switch Megaphone on or off when an avatar enters or leaves the volume. Optional. |

Zones never change Megaphone themselves: they send a request to the Policy, which checks it against its rules. One Policy per scene is enough for any number of zones.

---

## Quick Start

**A - Megaphone for everyone as soon as they arrive.** Add the Policy module to any object. The defaults do it: `Auto Triggers/On Join Action` 1 (On), `Targets/Target Mode` 0 (everyone), a public message "Name is now in Megaphone mode." Nothing else to set.

**B - Megaphone only on a stage.** On the Policy, set `Auto Triggers/On Join Action` to 2 (Off) so everyone starts silent. Make a trigger volume over the stage (a box with a RigidBody set to Trigger Volume), add the Zone module to it, keep `Zone/On Enter Action` 1 (On) and `Zone/On Exit Action` 2 (Off). Whoever steps on the stage is heard everywhere; whoever steps off is not.

**C - A silent room.** Keep the Policy defaults (Megaphone on at arrival) and put a Zone on the room with `On Enter Action` 2 (Off) and `On Exit Action` 1 (On).

The rest of this guide details every option.

---

## How It Works

Every Megaphone change, whatever asks for it, goes through the same gate in the Policy, **visitor by visitor**:

1. **Enabled**: with `Activation/Enabled` Off, the Policy changes nothing at all.
2. **Target Mode**: is this visitor affected? (`Targets/Target Mode`, with the Whitelist or the Blacklist).
3. **Once per session**: for the join and the collision only, if `Auto Triggers/Once Per Avatar Per Session` is On and this visitor was already served.
4. **Already in that state**: a request for the state the visitor already has does nothing and starts no cooldown.
5. **Queue**: the request waits a tenth of a second, or until the visitor's cooldown ends, then the **latest** request received for that visitor is applied. Earlier ones are replaced, never lost.
6. **Change and messages**: the Megaphone is switched, then the private and public messages of `Messages/Message Mode` are sent.

If Sansar refuses the change (too many changes at once, visitor gone), the state remembered for the visitor stays right, the next request works, and `Messages/Notify On Failure` can tell the visitor.

In the Build panel the Policy settings are grouped by category: `Activation/`, `Targets/`, `Auto Triggers/`, `Messages/`, `Events/` and `Debug/`. The Zone has `Zone/` and `Debug/`.

---

## Behavior Mode

`Activation/Behavior Mode (0-2)` chooses which sources the Policy listens to:

| Mode | Auto Triggers (join, collision, leave) | Zones |
|---|---|---|
| **0** - PolicyOnly | Yes | Ignored |
| **1** - ZoneOnly | Ignored | Yes |
| **2** - Hybrid (default) | Yes | Yes |

Script Events (buttons) work in every mode. `Activation/Enabled` Off stops everything, zones and buttons included.

---

## Targets - Who Is Affected

`Targets/Target Mode (0-6)` says which visitors the Policy may switch. It is not an access control on the zones or buttons: a visitor who is not targeted is simply left alone by every source.

| Mode | Who is affected |
|---|---|
| **0** - Everyone (default) | All visitors, the scene owner included |
| **1** - Everyone except the owner | All visitors but the scene owner |
| **2** - Owner only | The scene owner only |
| **3** - Whitelist only | The avatars of `Targets/Whitelist` |
| **4** - Owner and Whitelist | The scene owner and the avatars of `Targets/Whitelist` |
| **5** - Everyone except the Blacklist | All visitors but the avatars of `Targets/Blacklist` |
| **6** - Owner and everyone not blacklisted | The scene owner (even if listed) and all visitors but the avatars of `Targets/Blacklist` |

**Lists.** `Targets/Whitelist` and `Targets/Blacklist` take avatar **handles** or avatar **UUIDs**, separated by commas or semicolons. Handles are not case sensitive and a leading `@` is ignored. Display names are not accepted (Sansar does not guarantee them unique). A list of V1.4.4 with UUIDs separated by spaces still works: every UUID of such an entry is read, the other words are ignored with a warning. Example: `@morgane, friend-handle; 3f2c1a9e-0000-4c1e-9a55-1234567890ab`.

Tip: turn `Debug/Debug Logging` On on the Policy: every request shows the visitor's handle and UUID in the script console, ready to paste.

Mode 3 or 4 with an empty Whitelist gets a warning at start (nobody, or only the owner, is affected).

---

## Auto Triggers

The Policy can act on its own, without zones (Behavior Mode 0 or 2):

| Setting | Default | What it does |
|---|---|---|
| Auto Triggers/On Join Action (0-2) | 1 (On) | When a visitor enters the scene: 0 nothing, 1 Megaphone on, 2 Megaphone off |
| Auto Triggers/On Collision Action (0-2) | 0 (None) | When a visitor touches the **Policy object** itself: 0 nothing, 1 on, 2 off. The object needs a RigidBody (a trigger volume reacts on entry, a normal collider on contact). Most scenes use Zones instead |
| Auto Triggers/On Leave Action (0-2) | 0 (None) | When a visitor leaves the scene. Kept for compatibility: the visitor is usually already gone when Sansar reports the departure, so it rarely does anything, and it sends no message |
| Auto Triggers/Once Per Avatar Per Session | On | The join and the collision act at most **once per visitor and per visit**, and they share that one time: a visitor switched on at arrival is not switched again by the collision. Zones and buttons are never limited by this |

With `Once Per Avatar Per Session` On, `On Join Action` and `On Collision Action` both active get a warning at start: the join uses up the only application.

---

## Zones

Put the **Zone** module on a trigger volume: an object with a RigidBody set to **Trigger Volume** (a simple box is enough). Each zone has its own settings:

| Setting | Default | What it does |
|---|---|---|
| Zone/Enabled | On | Off = the zone does nothing |
| Zone/Zone Label | "" | A name for this zone, shown in the `{source}` token and the console: `Stage`, `Lobby`, `SilentRoom` |
| Zone/On Enter Action (0-2) | 1 (On) | When an avatar enters the volume: 0 nothing, 1 Megaphone on, 2 Megaphone off |
| Zone/On Exit Action (0-2) | 2 (Off) | When an avatar leaves the volume: 0 nothing, 1 on, 2 off |
| Debug/Debug Logging | Off | Writes each avatar detected and each request sent to the script console |

- A zone needs a **Policy** in the scene, with `Activation/Behavior Mode` 1 or 2 (mode 0 ignores zones).
- Zones only see the avatar's body: VR hands and the desktop grab point are ignored.
- Overlapping zones: the last request received for a visitor wins (see "Cooldown").
- A zone without a RigidBody, or with a RigidBody that is not a trigger volume, writes a warning at start.

---

## Cooldown and Anti-Spam

`Activation/Cooldown Seconds` (default 0, up to 120) is the minimum time between two Megaphone changes of the **same visitor**.

- A request that arrives during the visitor's cooldown is **kept** and applied when the cooldown ends. Several requests during the cooldown: only the **latest** is applied. A visitor who steps on a stage then off it within the cooldown ends up off, with one change at the end of the cooldown.
- Even with `Cooldown Seconds` at 0, the requests of the same instant are grouped: the Policy waits a tenth of a second before applying the latest one. A visitor going back and forth on a zone edge does not produce a burst of messages.
- A request for the state the visitor already has does nothing and starts no cooldown.
- If a change fails, no cooldown starts, and the next request goes through.

---

## Messages

`Messages/Message Mode (0-3)` chooses the feedback sent at each change:

| Mode | Private message to the visitor | Public message to everyone in the experience |
|---|---|---|
| **0** - None | - | - |
| **1** - Private only | Yes | - |
| **2** - Public only (default) | - | Yes |
| **3** - Private and public | Yes | Yes |

- `Messages/Private Message (On)` / `(Off)`: the private texts, default "Megaphone mode has been enabled for you." / "Megaphone mode has been disabled for you."
- `Messages/Public Format (On)` / `(Off)`: the public texts, default "{name} is now in Megaphone mode." / "{name} is no longer in Megaphone mode." They go to **everyone in the experience** (public chat), not only to nearby avatars. Tokens: `{name}` = the visitor's display name, `{state}` = `on` or `off`, `{source}` = what asked for the change: `PolicyJoin`, `PolicyCollision`, `Zone:<label>:enter`, `Zone:<label>:exit`, `ActionButton:self`.
- The **Off** messages are only sent for a visitor this Policy had turned on: a visitor who arrives with `On Join Action` 2 (Off) gets no "no longer in Megaphone mode".
- `Messages/Notify On Failure` (default Off) with `Messages/Failure Private Text`: a private message to the visitor when Sansar refused the change ("Could not change Megaphone mode. Please try again.").
- All On / All Off (see "Script Events") send one **summary** instead of the per-visitor messages: "Requested Megaphone ON for 5 avatar(s).", public in mode 2 or 3, otherwise private to the person who pressed the button.

---

## Script Events (buttons and your own scripts)

With `Events/Enable Script Events` On (default), the Policy listens to four Script Events, meant for **MPP - Action Button** (`Send as Command` On) or any script that sends the same data (an object with a text property `ActivatorAvatarUuid` holding the avatar's UUID):

| Event (default name) | Effect |
|---|---|
| `mpp_megaphone_self_on` (`Events/Self On Event Name`) | Megaphone on for the avatar who pressed the button |
| `mpp_megaphone_self_off` (`Events/Self Off Event Name`) | Megaphone off for that avatar |
| `mpp_megaphone_all_on` (`Events/All On Event Name`) | Megaphone on for every visitor present and targeted |
| `mpp_megaphone_all_off` (`Events/All Off Event Name`) | Megaphone off for every visitor present and targeted |

Self events follow the normal gate (Target Mode, cooldown, messages). They are never limited by `Once Per Avatar Per Session`.

**Who may use All On / All Off**: `Events/Global Event Access Mode (0-2)`:

| Mode | Allowed |
|---|---|
| **0** - Owner only (default) | The scene owner |
| **1** - Owner and Global Event Whitelist | The scene owner and the avatars of `Events/Global Event Whitelist` (handles or UUIDs, same format as the other lists) |
| **2** - Everyone | Anyone who presses the button |

A visitor who is not allowed receives `Events/Global Event Denied Text` in private ("You are not allowed to control Megaphone for everyone."), at most once every 5 seconds; empty = silent. The scene owner is always allowed. Each visitor then goes through the normal gate: one in their cooldown gets the change when it ends. With `Activation/Enabled` Off, All On and All Off do nothing, not even the summary. In mode 2 every visitor can post the public summary at each press: keep the button's own cooldown reasonable, or use mode 0 or 1.

**Buttons.** On an MPP - Action Button: `Send as Command` On and `Command 1` = `mpp_megaphone_self_on`. For a two-state button: `Command Count` 2, `Command 1` = `mpp_megaphone_self_on`, `Command 2` = `mpp_megaphone_self_off`. A master "All Off" button for the owner: `Command 1` = `mpp_megaphone_all_off`, and `Access/Permission Mode` 1 on the button as a second lock.

---

## Editor Properties Reference (26 + 5)

### Policy - Activation
| Property | Type | Default | Description |
|---|---|---|---|
| Activation/Enabled | bool | On | Off = no Megaphone change at all (zones, buttons, auto triggers ignored) |
| Activation/Behavior Mode (0-2) | int | 2 | 0 PolicyOnly (zones ignored), 1 ZoneOnly (auto triggers ignored), 2 Hybrid |
| Activation/Cooldown Seconds | number, 0-120 | 0 | Minimum time between two changes of the same visitor; the latest request waits and wins |

### Policy - Targets
| Property | Type | Default | Description |
|---|---|---|---|
| Targets/Target Mode (0-6) | int | 0 | Who is affected: 0 Everyone, 1 EveryoneExceptOwner, 2 OwnerOnly, 3 WhitelistOnly, 4 OwnerAndWhitelist, 5 EveryoneExceptBlacklist, 6 OwnerAndNotBlacklisted |
| Targets/Whitelist | string | "" | Handles or UUIDs for modes 3 and 4 |
| Targets/Blacklist | string | "" | Handles or UUIDs for modes 5 and 6 |

### Policy - Auto Triggers
| Property | Type | Default | Description |
|---|---|---|---|
| Auto Triggers/On Join Action (0-2) | int | 1 | On arrival: 0 none, 1 on, 2 off |
| Auto Triggers/On Collision Action (0-2) | int | 0 | On contact with the Policy object (RigidBody needed): 0 none, 1 on, 2 off |
| Auto Triggers/On Leave Action (0-2) | int | 0 | On departure, best effort, no message: 0 none, 1 on, 2 off |
| Auto Triggers/Once Per Avatar Per Session | bool | On | Join and collision act at most once per visitor and per visit, shared |

### Policy - Messages
| Property | Type | Default | Description |
|---|---|---|---|
| Messages/Message Mode (0-3) | int | 2 | 0 None, 1 PrivateOnly, 2 PublicOnly, 3 PrivateAndPublic |
| Messages/Private Message (On) | string | "Megaphone mode has been enabled for you." | Private text when switched on |
| Messages/Private Message (Off) | string | "Megaphone mode has been disabled for you." | Private text when switched off (only for a visitor this Policy turned on) |
| Messages/Public Format (On) | string | "{name} is now in Megaphone mode." | Public text when switched on; tokens `{name}` `{state}` `{source}` |
| Messages/Public Format (Off) | string | "{name} is no longer in Megaphone mode." | Public text when switched off (same rule as the private one) |
| Messages/Notify On Failure | bool | Off | Private message when Sansar refuses a change |
| Messages/Failure Private Text | string | "Could not change Megaphone mode. Please try again." | That message |

### Policy - Events
| Property | Type | Default | Description |
|---|---|---|---|
| Events/Enable Script Events | bool | On | Listens to the four events below |
| Events/Self On Event Name | string | "mpp_megaphone_self_on" | Megaphone on for the activating avatar |
| Events/Self Off Event Name | string | "mpp_megaphone_self_off" | Megaphone off for the activating avatar |
| Events/All On Event Name | string | "mpp_megaphone_all_on" | Megaphone on for every present, targeted visitor |
| Events/All Off Event Name | string | "mpp_megaphone_all_off" | Megaphone off for every present, targeted visitor |
| Events/Global Event Access Mode (0-2) | int | 0 | Who may use All On / All Off: 0 owner, 1 owner + Global Event Whitelist, 2 everyone |
| Events/Global Event Whitelist | string | "" | Handles or UUIDs for mode 1 |
| Events/Global Event Denied Text | string | "You are not allowed to control Megaphone for everyone." | Private refusal, at most every 5 s; empty = silent |

### Policy - Debug
| Property | Type | Default | Description |
|---|---|---|---|
| Debug/Debug Logging | bool | Off | Writes the requests, the changes and the refusals to the script console, with the avatar handle and UUID |

### Zone
| Property | Type | Default | Description |
|---|---|---|---|
| Zone/Enabled | bool | On | Off = the zone does nothing |
| Zone/Zone Label | string | "" | Name used in `{source}` and the console |
| Zone/On Enter Action (0-2) | int | 1 | Entering the volume: 0 none, 1 on, 2 off |
| Zone/On Exit Action (0-2) | int | 2 | Leaving the volume: 0 none, 1 on, 2 off |
| Debug/Debug Logging | bool | Off | Writes each avatar detected and each request sent |

---

## Version Notes

| Version | What changed |
|---|---|
| V1.3 | Policy + Zone package with Script Event requests |
| V1.4 | Tri-state actions (None / On / Off), Behavior Mode (PolicyOnly / ZoneOnly / Hybrid) |
| V1.4.1 | Script Events for MPP - Action Button: self on/off, all on/off with an access mode and a whitelist |
| V1.4.4 | Sold until V1.5.1 |
| V1.5.0 | Latest request wins per visitor (kept during the cooldown, grouped within 0.1 s), remembered state following Sansar's answers, "Off" messages only for visitors the Policy turned on, one summary for All On / All Off, handles in the lists, denied message at most every 5 s, VR hands ignored, warnings at start, settings grouped by category |
| **V1.5.1** (this version) | Labels only: groups `Activation/` (was Policy) and `Events/` (was ActionButton), `Enable Script Events`, `Zone/` group; modules named "MPP - Auto Megaphone Policy" and "MPP - Auto Megaphone Zone" without a version number |

### Updating from V1.4.4

- **Your values carry over**: the 26 settings of the Policy and the 5 of the Zone keep their internal names and their values. As with any update, take a screenshot of both panels first, update one Policy and one Zone and check that each object still runs its own module (Policy or Zone) and keeps its values.
- **Labels and groups**: same settings, new names:

| V1.4.4 | V1.5.1 |
|---|---|
| Enabled, Behavior Mode, Cooldown Seconds | Activation/Enabled, Behavior Mode, Cooldown Seconds |
| Target Mode, Whitelist Avatar UUIDs (CSV), Blacklist Avatar UUIDs (CSV) | Targets/Target Mode, Whitelist, Blacklist |
| On Join / On Collision / On Leave Action, Once Per Avatar Per Session (Policy) | Auto Triggers/... |
| Message Mode, Private Message (On/Off), Nearby Format (On/Off), Notify On Failure, Failure Private Text | Messages/... with Public Format (On/Off) |
| Enable ActionButton Events, the four event names, Global Event Access Mode, Global Event Whitelist (CSV), Global Event Denied Text | Events/Enable Script Events, ... |
| Zone: Enabled, Zone Label, On Enter Action, On Exit Action | Zone/... |

- **What behaves differently**: a request during the cooldown is no longer lost (it applies at the end, latest wins); requests of the same instant are grouped (0.1 s) even with `Cooldown Seconds` 0; "no longer in Megaphone mode" is only announced for a visitor the Policy had turned on; All On / All Off send one summary (public in Message Mode 2 or 3, else private to the sender) and no per-visitor copy; the lists accept handles; the denied message for All On / All Off is sent at most every 5 seconds; zones ignore VR hands; warnings at start for inconsistent settings.

---

## Recipes

**A - Megaphone for everyone at arrival.** Policy defaults (`On Join Action` 1). No zone.

**B - Safe default off, stage on (recommended for events).** Policy: `On Join Action` 2. Zone "Stage": `On Enter Action` 1, `On Exit Action` 2.

**C - Silent room.** Policy: `On Join Action` 1. Zone "SilentRoom": `On Enter Action` 2, `On Exit Action` 1 (or 0 to keep the visitor off after leaving).

**D - Event layout with several zones.** Policy: `On Join Action` 2. Zone "Stage": enter 1, exit 2. Zone "Backstage": enter 2, exit 2 (always off).

**E - Zones only.** Policy: `Behavior Mode` 1; the join, the collision and the leave are ignored, the zones do everything.

**F - Buttons.** An MPP - Action Button with `Send as Command` On, `Command Count` 2, `Command 1` = `mpp_megaphone_self_on`, `Command 2` = `mpp_megaphone_self_off`: each visitor toggles their own Megaphone. A second button `mpp_megaphone_all_off` for you, with `Events/Global Event Access Mode` 0.

**G - Staff only.** `Targets/Target Mode` 4 with your staff's handles in `Targets/Whitelist`: only they are ever switched, whatever the zones or buttons do.

---

## Troubleshooting

| Symptom | Check |
|---|---|
| Zones do nothing | A Policy in the scene, with `Activation/Enabled` On and `Behavior Mode` 1 or 2? The zone has a RigidBody set to **Trigger Volume**? The visitor is targeted by `Target Mode`? Turn `Debug/Debug Logging` On on the zone: "Posted request ..." must appear |
| Nobody is switched on at arrival | `Behavior Mode` not 1, `On Join Action` 1, `Target Mode` 0 (or the visitor listed)? With `Once Per Avatar Per Session` On, a visitor already served this visit is not served again |
| The change comes late | Normal with a cooldown: the request waits for the end of the visitor's cooldown, then the latest one applies. A tenth of a second even at 0 |
| Public messages appear for every step on a zone edge | Requests of the same instant are grouped; if a visitor really goes in and out slowly, raise `Cooldown Seconds` (one change at most per cooldown) |
| "All On" does nothing for a visitor | `Global Event Access Mode` 0: only the owner may use it (the visitor gets the Denied Text at most every 5 s). `Activation/Enabled` Off stops All On / All Off entirely |
| A visitor in my Whitelist is not affected | The list needs the **handle** (or UUID), not the display name; `Target Mode` must be 3 or 4. The console shows the handle of each request with Debug Logging On |
| Warnings at start | They name the setting to fix: empty Whitelist with mode 3 or 4, join and collision sharing Once Per Avatar Per Session, collision without RigidBody, list entry with words ignored |
| Settings look different after updating the script | Only the labels changed; the values stay (see "Updating from V1.4.4"). Check that each object still runs its module (Policy or Zone) |

---

## Limits

- `On Leave Action` rarely does anything: Sansar reports the departure when the avatar is already gone.
- Public messages go to everyone in the experience, not only nearby.
- All On / All Off in `Global Event Access Mode` 2 let any visitor post the public summary at each press; use mode 0 or 1, or a button cooldown.
- The Megaphone itself is a Sansar feature: the script only switches it, it does not change who hears whom otherwise.

---

## Related MPP Items

| Item | What it adds |
|---|---|
| **Action Button Script** (V1.7.1) | Buttons for `mpp_megaphone_self_on` / `_off` and `mpp_megaphone_all_on` / `_off`, with their own access control and cooldown. Store: https://www.sansar.com/store/listings/3e1a3546-6c79-4527-bc1e-78d02648d19e/action-button-script |
| **Commands Help On Chat Script** (V1.5.2) | A help text for your visitors, and arrival events that other scripts can use. Store: https://www.sansar.com/store/listings/fea2df6b-21ce-48eb-94fc-4b7a7aad2777/commands-help-on-chat-script |

---

*MPP - My Pretty Pixels. Auto Megaphone Package V1.5.1 (modules `MPP - Auto Megaphone Policy` and `MPP - Auto Megaphone Zone`). Store: https://www.sansar.com/store/listings/6d2981c1-d9a4-4b49-b8ff-0f643aae3ed3/automegaphone-package-script*
