Skip to content

Commit c8d9954

Browse files
authored
Merge pull request #465 from Mindgamesnl/feature/speaker-api
2 parents 3fc8135 + 5e25a28 commit c8d9954

File tree

18 files changed

+209
-42
lines changed

18 files changed

+209
-42
lines changed

.tool-versions

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
java adoptopenjdk-8.0.332+9
1+
java openjdk-21

api/src/main/java/com/craftmend/openaudiomc/api/WorldApi.java

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package com.craftmend.openaudiomc.api;
22

3-
import com.craftmend.openaudiomc.api.exceptions.InvalidRegionException;
4-
import com.craftmend.openaudiomc.api.exceptions.InvalidThreadException;
5-
import com.craftmend.openaudiomc.api.exceptions.UnknownWorldException;
3+
import com.craftmend.openaudiomc.api.exceptions.*;
4+
import com.craftmend.openaudiomc.api.media.Media;
65
import com.craftmend.openaudiomc.api.regions.AudioRegion;
76
import com.craftmend.openaudiomc.api.regions.RegionMediaOptions;
87
import com.craftmend.openaudiomc.api.speakers.BasicSpeaker;
8+
import com.craftmend.openaudiomc.api.speakers.ExtraSpeakerOptions;
9+
import com.craftmend.openaudiomc.api.speakers.SpeakerType;
910
import org.jetbrains.annotations.NotNull;
1011
import org.jetbrains.annotations.Nullable;
1112

@@ -54,6 +55,45 @@ static WorldApi getInstance() {
5455
@Nullable
5556
BasicSpeaker getSpeakerAt(int x, int y, int z, @NotNull String world);
5657

58+
/**
59+
* Register a virtual speaker at a location.
60+
* This is a location that will play sound as if there's a speaker there, but there isn't.
61+
*
62+
* @param x x
63+
* @param y y
64+
* @param z z
65+
* @param world world
66+
* @param media The media source
67+
* @param speakerType speaker type
68+
* @param radius radius
69+
* @param extraOptions extra options (redstone requirement, loop, etc)
70+
*
71+
* @throws InvalidThreadException if called from the main thread.
72+
* This is to prevent blocking the main thread with the underlying Sqlite database
73+
* @throws InvalidLocationException if the location is not valid (this location is already occupied by a real or virtual speaker)
74+
* @since 6.10.7
75+
*/
76+
void registerVirtualSpeaker(
77+
int x,
78+
int y,
79+
int z,
80+
@NotNull String world,
81+
@NotNull String media,
82+
SpeakerType speakerType,
83+
int radius,
84+
ExtraSpeakerOptions... extraOptions
85+
) throws InvalidThreadException, InvalidLocationException;
86+
87+
/**
88+
* Unregister a virtual speaker (which has been registered by the api)
89+
*
90+
* @param speaker speaker
91+
* @throws InvalidSpeakerException if the speaker is not valid (already unregistered, or not registered by the api)
92+
* @throws InvalidThreadException if called from the main thread.
93+
* @since 6.10.7
94+
*/
95+
void unregisterVirtualSpeaker(@NotNull BasicSpeaker speaker) throws InvalidSpeakerException, InvalidThreadException;
96+
5797
/**
5898
* Register a region in a world.
5999
* Important:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.craftmend.openaudiomc.api.exceptions;
2+
3+
/**
4+
* Thrown when a given location is not valid for a certain operation
5+
* (something is already there, or the location is not valid)
6+
*/
7+
public class InvalidLocationException extends RuntimeException {
8+
public InvalidLocationException(String message) {
9+
super(message);
10+
}
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.craftmend.openaudiomc.api.exceptions;
2+
3+
/**
4+
* Thrown when a given speaker is not valid for a certain operation
5+
* (when its null, or not placed/managed by the API initially)
6+
*/
7+
public class InvalidSpeakerException extends RuntimeException {
8+
public InvalidSpeakerException(String message) {
9+
super(message);
10+
}
11+
}

api/src/main/java/com/craftmend/openaudiomc/api/exceptions/InvalidThreadException.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,8 @@ public InvalidThreadException() {
99
super("This method can only be called from the main thread");
1010
}
1111

12+
public InvalidThreadException(String message) {
13+
super(message);
14+
}
15+
1216
}

api/src/main/java/com/craftmend/openaudiomc/api/speakers/BasicSpeaker.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,11 @@ public interface BasicSpeaker {
5959
*/
6060
boolean isRedstonePowered();
6161

62+
/**
63+
* If this speaker is a virtual speaker (managed by the API)
64+
* @return is virtual
65+
*/
66+
boolean isVirtual();
67+
68+
void setVirtual(boolean value);
6269
}

plugin/src/main/bash/data.bin

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
BUILD_NUM="1502"
1+
BUILD_NUM="1505"

plugin/src/main/java/com/craftmend/openaudiomc/generic/api/implementaions/WorldApiImpl.java

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
import com.craftmend.openaudiomc.OpenAudioMc;
44
import com.craftmend.openaudiomc.api.WorldApi;
5-
import com.craftmend.openaudiomc.api.exceptions.InvalidRegionException;
6-
import com.craftmend.openaudiomc.api.exceptions.InvalidThreadException;
7-
import com.craftmend.openaudiomc.api.exceptions.UnknownWorldException;
5+
import com.craftmend.openaudiomc.api.exceptions.*;
86
import com.craftmend.openaudiomc.api.media.Media;
97
import com.craftmend.openaudiomc.api.regions.AudioRegion;
108
import com.craftmend.openaudiomc.api.regions.RegionMediaOptions;
119
import com.craftmend.openaudiomc.api.speakers.BasicSpeaker;
10+
import com.craftmend.openaudiomc.api.speakers.ExtraSpeakerOptions;
11+
import com.craftmend.openaudiomc.api.speakers.SpeakerType;
1212
import com.craftmend.openaudiomc.generic.database.DatabaseService;
1313
import com.craftmend.openaudiomc.generic.platform.Platform;
1414
import com.craftmend.openaudiomc.spigot.OpenAudioMcSpigot;
@@ -19,17 +19,15 @@
1919
import com.craftmend.openaudiomc.spigot.modules.regions.registry.WorldRegionManager;
2020
import com.craftmend.openaudiomc.spigot.modules.speakers.SpeakerService;
2121
import com.craftmend.openaudiomc.spigot.modules.speakers.objects.MappedLocation;
22+
import com.craftmend.openaudiomc.spigot.modules.speakers.objects.Speaker;
2223
import lombok.AllArgsConstructor;
2324
import org.bukkit.Bukkit;
2425
import org.bukkit.ChatColor;
2526
import org.bukkit.Location;
2627
import org.jetbrains.annotations.NotNull;
2728
import org.jetbrains.annotations.Nullable;
2829

29-
import java.util.ArrayList;
30-
import java.util.Collection;
31-
import java.util.List;
32-
import java.util.Objects;
30+
import java.util.*;
3331

3432
public class WorldApiImpl implements WorldApi {
3533

@@ -64,6 +62,76 @@ public BasicSpeaker getSpeakerAt(int x, int y, int z, @NotNull String world) {
6462
return OpenAudioMc.getService(SpeakerService.class).getSpeaker(new MappedLocation(x, y, z, world));
6563
}
6664

65+
@Override
66+
public void registerVirtualSpeaker(int x, int y, int z, @NotNull String world, @NotNull String mediaSource, SpeakerType type, int radius, ExtraSpeakerOptions... options) throws InvalidThreadException, InvalidLocationException {
67+
Objects.requireNonNull(world, "World cannot be null");
68+
Objects.requireNonNull(mediaSource, "Media source cannot be null");
69+
70+
if (Bukkit.isPrimaryThread()) {
71+
throw new InvalidThreadException("The register method should not be called from the main thread");
72+
}
73+
74+
if (Bukkit.getWorld(world) == null) {
75+
throw new InvalidLocationException("World " + world + " does not exist");
76+
}
77+
78+
UUID id = UUID.randomUUID();
79+
MappedLocation location = new MappedLocation(
80+
x, y, z, world
81+
);
82+
83+
// check if there is already a speaker at this location
84+
if (getSpeakerAt(x, y, z, world) != null) {
85+
throw new InvalidLocationException("There is already a speaker at this location");
86+
}
87+
88+
// make the options a set
89+
EnumSet<ExtraSpeakerOptions> optionSet = EnumSet.noneOf(ExtraSpeakerOptions.class);
90+
Collections.addAll(optionSet, options);
91+
92+
// init speaker
93+
Speaker speaker = new Speaker(
94+
mediaSource,
95+
id,
96+
radius,
97+
location,
98+
type,
99+
optionSet
100+
);
101+
102+
speaker.setVirtual(true);
103+
104+
OpenAudioMc.getService(SpeakerService.class).registerSpeaker(speaker);
105+
106+
// save to the database
107+
OpenAudioMc.getService(DatabaseService.class)
108+
.getRepository(Speaker.class)
109+
.save(speaker);
110+
}
111+
112+
@Override
113+
public void unregisterVirtualSpeaker(@NotNull BasicSpeaker speaker) throws InvalidSpeakerException, InvalidThreadException {
114+
Objects.requireNonNull(speaker, "Speaker cannot be null");
115+
116+
if (!speaker.isVirtual()) {
117+
throw new InvalidSpeakerException("Speaker is not virtual, only speakers managed by the API can be unregistered");
118+
}
119+
120+
if (Bukkit.isPrimaryThread()) {
121+
throw new InvalidThreadException("The unregister method should not be called from the main thread");
122+
}
123+
124+
// is this speaker actually here?
125+
if (getSpeakerAt(speaker.getLocation().getX(), speaker.getLocation().getY(), speaker.getLocation().getZ(), speaker.getLocation().getWorld()) == null) {
126+
throw new InvalidSpeakerException("Speaker is not registered");
127+
}
128+
129+
// unlist from service
130+
OpenAudioMc.getService(SpeakerService.class).unlistSpeaker(speaker.getLocation());
131+
// delete from database
132+
OpenAudioMc.getService(DatabaseService.class).getRepository(Speaker.class).delete((Speaker) speaker);
133+
}
134+
67135
@Override
68136
public void registerRegion(String worldName, String regionId, RegionMediaOptions regionMedia) throws InvalidRegionException, InvalidThreadException {
69137
Objects.requireNonNull(worldName, "World name cannot be null");

plugin/src/main/java/com/craftmend/openaudiomc/generic/client/helpers/ClientRtcLocationUpdate.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
@AllArgsConstructor
1616
public class ClientRtcLocationUpdate {
1717

18-
private static final boolean PROCESS_OBSTRUCTIONS = StorageKey.SETTINGS_VC_PROCESS_OBSTRUCTIONS.getBoolean();
18+
// private static final boolean PROCESS_OBSTRUCTIONS = StorageKey.SETTINGS_VC_PROCESS_OBSTRUCTIONS.getBoolean();
1919
private static IRayTracer rayTracer = new DummyTracer();
2020

2121
private String streamKey;
@@ -24,15 +24,15 @@ public class ClientRtcLocationUpdate {
2424

2525
public static ClientRtcLocationUpdate fromClientWithLocation(ClientConnection clientConnection, Location source, Vector3 targetLocation) {
2626
int obstructions = 0;
27-
28-
if (PROCESS_OBSTRUCTIONS) {
29-
// check line-of-sight
30-
obstructions = rayTracer.obstructionsBetweenLocations(
31-
source,
32-
targetLocation
33-
);
34-
35-
}
27+
//
28+
// if (PROCESS_OBSTRUCTIONS) {
29+
// // check line-of-sight
30+
// obstructions = rayTracer.obstructionsBetweenLocations(
31+
// source,
32+
// targetLocation
33+
// );
34+
//
35+
// }
3636

3737
return new ClientRtcLocationUpdate(
3838
clientConnection.getRtcSessionManager().getStreamKey(),
@@ -48,14 +48,14 @@ public static ClientRtcLocationUpdate fromClient(ClientConnection clientConnecti
4848

4949
int obstructions = 0;
5050

51-
if (PROCESS_OBSTRUCTIONS) {
52-
// check line-of-sight
53-
obstructions = rayTracer.obstructionsBetweenLocations(
54-
player.getLocation(),
55-
originLocation
56-
);
57-
58-
}
51+
// if (PROCESS_OBSTRUCTIONS) {
52+
// // check line-of-sight
53+
// obstructions = rayTracer.obstructionsBetweenLocations(
54+
// player.getLocation(),
55+
// originLocation
56+
// );
57+
//
58+
// }
5959

6060
return new ClientRtcLocationUpdate(
6161
clientConnection.getRtcSessionManager().getStreamKey(),

plugin/src/main/java/com/craftmend/openaudiomc/generic/storage/enums/StorageKey.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public enum StorageKey {
7373
SETTING_VC_ENTERED_MUTED_REGION(false, "messages.voice-disabled-here", StorageLocation.CONFIG_FILE),
7474
SETTING_VC_LEFT_MUTED_REGION(false, "messages.voice-reenabled-here", StorageLocation.CONFIG_FILE),
7575
SETTINGS_VC_ANNOUNCEMENTS(false, "options.voicechat-announcements", StorageLocation.CONFIG_FILE),
76-
SETTINGS_VC_PROCESS_OBSTRUCTIONS(false, "options.voicechat-obstructions", StorageLocation.CONFIG_FILE),
76+
// SETTINGS_VC_PROCESS_OBSTRUCTIONS(false, "options.voicechat-obstructions", StorageLocation.CONFIG_FILE),
7777
SETTINGS_VC_ALLOW_JOIN_DURING_LOAD(false, "options.voicechat-allow-joining-while-loading", StorageLocation.CONFIG_FILE),
7878
SETTINGS_FORCE_OFFLINE_MODE(false, "options.force-offline-mode", StorageLocation.CONFIG_FILE),
7979
SETTINGS_DEFAULT_WORLD_NAME(false, "options.fallback-world-name", StorageLocation.CONFIG_FILE),

plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/speakers/SpeakerService.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.craftmend.openaudiomc.spigot.modules.speakers;
22

33
import com.craftmend.openaudiomc.OpenAudioMc;
4+
import com.craftmend.openaudiomc.api.speakers.Loc;
45
import com.craftmend.openaudiomc.generic.database.DatabaseService;
56
import com.craftmend.openaudiomc.generic.logging.OpenAudioLogger;
67
import com.craftmend.openaudiomc.generic.media.MediaService;
@@ -169,7 +170,10 @@ public SpeakerMedia getMedia(String source) {
169170
return speakerMedia;
170171
}
171172

172-
public void unlistSpeaker(MappedLocation location) {
173+
public void unlistSpeaker(Loc location) {
174+
if (!(location instanceof MappedLocation)) {
175+
throw new IllegalArgumentException("Location is not a MappedLocation");
176+
}
173177
speakerMap.remove(location);
174178
}
175179
}

plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/speakers/objects/MappedLocation.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,17 @@ public static MappedLocation fromBukkit(Location location) {
3939
return new MappedLocation(location.getBlockX(), location.getBlockY(), location.getBlockZ(), location.getWorld().getName());
4040
}
4141

42+
@Override
43+
public boolean equals(Object obj) {
44+
if (obj instanceof MappedLocation) {
45+
MappedLocation other = (MappedLocation) obj;
46+
return other.x == x && other.y == y && other.z == z && other.world.equals(world);
47+
}
48+
return false;
49+
}
50+
51+
public Loc toApiLoc() {
52+
return this;
53+
}
54+
4255
}

plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/speakers/objects/Speaker.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public class Speaker extends DataStore implements BasicSpeaker {
1818

1919
@Column @Getter private String source;
2020
@Column @Getter private UUID speakerId;
21+
@Column(defaultValue = "true")
22+
@Getter private Boolean requiresHealthCheck = true;
2123
@Column @Setter @Getter private Integer radius;
2224

2325
@Column(
@@ -66,4 +68,14 @@ public SpeakerMedia getMedia() {
6668
return OpenAudioMc.getService(SpeakerService.class).getMedia(source);
6769
}
6870

71+
@Override
72+
public boolean isVirtual() {
73+
return !requiresHealthCheck;
74+
}
75+
76+
@Override
77+
public void setVirtual(boolean value) {
78+
this.requiresHealthCheck = !value;
79+
}
80+
6981
}

plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/speakers/tasks/SpeakerGarbageCollection.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@ public void run() {
5757
possiblyFilterLimits(setSize, this.speakerService
5858
.getSpeakerMap()
5959
.values().stream()
60-
.filter(speaker -> !speaker.getValidated())
61-
.skip(fractionStart)
60+
.filter(Speaker::getRequiresHealthCheck)
61+
.filter(speaker -> !speaker.getValidated())
62+
.skip(fractionStart)
6263
).collect(Collectors.toList())
6364
.forEach(speaker -> {
6465
MappedLocation mappedLocation = speaker.getLocation();

plugin/src/main/resources/config.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,6 @@ options:
239239
# Decides if voicechat messages should go in the hotbar or chat. Setting this to false will default to chat
240240
voicechat-send-messages-in-hotbar: true
241241

242-
# Toggles voicechat obstruction detection. This can get quite resource intensive so it's off by default, but this muffles voices when
243-
# One or more blocks are blocking the players line-of-sight
244-
voicechat-obstructions: false
245-
246242
# Automatically request a free voicechat license when the server starts
247243
voicechat-autoclaim-on-start: true
248244

plugin/src/main/resources/data.bin

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
BUILD_NUM="1502"
1+
BUILD_NUM="1505"
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
BUILD_VERSION="1502"
2-
BUILD_COMMIT="c1b8d01b0ffb085c03a6af17a91695c43f8a1ce8"
1+
BUILD_VERSION="1505"
2+
BUILD_COMMIT="f0ec41730d7590829944fb97c1499d1064450fab"
33
BUILD_AUTHOR="Mats"

plugin/src/main/resources/plugin.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ version: 6.10.6
33
softdepend: [WorldGuard, Train_Carts, LiteBans, Essentials, PlaceholderAPI]
44
main: com.craftmend.openaudiomc.spigot.OpenAudioMcSpigot
55
api-version: 1.13
6-
authors: [Mindgamesnl]
6+
authors: [Mindgamesnl, ToetMats]
77
description: "OpenAudioMc: Proximity voice chat & audio plugin for Minecraft, no mods needed. Supports Bungeecord, Velocity, Spigot & more."
88
website: https://openaudiomc.net/
99
commands:

0 commit comments

Comments
 (0)