aboutsummaryrefslogtreecommitdiff
path: root/adi_change.md
blob: 5338113f21028ba3c638719505a1e7b986ec0830 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
# Changes Made to SVC Intercom Plugin

## Overview
Implemented a comprehensive speaker system with **dual broadcast modes** for the intercom plugin:
- **Global broadcasts**: Everyone in the world hears equally (original behavior)
- **Speaker broadcasts**: Positional audio from defined speaker locations with limited range

This allows admins to choose between world-wide announcements or realistic, location-based PA systems.

---

## New Files Created

### 1. `src/main/java/eu/projnull/spelis/svci/voice/Speaker.java`
**Purpose:** Data model representing a virtual speaker in the world

**Features:**
- Stores speaker location (world, x, y, z coordinates)
- Configurable broadcast range (1-1000 blocks)
- Named speakers for easy management
- Distance calculation to check if players are in range
- Helper method to get Bukkit Location object
- Thread-safe design

---

### 2. `src/main/java/eu/projnull/spelis/svci/voice/SpeakerManager.java`
**Purpose:** Singleton manager for speaker storage and persistence

**Features:**
- Manages all speakers across all worlds using ConcurrentHashMap
- JSON-based persistence (saves to `plugins/SVCIntercom/speakers.json`)
- Add/remove/list speakers by world
- Find speakers within range of a location
- Thread-safe operations
- Automatic save on modifications
- Automatic load on plugin initialization
- Uses Gson for serialization

---

### 3. `src/main/java/eu/projnull/spelis/svci/commands/handlers/SpeakerCommand.java`
**Purpose:** Command handler for managing speakers with flexible coordinate options

**Commands Implemented:**
- `/intercom speaker add <name> <range>` - Add speaker at player's current location (simplest)
- `/intercom speaker add <name> <range> <world>` - Add speaker using player's X/Y/Z in different world
- `/intercom speaker add <name> <world> <x> <y> <z> <range>` - Add speaker at specific coordinates (full control)
- `/intercom speaker remove <world> <name>` - Remove a speaker
- `/intercom speaker list [world]` - List all speakers (defaults to player's world)

**Features:**
- **Coordinates are truly optional** - 3 different ways to add speakers
- Tab completion for world names and speaker names
- Permission checks (`svcintercom.speaker.add`, `svcintercom.speaker.remove`, `svcintercom.speaker.list`)
- Validation for duplicate names and world existence
- Range validation (1.0 to 1000.0 blocks)
- Clear error messages and feedback

---

### 4. `gradlew`
**Purpose:** Gradle wrapper script for building the project
- Standard Gradle wrapper shell script for Unix-based systems
- Made executable for building the project without system Gradle

---

## Modified Files

### 1. `src/main/java/eu/projnull/spelis/svci/voice/BroadcasterState.java`
**Major Changes:**
- Added `BroadcastMode` enum with two values:
  - `GLOBAL` - Everyone hears equally, speakers ignored
  - `SPEAKER` - Only audible near speakers with positional audio
- Updated `Broadcaster` constructor to require a `mode` parameter
- Added `getMode()` getter method
- Mode is now stored alongside broadcast type and validated on creation

**Why:** Separates global broadcasts from speaker-based broadcasts, giving admins full control

---

### 2. `src/main/java/eu/projnull/spelis/svci/commands/handlers/LiveCommand.java`
**Major Rewrite:**
- Added optional `mode` parameter: `/intercom live <player> <world> <duration> [mode]`
- Mode can be `global` or `speaker`
- **Auto-detection**: If mode not specified, uses speaker mode if speakers exist, otherwise global
- Refactored to use helper method `executeLiveBroadcast()` for cleaner code
- Added import for `SpeakerManager` for mode detection
- Warning if speaker mode selected but no speakers exist
- Shows mode in success message: `(global)` or `(speaker)`

**Usage Examples:**
- `/intercom live Player world 60` - Auto-detect
- `/intercom live Player world 60 global` - Force global
- `/intercom live Player world 60 speaker` - Force speaker mode

---

### 3. `src/main/java/eu/projnull/spelis/svci/commands/handlers/FileCommand.java`
**Major Rewrite:**
- Added optional `mode` parameter: `/intercom file <filename> <world> [mode]`
- Mode can be `global` or `speaker`
- **Auto-detection**: If mode not specified, uses speaker mode if speakers exist, otherwise global
- Refactored to use helper method `executeFileBroadcast()` for cleaner code
- **Global mode**: Creates static audio channels for each player (everyone hears equally)
- **Speaker mode**: Creates locational audio channels at each speaker position
- Warning if speaker mode selected but no speakers exist
- Shows mode and speaker count in success message

**Behavior:**
- Global: Uses `createStaticAudioChannel()` - no positional audio
- Speaker: Uses `createLocationalAudioChannel()` with `setDistance()` for each speaker

---

### 4. `src/main/java/eu/projnull/spelis/svci/voice/VoicePlugin.java`
**Major Changes:**
- Modified `onMicPacket()` to respect broadcast mode
- **Global mode path**: Uses static sound packets, everyone hears equally (ignores speakers)
- **Speaker mode path**: 
  - Checks for speakers in the world
  - Finds nearest speaker to each listener
  - Sends locational sound packets from speaker position
  - Players only hear if within range of a speaker
- Removed auto-fallback - now strictly follows the configured mode
- Better separation of concerns between modes

**Key Logic:**
```java
if (mode == GLOBAL) {
    // Send static packets to all players
} else {
    // Find nearest speaker per listener
    // Send locational packets from speaker position
}
```

---

### 5. `src/main/java/eu/projnull/spelis/svci/commands/IntercomCommand.java`
**Changes Made:**
- Added `SpeakerCommand` to the list of registered handlers
- New line: `registerHandler(new SpeakerCommand());`

---

### 6. `src/main/java/eu/projnull/spelis/svci/Intercom.java`
**Changes Made:**
- Added import for `SpeakerManager`
- Modified `onEnable()` method to initialize the speaker system
- Added: `SpeakerManager.inst().initialize(this.getDataFolder());`
- This runs before everything else to load saved speakers from disk

---

### 7. `build.gradle.kts`
**Changes Made:**
- Added Gson dependency for JSON serialization: `implementation("com.google.code.gson:gson:2.10.1")`
- Required for saving/loading speaker configuration to disk

---

### 8. `README.md`
**Major Update:**
- Completely rewritten with comprehensive documentation
- Added "Broadcast Modes Explained" section with detailed behavior
- Expanded command documentation with examples
- Added auto-detection explanation
- Added permissions list
- Added setup example with real-world scenarios
- Clarified all three ways to add speakers

---

## Key Improvements from Previous Version

### 1. **Separated Global and Speaker Broadcasts**
- **Before**: Speakers would override behavior for entire world (all-or-nothing)
- **After**: Choose mode per broadcast - use global for world announcements, speaker for localized PA

### 2. **Truly Optional Coordinates**
- **Before**: Two options - full coords or player location
- **After**: Three flexible options:
  1. Just name + range (uses player's location)
  2. Name + range + world (uses player's XYZ in different world)
  3. Full specification with all coordinates

### 3. **Better Command Structure**
- Optional mode parameters with auto-detection
- Tab completion for modes
- Clearer command syntax
- More helpful error messages

### 4. **Improved Logic**
- No more auto-fallback confusion
- Explicit mode selection
- Warning system for invalid configurations
- Cleaner code with helper methods

---

## Technical Details

### Broadcast Mode Logic

#### Global Mode:
1. Broadcast is created with `BroadcastMode.GLOBAL`
2. VoicePlugin/FileCommand checks the mode
3. For live: Sends static sound packets to all players
4. For file: Creates static audio channels for each player
5. **Speakers are completely ignored** - audio is non-positional

#### Speaker Mode:
1. Broadcast is created with `BroadcastMode.SPEAKER`
2. VoicePlugin/FileCommand checks the mode
3. Retrieves speakers from SpeakerManager
4. If no speakers exist, no audio is heard (with warning)
5. For live: Finds nearest speaker per listener, sends locational packets
6. For file: Creates locational audio channels at each speaker position
7. **Only players near speakers hear the audio**

#### Auto-Detection:
```java
boolean hasSpeakers = !SpeakerManager.inst().getSpeakers(worldId).isEmpty();
mode = hasSpeakers ? SPEAKER : GLOBAL;
```

### Data Persistence

- Speakers saved to `plugins/SVCIntercom/speakers.json`
- Format: Array of speaker objects with worldId, coordinates, range, and name
- Uses Gson for clean JSON serialization
- Automatically loaded on plugin enable
- Automatically saved after any speaker modification
- Thread-safe operations with ConcurrentHashMap

### Permission Nodes

**Existing:**
- `svcintercom.broadcast` - Base permission
- `svcintercom.broadcast.start` - Start broadcasts

**New:**
- `svcintercom.speaker` - Base permission for speaker commands
- `svcintercom.speaker.add` - Permission to add speakers
- `svcintercom.speaker.remove` - Permission to remove speakers
- `svcintercom.speaker.list` - Permission to list speakers

---

## Summary of Changes

**Files Created:** 4
- Speaker.java (data model)
- SpeakerManager.java (persistence & management)
- SpeakerCommand.java (command handlers with 3 flexible add options)
- gradlew (build script)

**Files Modified:** 8
- BroadcasterState.java (added BroadcastMode enum)
- LiveCommand.java (added mode selection with auto-detect)
- FileCommand.java (added mode selection with auto-detect)
- VoicePlugin.java (respects broadcast mode, no fallback)
- IntercomCommand.java (register speaker commands)
- Intercom.java (initialize speaker system)
- build.gradle.kts (add Gson dependency)
- README.md (comprehensive documentation rewrite)

**Total Lines Added:** ~900+

**Key Features:**
1. ✅ Dual broadcast modes (Global vs Speaker)
2. ✅ Truly optional coordinates (3 ways to add speakers)
3. ✅ Auto-detection with explicit mode override
4. ✅ Better separation of concerns
5. ✅ Comprehensive documentation
6. ✅ Warning system for invalid configurations
7. ✅ Persistent speaker storage
8. ✅ Thread-safe operations