diff --git a/client/public/metadata.json b/client/public/metadata.json index f7a2c2da08..bce3ad07cf 100644 --- a/client/public/metadata.json +++ b/client/public/metadata.json @@ -1 +1 @@ -{"buildMajor":1,"buildMinor":125,"buildRevision":250,"buildTag":"dev","buildDate":"Thu Jun 13 2024","build":"1.125.250 dev"} \ No newline at end of file +{"buildMajor":1,"buildMinor":125,"buildRevision":251,"buildTag":"dev","buildDate":"Tue Jul 09 2024","build":"1.125.251 dev"} \ No newline at end of file diff --git a/client/src/client/services/media/objects/Mixer.jsx b/client/src/client/services/media/objects/Mixer.jsx index b7198b1dc1..e811a5b7e5 100644 --- a/client/src/client/services/media/objects/Mixer.jsx +++ b/client/src/client/services/media/objects/Mixer.jsx @@ -26,7 +26,7 @@ export class Mixer { }, 250); } - tick() { + tick(forceInstant = false) { this.channels.forEach((channel) => { channel.tick(); }); @@ -57,7 +57,7 @@ export class Mixer { } }); - const fade = channel.getPrefferedFadeTime() > 5; + const fade = channel.getPrefferedFadeTime() > 5 && !forceInstant; if (score >= 1 && !channel.mutedByScore) { channel.mutedByScore = true; diff --git a/client/src/client/services/socket/handlers/HandleCreateMedia.jsx b/client/src/client/services/socket/handlers/HandleCreateMedia.jsx index 0adc241e11..13c3ade7bb 100644 --- a/client/src/client/services/socket/handlers/HandleCreateMedia.jsx +++ b/client/src/client/services/socket/handlers/HandleCreateMedia.jsx @@ -43,13 +43,11 @@ export async function handleCreateMedia(data) { if (muteRegions) { debugLog('Incrementing region inhibit'); MediaManager.mixer.incrementInhibitor('REGION'); - MediaManager.mixer.tick(); } if (muteSpeakers) { debugLog('Incrementing speaker inhibit'); MediaManager.mixer.incrementInhibitor('SPEAKER'); - MediaManager.mixer.tick(); } MediaManager.mixer.whenFinished(id, () => { @@ -67,9 +65,12 @@ export async function handleCreateMedia(data) { createdChannel.setTag(flag); + MediaManager.mixer.tick(); + // load file and play await createdMedia.load(source); createdChannel.setChannelVolume(0); + createdChannel.originalVolume = volume; createdMedia.setLooping(looping); createdMedia.setStartAt(startAt); // convert distance @@ -83,7 +84,13 @@ export async function handleCreateMedia(data) { } else { // default sound, just play createdChannel.setTag('DEFAULT'); + createdMedia.whenInitialized(() => { + // are we not already nicked from the start? + if (createdChannel.mutedByScore) { + return; + } + if (fadeTime === 0) { createdChannel.setChannelVolume(volume); createdChannel.updateFromMasterVolume(); diff --git a/client/src/client/util/AudioSourceProcessor.jsx b/client/src/client/util/AudioSourceProcessor.jsx index e3c3143ce9..175bf6d806 100644 --- a/client/src/client/util/AudioSourceProcessor.jsx +++ b/client/src/client/util/AudioSourceProcessor.jsx @@ -72,11 +72,6 @@ export class AudioSourceProcessor { this.isYoutube = true; } - // strip old endpoint - if (source.includes('https://weathered-dust-0281.craftmend.workers.dev/')) { - source = source.replace('https://weathered-dust-0281.craftmend.workers.dev/', ''); - } - // handle soundcloud if (source.includes('soundcloud.com')) { // update now playing too diff --git a/client/src/metadata.json b/client/src/metadata.json index f7a2c2da08..bce3ad07cf 100644 --- a/client/src/metadata.json +++ b/client/src/metadata.json @@ -1 +1 @@ -{"buildMajor":1,"buildMinor":125,"buildRevision":250,"buildTag":"dev","buildDate":"Thu Jun 13 2024","build":"1.125.250 dev"} \ No newline at end of file +{"buildMajor":1,"buildMinor":125,"buildRevision":251,"buildTag":"dev","buildDate":"Tue Jul 09 2024","build":"1.125.251 dev"} \ No newline at end of file diff --git a/dev-resources/vistas-test/plugins/OpenAudioMc/config.yml b/dev-resources/vistas-test/plugins/OpenAudioMc/config.yml index de6236e126..c541189c34 100644 --- a/dev-resources/vistas-test/plugins/OpenAudioMc/config.yml +++ b/dev-resources/vistas-test/plugins/OpenAudioMc/config.yml @@ -1,21 +1,29 @@ messages: # The message a client gets when they are not connected but a sound got triggered. this can be disabled under settings - suggest-connection: '&7&oYou are currently missing out on some sounds! connect with the audio client via /audio' + suggest-connection: '&7&oYou are currently missing out on some sounds! connect with + the audio client via /audio' # The message a client receives when a URL is being prepared for them to open the web client preparing-session: '&7&oGenerating audio session..' # The message the client gets when executing /audio of joins (if send-on-join is enabled) - click-to-connect: '\n&b&lClick &ahere&b&l to open the Web Client!\n&3This lets you use &dProximity Voice Chat&3 and in-game &daudio&3!\n ' + click-to-connect: '\n&b&lClick &ahere&b&l to open the Web Client!\n&3This lets you + use &dProximity Voice Chat&3 and in-game &daudio&3!\n ' + # an alternate version of this message for bedrock users + connect-prompt-bedrock: \n&b&lThis server supports &aProximity Voice Chat&b&!\nGo + to {domain} in your web-browser to get started.\n # The message a player receives when a session error occurs - session-error: '&cAn error occurred while generating your audio session. please report the problem and try again later.' + session-error: '&cAn error occurred while generating your audio session. please + report the problem and try again later.' # A hover message for the click-to-connect message, only appears right before clicking when you mouse over it - click-to-connect-hover: '&6Minecraft will prompt you to open the web client when you click this message' + click-to-connect-hover: '&6Minecraft will prompt you to open the web client when + you click this message' # The message the client gets when their audio link has expired - click-link-expired: '&3Your link to the audio client has expired. Use &b/audio&3 to request a new one.' + click-link-expired: '&3Your link to the audio client has expired. Use &b/audio&3 + to request a new one.' # The message a client gets when their web-client has been opened client-opened: '&2&oYou are now connected with the audio client!' @@ -27,7 +35,8 @@ messages: client-already-connected: '&cYou are already connected to the web client' # Prints the client volume when /volume is ran without arguments - client-volume: '&6Your current volume is __amount__%&7 (TIP: use /volume 40 to set your volume to 40%)' + client-volume: '&6Your current volume is __amount__%&7 (TIP: use /volume 40 to set + your volume to 40%)' # The message a client gets as confirmation for executing /volume or /vol client-volume-change: '&6Your volume has been changed to __amount__%' @@ -36,7 +45,8 @@ messages: client-volume-invalid: '&4You must enter a number between 0 and 100' # The message a client gets as warning that they aren't even connected - client-not-connected: '&4You need to be connected to the web client to be able to do that' + client-not-connected: '&4You need to be connected to the web client to be able to + do that' # The message a client gets when they need to be connected to voice chat to do something voice-not-connected: '&4An active Voice connection is required to execute this command' @@ -64,8 +74,15 @@ messages: # Message a player receives when their microphone is unmuted voicechat-mic-unmute: '&7&oYour microphone is now &2&ounmuted' + # Message a player receives when their voicechat is deafened + voicechat-deafen: '&7&oYou are now &c&odeafened' + + # Message a player receives when their voicechat is undeafened + voicechat-undeafen: '&7&oYou are now &2&oundeafened' + # Message a player receives when voicechat runs into a technical issue - voicechat-service-unstable: '&7&oWarning: we ran into one or more problems with the voice service.. please hold on while we try to recover your beautiful voice.' + voicechat-service-unstable: '&7&oWarning: we ran into one or more problems with + the voice service.. please hold on while we try to recover your beautiful voice.' # Message a player receives when the voicechat is back online again voicechat-service-recovered: '&7&oYour voicechat session got successfully recovered' @@ -73,26 +90,100 @@ messages: # A message players will periodically receive when they are not connected to voice chat, # but others in their vicinity are. The minimum interval and range can be configured in the options section, # or you can disable it entirely by following the settings below. - voicechat-players-in-vicinity: '&7&oGet social! Other players in your vicinity are using voice chat - join them and communicate. Use &b/audio&7&o to connect.' + voicechat-players-in-vicinity: '&7&oGet social! Other players in your vicinity are + using voice chat - join them and communicate. Use &b/audio&7&o to connect.' + + # The message a channel owner receives when their chanel has been abandoned + voicechat-channel-abandoned: '&7&oYour voicechat channel has been abandoned and + got removed' + + # The message a player receives when they are kicked from a voicechat channel + # This gets triggered when they were forcefully removed from a channel, for example when it gets deleted + voicechat-channel-kicked: '&7&oYou have been kicked from the voicechat channel' + + # The message a player receives when they are invited to a voicechat channel + voicechat-channel-invited: ' \n&b&lYou have been invited to a voice chat channel!\n&3Click + &ahere&3 to join &d{channel}&3 by &d{inviter}&3!\n&7&oYou have 30 seconds to + accept the invitation.\n ' + + # Error message seen by players when the command is executed through anything other than chat + voicechat-channel-not-a-player: '&cOnly players can use this command' + + # Seen when a player tries to join or create a channel with an invalid name + voicechat-channel-name-unknown: '&cPlease enter a valid channel name' + + # Error seen when a player tries to join a channel that doesn't exist + voicechat-channel-name-not-found: '&cThe channel you are trying to join does not + exist' + + # Error seen when a player tries to create a channel with a name that already exists + voicechat-channel-name-already-exists: '&cA channel with that name already exists' + + # Validation message after creating a new channel + voicechat-channel-created: '&7&oSuccessfully created the voice chat channel &d{channel}' -bedrock: - # These settings are to provide some automatic handholding for Bedrock users. - # Please take some time to go over these settings and adjust them based on your geyser configuration. + # Message a player receives while trying to create or join a channel while already in one + voicechat-channel-already-in: '&cYou are already in a voice chat channel, please + leave it first' - # This message shows as a SUBTITLE for the token prompt - token-subtitle: '&7&oEnter this code on &b__address__' + # A message a player receives after accepting an invitation to a voicechat channel + voicechat-channel-joined: '&7&oYou have joined the voice chat channel &d{channel}' - # The amount of seconds the token prompt will be shown for - token-display-duration: 25 + # A message a player receives after running a command while not in a voicechat channel + voicechat-channel-not-a-member: '&cYou can only perform this action if you are a + member of the channel' - # OA will automatically send the token to the Bedrock client, if a player is detected as one - # based on their name prefix, which defaults to '.'. If you have a custom prefix, you can set it here - # or you can disable this feature entirely - bedrock-name-prefix: '.' - bedrock-auto-send-token: true + # A message a player receives while trying to invite someone to a channel they do not own + voicechat-channel-not-owner: '&cOnly the creator of the channel can do this' + # A message a player receives while trying to invite an invalid player + voicechat-channel-player-not-found: '&cThe player you are trying to invite is not + online' + + # A message a player receives after trying to invite someone who is already in another channel + voicechat-channel-player-already-in-channel: '&cThe player you are trying to invite + is already in a voice chat channel' + + # A message a player receives after trying to invite someone who is not connected to voice chat + voicechat-target-not-connected: '&cThe player you are trying to invite is not connected + to voice chat, please ask them to connect first' + + # Good job! the invitation was sent + voicechat-target-invitation-sent: '&7&oAn invitation has been sent to %name' + voicechat-target-invitation-expired: '&7&oThe invitation to %name has expired' + + # A player receives after leaving a channel voluntarily + voicechat-channel-left: '&7&oYou have left the voice chat channel' + + # Format messages for the channel list command + voicechat-channel-list-no-channels: '&7&oThere are no voice chat channels available' + voicechat-channel-list-header: '&7&oAvailable voice chat channels and their occupants:' + voicechat-channel-list-item: '&7&o- &d{channel} &7&o&d{participants}&7&o' + + # Header of the base /voice help command + voicechat-command-help-header: Welcome to OpenAudioMc! Please click the sub command + you need help with. + + # The format most error messages will be shown in, including prefix + voicechat-command-error-format: '&3[&bVoice Channel&3] &c&oError: &7&o{message}' + + # The following messages are for the new "revised" authentication flow. + # Users who have a client tab open with the bedrock flow till automatically be logged in when a player joins with the same IP address, + # but users who don't have a tab open will be prompted to login with a code. + # That code needs to be entered in-game, and these messages are used for that. + token-activation-loading: '&7&oPlease wait while we activate your token..' + token-activation-success: '&7&oYour token has been activated! You can now use the + web client.' + token-activation-failed: '&7&oYour token could not be activated. Please try again + or double check your code.' options: + # The name prefix to look for to determine if a player is playing on bedrock edition + bedrock-name-prefix: . + + # This setting enabled/disables automatic authentication for bedrock users. + token-auto-login: true + # If set to true, the player automatically receives a link upon joining send-on-join: true @@ -191,20 +282,58 @@ options: # but the higher the load on the server will be. I recommend setting this to 5 (meaning it updates 4 times a second) redstone-tick-speakers-interval: 5 + # This feature will completely ignore ALL regions when a player is on a vehicle + # (Minecraft, Boat, or mounted on another entity). + # This is useful for some themepark servers, but should be used with caution. + ignore-regions-on-vehicles: false + + # This feature will hydrate region media for all regions on boot. This means that if you hae two regions, with different sources but equal durations + # they will be played in sync. Having this feature enable might have an additional memory footprint if you have a *ton* of regions (hundreds) + # but it's recommended to leave this on. + hydrate-regions-on-boot: true + +# Voicechat filters define requirements that players both have to meet before they will be able to hear eachother. +# You can implement custom filters through the API, or enable some of the default ones below. +vc-filter: + + # When enabled, players will only be able to hear eachother if they both share the same gamemode (survival, creative, adventure, spectator) + require-same-gamemode: false + + # When enabled, players will only be able to hear eachother if they both share the same team. Edge cases: + # - Players without a team can only hear other players without a team + require-common-team: false + +# Static channels are a set of channels that will always exist (even if they are empty), and can be locked behind certain permissions +# You can use this feature in cases where individuals don't have permissions to create their own channels, but sitll want to offer +# some groups for global voicechat (like a channel for minigames, off-topic, and roleplay). You can add more values here if you wish, +# or disable the feature entirely. Keep in mind to include all sub values if you add a new channel, and to respect yaml formatting. +# These values are only used on spigot instances +static-channels: + enabled: true + list: + - name: survival + permission: channels.survival + requirePermission: false + - name: off-topic + permission: channels.offtopic + requirePermission: false + - name: staff-chat + permission: channels.staffchat + requirePermission: true # PlaceholderAPI papi: # Value to display when player is connected to the web client - client-connected: "Connected" + client-connected: Connected # Value to display when player is disconnected from the web client - client-disconnected: "Disconnected" + client-disconnected: Disconnected # Value to display when player is connected to the voice chat - voicechat-connected: "Connected" + voicechat-connected: Connected # Value to display when player is disconnected from the voice chat - voicechat-disconnected: "Disconnected" + voicechat-disconnected: Disconnected # CDN # Configuration for the Patreon CDN @@ -234,3 +363,5 @@ redis: useSSL: false # The channel to sync with. When configured, OpenAudioMc will only sync to servers on redis with the same section section: event + # When using Redis Sentinel, you should set the master set to use. Leaves empty to use a single server Redis cluster + sentinel-master-set: '' diff --git a/modules/vistas-client/src/main/java/com/craftmend/openaudiomc/vistas/client/redis/RedisConnection.java b/modules/vistas-client/src/main/java/com/craftmend/openaudiomc/vistas/client/redis/RedisConnection.java index 3dd2ee221e..1aa76d26ad 100644 --- a/modules/vistas-client/src/main/java/com/craftmend/openaudiomc/vistas/client/redis/RedisConnection.java +++ b/modules/vistas-client/src/main/java/com/craftmend/openaudiomc/vistas/client/redis/RedisConnection.java @@ -9,10 +9,14 @@ import io.lettuce.core.pubsub.RedisPubSubAdapter; import io.lettuce.core.pubsub.StatefulRedisPubSubConnection; import io.lettuce.core.pubsub.api.async.RedisPubSubAsyncCommands; +import io.lettuce.core.resource.ClientResources; +import io.lettuce.core.resource.DefaultClientResources; import lombok.Getter; public class RedisConnection { + private static final ClientResources sharedResources = DefaultClientResources.create(); + @Getter private RedisClient redisClient; @Getter private StatefulRedisPubSubConnection connection; @Getter private RedisPubSubAsyncCommands pubSubHandler; @@ -47,7 +51,7 @@ public RedisConnection(String host, OpenAudioLogger.info("Connecting to redis server: " + uri.toString()); - redisClient = RedisClient.create(uri); + redisClient = RedisClient.create(sharedResources, uri); redisClient.setOptions(ClientOptions.builder().autoReconnect(true).build()); } diff --git a/modules/vistas-client/src/main/java/com/craftmend/openaudiomc/vistas/client/users/ServerUserHooks.java b/modules/vistas-client/src/main/java/com/craftmend/openaudiomc/vistas/client/users/ServerUserHooks.java index 59edd84cbb..f0995fcb99 100644 --- a/modules/vistas-client/src/main/java/com/craftmend/openaudiomc/vistas/client/users/ServerUserHooks.java +++ b/modules/vistas-client/src/main/java/com/craftmend/openaudiomc/vistas/client/users/ServerUserHooks.java @@ -22,7 +22,8 @@ public class ServerUserHooks implements UserHooks { private Map remoteUsers = new ConcurrentHashMap<>(); - @Getter private Map remoteInstallation = new ConcurrentHashMap<>(); + @Getter + private Map remoteInstallation = new ConcurrentHashMap<>(); public void startGc() { OpenAudioMc.resolveDependency(TaskService.class).scheduleSyncRepeatingTask(() -> { @@ -96,7 +97,7 @@ public VistasUser registerUserIfNew(UUID playerId, String name, String ip) { public void registerServer(UUID serverId) { MinecraftServer c = new MinecraftServer("remote-" + serverId, serverId); - remoteInstallation.put(serverId, c); + remoteInstallation.put(serverId, c); System.out.println("Registering remote server " + c.getName()); } @@ -110,7 +111,7 @@ public MinecraftServer registerServerIfNew(UUID serverId) { registerServer(serverId); return registerServerIfNew(serverId); } - + public void unregisterServer(UUID serverId) { for (VistasUser value : remoteUsers.values()) { if (value.getLastSeenServer() != null && value.getLastSeenServer().equals(serverId)) { diff --git a/modules/vistas-server/.tool-versions b/modules/vistas-server/.tool-versions new file mode 100644 index 0000000000..b1e51edda4 --- /dev/null +++ b/modules/vistas-server/.tool-versions @@ -0,0 +1 @@ +java adoptopenjdk-8.0.332+9 diff --git a/modules/vistas-server/dependency-reduced-pom.xml b/modules/vistas-server/dependency-reduced-pom.xml index 922179d83f..cdfe118571 100644 --- a/modules/vistas-server/dependency-reduced-pom.xml +++ b/modules/vistas-server/dependency-reduced-pom.xml @@ -115,29 +115,7 @@ ${project.basedir}/target/classes - - - - org.jacoco - jacoco-maven-plugin - 0.8.8 - - - - prepare-agent - - - - report - test - - report - - - - - ${basedir}/target/coverage-reports/jacoco-unit.exec - ${basedir}/target/coverage-reports/jacoco-unit.exec + -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/mats/Desktop diff --git a/modules/vistas-server/pom.xml b/modules/vistas-server/pom.xml index 2560ee6fa2..92ad5b0093 100644 --- a/modules/vistas-server/pom.xml +++ b/modules/vistas-server/pom.xml @@ -130,32 +130,9 @@ ${project.basedir}/target/classes + -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/mats/Desktop - - org.jacoco - jacoco-maven-plugin - 0.8.8 - - ${basedir}/target/coverage-reports/jacoco-unit.exec - ${basedir}/target/coverage-reports/jacoco-unit.exec - - - - - prepare-agent - - - - - report - test - - report - - - - org.apache.maven.plugins maven-shade-plugin @@ -223,7 +200,7 @@ com.coreoz wisp - 2.2.1 + 2.4.0 compile @@ -237,4 +214,4 @@ - \ No newline at end of file + diff --git a/modules/vistas-server/src/main/java/com/craftmend/vistas/server/base/VistasScheduler.java b/modules/vistas-server/src/main/java/com/craftmend/vistas/server/base/VistasScheduler.java index 6a6ca59e0d..aae7fe147f 100644 --- a/modules/vistas-server/src/main/java/com/craftmend/vistas/server/base/VistasScheduler.java +++ b/modules/vistas-server/src/main/java/com/craftmend/vistas/server/base/VistasScheduler.java @@ -1,22 +1,33 @@ package com.craftmend.vistas.server.base; +import com.coreoz.wisp.JobStatus; import com.coreoz.wisp.Scheduler; import com.coreoz.wisp.schedule.Schedules; import com.craftmend.openaudiomc.generic.platform.interfaces.TaskService; import com.craftmend.openaudiomc.generic.service.Service; import java.time.Duration; -import java.util.ArrayList; -import java.util.List; +import java.util.UUID; public class VistasScheduler extends Service implements TaskService { - private Scheduler scheduler; + private final Scheduler scheduler; private int taskCount = 0; - private List runningTasks = new ArrayList<>(); public VistasScheduler() { scheduler = new Scheduler(); + + scheduler.schedule( + "Terminated jobs cleaner", + () -> scheduler + .jobStatus() + .stream() + .filter(job -> job.status() == JobStatus.DONE) + // Clean only jobs that have finished executing since at least 10 seconds + .filter(job -> job.lastExecutionEndedTimeInMillis() < (System.currentTimeMillis() - 10000)) + .forEach(job -> scheduler.remove(job.name())), + Schedules.fixedDelaySchedule(Duration.ofSeconds(5)) + ); } @Override @@ -25,29 +36,12 @@ public int scheduleAsyncRepeatingTask(Runnable runnable, int delayUntilFirst, in int intervalMs = tickInterval * 50; int currentTask = taskCount++; - runningTasks.add(currentTask); - WrappedRunnable handler = new WrappedRunnable(); - - handler.setTask(() -> { - if (isCancelled(currentTask)) { - runningTasks.removeIf(task -> task == currentTask); - return; - } - - runnable.run(); - - scheduler.schedule( - () -> { - handler.getTask().run(); - }, - Schedules.executeOnce(Schedules.fixedDelaySchedule(Duration.ofMillis(intervalMs))) - ); - - }); - scheduler.schedule( - handler.getTask(), - Schedules.executeOnce(Schedules.fixedDelaySchedule(Duration.ofMillis(delayMs))) + currentTask + "", + () -> { + runnable.run(); + }, + Schedules.fixedDelaySchedule(Duration.ofMillis(intervalMs)) ); return currentTask; @@ -62,16 +56,11 @@ public int scheduleSyncRepeatingTask(Runnable runnable, int delayUntilFirst, int public int schduleSyncDelayedTask(Runnable runnable, int delay) { int delayMs = delay * 50; int currentTask = taskCount++; - runningTasks.add(currentTask); scheduler.schedule( + currentTask + "", () -> { - if (isCancelled(currentTask)) { - runningTasks.removeIf(task -> task == currentTask); - return; - } runnable.run(); - runningTasks.removeIf(task -> task == currentTask); }, Schedules.executeOnce(Schedules.fixedDelaySchedule(Duration.ofMillis(delayMs))) ); @@ -79,18 +68,15 @@ public int schduleSyncDelayedTask(Runnable runnable, int delay) { return currentTask; } - public boolean isCancelled(int task) { - return !runningTasks.contains(task); - } - @Override public void cancelRepeatingTask(int i) { - runningTasks.removeIf(task -> task == i); + scheduler.cancel(i + ""); } @Override public void runAsync(Runnable runnable) { scheduler.schedule( + UUID.randomUUID().toString(), () -> { runnable.run(); }, @@ -101,6 +87,7 @@ public void runAsync(Runnable runnable) { @Override public void runSync(Runnable runnable) { scheduler.schedule( + UUID.randomUUID().toString(), runnable, Schedules.executeOnce(Schedules.fixedDelaySchedule(Duration.ofMillis(1))) ); diff --git a/modules/vistas-server/src/test/java/vistas/test/TestServer.java b/modules/vistas-server/src/test/java/vistas/test/TestServer.java index 4b77b05179..fa574babce 100644 --- a/modules/vistas-server/src/test/java/vistas/test/TestServer.java +++ b/modules/vistas-server/src/test/java/vistas/test/TestServer.java @@ -1,12 +1,17 @@ package vistas.test; import com.craftmend.openaudiomc.OpenAudioMc; +import com.craftmend.openaudiomc.generic.client.helpers.ClientRtcLocationUpdate; +import com.craftmend.openaudiomc.generic.client.objects.ClientConnection; +import com.craftmend.openaudiomc.generic.networking.packets.client.voice.PacketClientUpdateVoiceLocations; +import com.craftmend.openaudiomc.generic.networking.payloads.client.voice.ClientVoiceUpdatePeerLocationsPayload; +import com.craftmend.openaudiomc.generic.node.packets.ForwardSocketPacket; import com.craftmend.openaudiomc.generic.oac.OpenaudioAccountService; import com.craftmend.openaudiomc.generic.logging.OpenAudioLogger; import com.craftmend.openaudiomc.generic.proxy.interfaces.UserHooks; -import com.craftmend.openaudiomc.vistas.client.redis.packets.ServerRegisterPacket; -import com.craftmend.openaudiomc.vistas.client.redis.packets.UserJoinPacket; -import com.craftmend.openaudiomc.vistas.client.redis.packets.UserLeavePacket; +import com.craftmend.openaudiomc.vistas.client.Vistas; +import com.craftmend.openaudiomc.vistas.client.client.VistasRedisClient; +import com.craftmend.openaudiomc.vistas.client.redis.packets.*; import com.craftmend.openaudiomc.vistas.client.server.networking.VistasRedisServer; import com.craftmend.openaudiomc.vistas.client.users.ServerUserHooks; import com.craftmend.vistas.server.VistasServer; @@ -20,6 +25,8 @@ import vistas.test.utils.Waiter; import java.net.Socket; +import java.util.HashSet; +import java.util.Set; import java.util.UUID; public class TestServer extends TestCase { @@ -68,6 +75,7 @@ public void testFullStack() { // fake register a minecraft server UUID fakeServer1 = UUID.randomUUID(); UUID fakeServer2 = UUID.randomUUID(); + OpenAudioMc.getService(VistasRedisServer.class).getPacketEvents().handlePacket(null, new ServerRegisterPacket(fakeServer1)); OpenAudioMc.getService(VistasRedisServer.class).getPacketEvents().handlePacket(null, new ServerRegisterPacket(fakeServer2)); @@ -151,6 +159,70 @@ public void testFullStack() { assertEquals(0, OpenAudioMc.resolveDependency(ServerUserHooks.class).getRemoteUsers().size()); assertEquals(0, OpenAudioMc.resolveDependency(ServerUserHooks.class).getRemoteUsers().size()); + startLoggingMemory(); + startStressTesting(); + } + + private void startStressTesting() { + // crate server + UUID fakeServer1 = UUID.randomUUID(); + OpenAudioMc.getService(VistasRedisServer.class).getPacketEvents().handlePacket(null, new ServerRegisterPacket(fakeServer1)); + + Set updates = new HashSet<>(); + + // loop 50 times + for (int i = 0; i < 50; i++) { + ClientRtcLocationUpdate update = new ClientRtcLocationUpdate("RandomStreamKey" + i, 1, 2, 3, 4); + updates.add(update); + } + + TempUser tempUser = new TempUser(UUID.randomUUID().toString(), UUID.randomUUID()); + + while (true) { + // create user, send 1000 movement packets, then leave + //System.out.println("Stress testing user " + tempUser.getName()); + OpenAudioMc.getService(VistasRedisServer.class).getPacketEvents().handlePacket(null, new UserJoinPacket( + tempUser.getName(), + tempUser.getUuid(), + fakeServer1, + "localhost" + )); + + for (int i = 0; i < 1000; i++) { + // make movement update packet + PacketClientUpdateVoiceLocations packet = new PacketClientUpdateVoiceLocations(new ClientVoiceUpdatePeerLocationsPayload(updates)); + OpenAudioMc.getService(VistasRedisServer.class).getPacketEvents().handlePacket(null, new WrappedProxyPacket( + new ForwardSocketPacket(packet), + fakeServer1, + tempUser.getUuid() + )); + } + + // user logout + OpenAudioMc.getService(VistasRedisServer.class).getPacketEvents().handlePacket(null, new UserLeavePacket( + tempUser.getName(), + tempUser.getUuid(), + fakeServer1 + )); + } + } + + private void startLoggingMemory() { + new Thread(() -> { + int max = 0; + while (true) { + int used = (int) ((Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / 1024 / 1024); + if (used > max) max = used; + + System.out.println("Memory usage: " + used + "MB (max: " + max + "MB)"); + + try { + Thread.sleep(500); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + }).start(); } @Getter diff --git a/plugin/dependency-reduced-pom.xml b/plugin/dependency-reduced-pom.xml index 59a66910ee..971339caab 100644 --- a/plugin/dependency-reduced-pom.xml +++ b/plugin/dependency-reduced-pom.xml @@ -217,7 +217,7 @@ com.coreoz wisp - 2.2.2 + 2.4.0 test diff --git a/plugin/pom.xml b/plugin/pom.xml index 9d6cf903e6..1b7a76f8e8 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -110,7 +110,7 @@ com.coreoz wisp - 2.2.2 + 2.4.0 test @@ -456,4 +456,4 @@ - \ No newline at end of file + diff --git a/plugin/src/main/bash/data.bin b/plugin/src/main/bash/data.bin index 3cd16e9684..5113dc0a2b 100755 --- a/plugin/src/main/bash/data.bin +++ b/plugin/src/main/bash/data.bin @@ -1 +1 @@ -BUILD_NUM="1438" +BUILD_NUM="1445" diff --git a/plugin/src/main/java/com/craftmend/openaudiomc/bungee/modules/commands/subcommand/BungeeRegionCommand.java b/plugin/src/main/java/com/craftmend/openaudiomc/bungee/modules/commands/subcommand/BungeeRegionCommand.java index 8d4bff0681..35310c60fa 100644 --- a/plugin/src/main/java/com/craftmend/openaudiomc/bungee/modules/commands/subcommand/BungeeRegionCommand.java +++ b/plugin/src/main/java/com/craftmend/openaudiomc/bungee/modules/commands/subcommand/BungeeRegionCommand.java @@ -48,7 +48,9 @@ public BungeeRegionCommand() { "Change the fade of a region"), new Argument("list", - "List all regions at your current location and their properties") + "List all regions at your current location and their properties"), + + new Argument("forceupdate", "Force all regions to update their media cache") ); } diff --git a/plugin/src/main/java/com/craftmend/openaudiomc/generic/networking/drivers/SystemDriver.java b/plugin/src/main/java/com/craftmend/openaudiomc/generic/networking/drivers/SystemDriver.java index 3044f491a9..68818ee1f3 100644 --- a/plugin/src/main/java/com/craftmend/openaudiomc/generic/networking/drivers/SystemDriver.java +++ b/plugin/src/main/java/com/craftmend/openaudiomc/generic/networking/drivers/SystemDriver.java @@ -63,7 +63,6 @@ public void boot(Socket socket, SocketConnection connector) { }); socket.on("announce-shutdown", args -> { - OpenAudioLogger.info("The server announced its intention to close our connection.."); announcedShutdown = true; }); diff --git a/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/commands/subcommands/RegionsSubCommand.java b/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/commands/subcommands/RegionsSubCommand.java index e13e4827b7..ca5a2138e4 100644 --- a/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/commands/subcommands/RegionsSubCommand.java +++ b/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/commands/subcommands/RegionsSubCommand.java @@ -22,7 +22,8 @@ public RegionsSubCommand(OpenAudioMcSpigot openAudioMcSpigot) { new RegionDeleteSubCommand(openAudioMcSpigot), new RegionTempSubCommand(openAudioMcSpigot), new RegionEditSubCommand(openAudioMcSpigot), - new RegionListSubCommand(openAudioMcSpigot) + new RegionListSubCommand(openAudioMcSpigot), + new RegionForceUpdateSubCommand() ); registerArguments( @@ -49,7 +50,9 @@ public RegionsSubCommand(OpenAudioMcSpigot openAudioMcSpigot) { "Change the fade of a region"), new Argument("list", - "List all regions at your current location and their properties") + "List all regions at your current location and their properties"), + + new Argument("forceupdate", "Force all regions to update their media cache") ); this.openAudioMcSpigot = openAudioMcSpigot; } @@ -104,6 +107,11 @@ public void onExecute(User sender, String[] args) { return; } + if (args[0].equalsIgnoreCase("forceupdate") && args.length == 1) { + delegateTo("forceupdate", sender, args); + return; + } + sender.makeExecuteCommand("oa help " + getCommand()); } diff --git a/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/commands/subcommands/region/RegionForceUpdateSubCommand.java b/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/commands/subcommands/region/RegionForceUpdateSubCommand.java new file mode 100644 index 0000000000..acb51f3289 --- /dev/null +++ b/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/commands/subcommands/region/RegionForceUpdateSubCommand.java @@ -0,0 +1,28 @@ +package com.craftmend.openaudiomc.spigot.modules.commands.subcommands.region; + +import com.craftmend.openaudiomc.generic.commands.interfaces.SubCommand; +import com.craftmend.openaudiomc.generic.commands.objects.Argument; +import com.craftmend.openaudiomc.generic.user.User; +import com.craftmend.openaudiomc.spigot.OpenAudioMcSpigot; +import com.craftmend.openaudiomc.spigot.modules.regions.RegionModule; +import com.craftmend.openaudiomc.spigot.modules.regions.registry.WorldRegionManager; + +public class RegionForceUpdateSubCommand extends SubCommand { + + public RegionForceUpdateSubCommand() { + super("forceupdate"); + + registerArguments( + new Argument("", "Force all regions to update their media cache") + ); + + } + + @Override + public void onExecute(User sender, String[] args) { + OpenAudioMcSpigot oams = OpenAudioMcSpigot.getInstance(); + RegionModule regionModule = oams.getRegionModule(); + regionModule.getWorlds().forEach(WorldRegionManager::clearMediaCache); + message(sender, "Cleared the media cache for all regions."); + } +} diff --git a/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/regions/RegionModule.java b/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/regions/RegionModule.java index 8fe3688d79..cccd42f4fe 100644 --- a/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/regions/RegionModule.java +++ b/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/regions/RegionModule.java @@ -90,7 +90,7 @@ public RegionModule(@Nullable AbstractRegionAdapter customAdapter) { OpenAudioMc.getService(MediaService.class).getResetTriggers().add(() -> { // clean media once a new media adapter is loaded, this ensures that they will be re-evaluated - worldManagers.forEach((s, worldRegionManager) -> {worldRegionManager.clearMedia();}); + worldManagers.forEach((s, worldRegionManager) -> {worldRegionManager.dropMediaCache();}); }); // register unknown regions @@ -276,4 +276,8 @@ public int getRegionCount() { } return count; } + + public Collection getWorlds() { + return worldManagers.values(); + } } diff --git a/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/regions/gui/RegionEditGui.java b/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/regions/gui/RegionEditGui.java index de0694b88e..fffe923c57 100644 --- a/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/regions/gui/RegionEditGui.java +++ b/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/regions/gui/RegionEditGui.java @@ -74,6 +74,8 @@ public Item getSyncItem(IRegion region) { player.sendMessage(MagicValue.COMMAND_PREFIX.get(String.class) + ChatColor.RED + "Music will now always play from the beginning when someone enters or connects."); } + OpenAudioMc.getService(DatabaseService.class).getRepository(RegionProperties.class) + .save(region.getProperties()); // reset the media cache for this region Media oldMedia = region.getMedia(); diff --git a/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/regions/registry/WorldRegionManager.java b/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/regions/registry/WorldRegionManager.java index 1b4a6b5a1d..0762bdfdc9 100644 --- a/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/regions/registry/WorldRegionManager.java +++ b/plugin/src/main/java/com/craftmend/openaudiomc/spigot/modules/regions/registry/WorldRegionManager.java @@ -67,6 +67,10 @@ public RegionMedia getRegionMedia(String source, int volume, int fadeTimeMs, Boo return regionMedia; } + public void dropMediaCache() { + regionMediaMap.clear(); + } + public Collection getRegions() { return regionPropertiesMap.values(); } @@ -75,7 +79,7 @@ public void unregisterRegionMedia(String source) { regionMediaMap.remove(source); } - public void clearMedia() { + public void clearMediaCache() { regionMediaMap.clear(); } diff --git a/plugin/src/main/java/com/craftmend/openaudiomc/velocity/modules/commands/subcommand/VelocityRegionCommand.java b/plugin/src/main/java/com/craftmend/openaudiomc/velocity/modules/commands/subcommand/VelocityRegionCommand.java index d42596fd2e..da741f08ff 100644 --- a/plugin/src/main/java/com/craftmend/openaudiomc/velocity/modules/commands/subcommand/VelocityRegionCommand.java +++ b/plugin/src/main/java/com/craftmend/openaudiomc/velocity/modules/commands/subcommand/VelocityRegionCommand.java @@ -40,7 +40,9 @@ public VelocityRegionCommand() { "Change the fade of a region"), new Argument("list", - "List all regions at your current location and their properties") + "List all regions at your current location and their properties"), + + new Argument("forceupdate", "Force all regions to update their media cache") ); } diff --git a/plugin/src/main/resources/data.bin b/plugin/src/main/resources/data.bin index 3cd16e9684..5113dc0a2b 100755 --- a/plugin/src/main/resources/data.bin +++ b/plugin/src/main/resources/data.bin @@ -1 +1 @@ -BUILD_NUM="1438" +BUILD_NUM="1445" diff --git a/plugin/src/main/resources/openaudiomc-build.properties b/plugin/src/main/resources/openaudiomc-build.properties index f9adf3737d..474a1b31a6 100644 --- a/plugin/src/main/resources/openaudiomc-build.properties +++ b/plugin/src/main/resources/openaudiomc-build.properties @@ -1,3 +1,3 @@ -BUILD_VERSION="1438" -BUILD_COMMIT="b185ac1858bdbe73f0106928153783356d59ef1b" +BUILD_VERSION="1445" +BUILD_COMMIT="28cd0ac842b271f5be2e8efe9dc60208b96ad077" BUILD_AUTHOR="Mats" diff --git a/pom.xml b/pom.xml index 911481148a..d05a83417b 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ 4.7.0 3.0.1 e1f961b - 2.12.4 + 2.13.1 b23a51825e