VoiceModule class

Пакет: com.hypixel.hytale.server.core.modules.voice

Файл: com/hypixel/hytale/server/core/modules/voice/VoiceModule.java

extends: JavaPlugin

Поля (81)

МодификаторыТипИмя
final long POSITION_CACHE_UPDATE_INTERVAL_MS
instance
HashMap var1
List var1
var1
Iterator var1
boolean var10
int var10
Ref var10
int var11
UUID var11
Store var11
boolean var12
VoiceModule.PositionSnapshot var12
ChunkColumn var12
UUID var13
TransformComponent var13
Ref var14
UUID var14
World var15
World var16
Store var2
PlayerRef var2
UUID var2
PlayerRef var2
EntityVoiceSpeaker var2
Ref var2
ClipPlayback var2
boolean var2
float var2
float var2
boolean var2
boolean var2
NetworkId var2
int var2
PlayerRef var3
EntityStore var3
Ref var3
VoicePlayerState var3
Ref var3
PlayerRef var3
VoicePlayerState var3
VoiceModule.RegisteredInterceptor var3
ArrayList var3
World var3
UUID var3
ClipPlayback var3
boolean var3
var3
var3
PlayerRef var3
UUID var4
Ref var4
Store var4
Store var4
String var4
PlayerVoiceInterceptor var4
boolean var4
var4
int var4
PlayerRef var5
Store var5
EntityStore var5
EntityStore var5
ArrayList var5
int var5
World var6
EntityStore var6
World var6
World var6
int var6
Vector3d var6
HashMap var7
World var7
UUID var7
ChunkStore var7
TransformComponent var8
float var8
long var8
float var9
boolean var9

Методы (94)

МодификаторыВозвратСигнатура
public record PositionSnapshotrecord PositionSnapshot(@Nonnull Vector3dc position, boolean isUnderwater, @Nonnull UUID worldId, int networkId, boolean isDead)
private record RegisteredInterceptorrecord RegisteredInterceptor(int priority, @Nonnull PlayerVoiceInterceptor interceptor)
static VoiceModule.PositionSnapshot atEyeHeightstatic VoiceModule.PositionSnapshot atEyeHeight(@Nonnull Vector3dc var0, float var1, boolean var2, @Nonnull UUID var3, int var4, boolean var5)
private void broadcastConfigToAllPlayersvoid broadcastConfigToAllPlayers()
private void broadcastMuteUpdatevoid broadcastMuteUpdate(@Nonnull UUID var1, boolean var2)
static int entityNetworkIdint entityNetworkId(@Nonnull Ref<EntityStore> var0, @Nonnull ComponentAccessor<EntityStore> var1)
private void executeOnWorldOrSkipvoid executeOnWorldOrSkip(@Nonnull World var1, @Nonnull String var2, @Nonnull Runnable var3)
for for(int var2 = 0; var2 < 4; var2++)
for for(UUID var5 : var2)
for for(VoiceSpeaker var10 : var3)
for for(ClipPlayback var3 : var1)
for for(ExecutorService var5 : this.voiceExecutors)
for for(ExecutorService var20 : this.voiceExecutors)
for for(ExecutorService var6 : this.voiceExecutors)
for for(VoiceModule.RegisteredInterceptor var3 : this.playerVoiceInterceptors)
static VoiceModule getVoiceModule get()
public int getBurstCapacityint getBurstCapacity()
public Set<UUID> getGloballyMutedPlayersSet<UUID> getGloballyMutedPlayers()
public float getMaxHearingDistancefloat getMaxHearingDistance()
public int getMaxPacketSizeint getMaxPacketSize()
public int getMaxPacketsPerSecondint getMaxPacketsPerSecond()
public Map<UUID, VoicePlayerState> getPlayerStatesMap<UUID, VoicePlayerState> getPlayerStates()
public float getReferenceDistancefloat getReferenceDistance()
public ExecutorService getVoiceExecutorExecutorService getVoiceExecutor(@Nonnull UUID var1)
public VoiceRouter getVoiceRouterVoiceRouter getVoiceRouter()
boolean hasPlayerVoiceInterceptorsboolean hasPlayerVoiceInterceptors()
if if(Constants.SINGLEPLAYER)
if if(Constants.SINGLEPLAYER)
if if(!this.isShutdown)
if if(var5 != null)
if if(var6 != null)
if if(var14 != null)
if if(var16 == null)
if if(var2 != null)
if if(var3 != null)
if if(var3 == null)
if if(var5 == null)
if if(var6 == null)
if if(var7 != var1)
if if(var8 == null)
if if(var1 == null)
if if(var2 == null)
if if(var4 == null)
if if(var6 != null && var6 == var2)
if if(var13 == null)
if if(this.positionUpdateTask != null)
if if(this.clipPumpTask != null)
if if(var3 != null)
if if(var4 != null)
if if(var5 != null)
if if(var6 != null)
if if(var3 != null)
if if(var2 != null)
if if(var3 != null)
if if(!this.isShutdown)
if if(this.clipPumpTask == null)
if if(!var4)
if if(!var3)
if if(var2 != var1)
if if(var2 != var1)
if if(var2 != var1)
if if(var3 != null)
if if(var2)
if if(var2)
public boolean isDeadPlayersCanHearboolean isDeadPlayersCanHear()
private boolean isEyeInFluidboolean isEyeInFluid(@Nonnull Vector3d var1, float var2, @Nonnull World var3)
public boolean isPlayerMutedboolean isPlayerMuted(@Nonnull UUID var1)
public boolean isShutdownboolean isShutdown()
public boolean isVoiceEnabledboolean isVoiceEnabled()
public boolean mutePlayerboolean mutePlayer(@Nonnull UUID var1)
static UUID newVoiceStreamIdUUID newVoiceStreamId()
private void onPlayerConnectvoid onPlayerConnect(@Nonnull PlayerConnectEvent var1)
private void onPlayerDisconnectvoid onPlayerDisconnect(@Nonnull PlayerDisconnectEvent var1)
private void onServerAccessChangedvoid onServerAccessChanged(@Nonnull SingleplayerRequestAccessEvent var1)
private void pumpClipsvoid pumpClips()
void removeSpeakervoid removeSpeaker(@Nonnull UUID var1)
void runPlayerVoiceInterceptorsvoid runPlayerVoiceInterceptors(@Nonnull PlayerVoiceFrame var1)
private void scheduleImmediateEntitySpeakerUpdatevoid scheduleImmediateEntitySpeakerUpdate(@Nonnull VoiceSpeaker var1)
public void scheduleImmediatePositionUpdatevoid scheduleImmediatePositionUpdate(@Nonnull PlayerRef var1)
private void scheduleWorldSamplevoid scheduleWorldSample(@Nonnull World var1, @Nullable List<UUID> var2, @Nullable List<VoiceSpeaker> var3)
public void setMaxHearingDistancevoid setMaxHearingDistance(float var1)
public void setPlayerVoiceChannelvoid setPlayerVoiceChannel(@Nonnull UUID var1, @Nullable String var2)
public void setReferenceDistancevoid setReferenceDistance(float var1)
public void setVoiceEnabledvoid setVoiceEnabled(boolean var1)
abstract super super(var1)
synchronized synchronized(this.clipPumpLock)
synchronized synchronized(this.playerVoiceInterceptorLock)
synchronized synchronized(this.playerVoiceInterceptorLock)
synchronized synchronized(this.clipPumpLock)
synchronized synchronized(this.clipPumpLock)
public boolean unmutePlayerboolean unmutePlayer(@Nonnull UUID var1)
private void updateAllPlayerPositionsvoid updateAllPlayerPositions()
private void updateEntitySpeakerPositionCachevoid updateEntitySpeakerPositionCache(@Nonnull VoiceSpeaker var1, @Nonnull World var2)
void updatePositionCachevoid updatePositionCache(@Nonnull UUID var1, @Nonnull VoiceModule.PositionSnapshot var2)

Исходный код

Показать/скрыть
class="kw">package com.hypixel.hytale.server.core.modules.voice;

class="kw">import com.hypixel.hytale.common.plugin.PluginManifest;
class="kw">import com.hypixel.hytale.component.ComponentAccessor;
class="kw">import com.hypixel.hytale.component.Ref;
class="kw">import com.hypixel.hytale.component.Store;
class="kw">import com.hypixel.hytale.event.EventPriority;
class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.math.util.ChunkUtil;
class="kw">import com.hypixel.hytale.math.util.MathUtil;
class="kw">import com.hypixel.hytale.protocol.packets.serveraccess.Access;
class="kw">import com.hypixel.hytale.protocol.packets.stream.StreamType;
class="kw">import com.hypixel.hytale.registry.Registration;
class="kw">import com.hypixel.hytale.server.core.Constants;
class="kw">import com.hypixel.hytale.server.core.HytaleServer;
class="kw">import com.hypixel.hytale.server.core.event.events.player.PlayerConnectEvent;
class="kw">import com.hypixel.hytale.server.core.event.events.player.PlayerDisconnectEvent;
class="kw">import com.hypixel.hytale.server.core.io.ServerManager;
class="kw">import com.hypixel.hytale.server.core.io.stream.StreamManager;
class="kw">import com.hypixel.hytale.server.core.modules.collision.WorldUtil;
class="kw">import com.hypixel.hytale.server.core.modules.entity.EntityModule;
class="kw">import com.hypixel.hytale.server.core.modules.entity.component.ModelComponent;
class="kw">import com.hypixel.hytale.server.core.modules.entity.component.TransformComponent;
class="kw">import com.hypixel.hytale.server.core.modules.entity.damage.DeathComponent;
class="kw">import com.hypixel.hytale.server.core.modules.entity.tracker.NetworkId;
class="kw">import com.hypixel.hytale.server.core.modules.singleplayer.SingleplayerRequestAccessEvent;
class="kw">import com.hypixel.hytale.server.core.modules.voice.commands.VoiceCommand;
class="kw">import com.hypixel.hytale.server.core.plugin.JavaPlugin;
class="kw">import com.hypixel.hytale.server.core.plugin.JavaPluginInit;
class="kw">import com.hypixel.hytale.server.core.universe.PlayerRef;
class="kw">import com.hypixel.hytale.server.core.universe.Universe;
class="kw">import com.hypixel.hytale.server.core.universe.world.World;
class="kw">import com.hypixel.hytale.server.core.universe.world.chunk.ChunkColumn;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.ChunkStore;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
class="kw">import com.hypixel.hytale.server.core.util.Config;
class="kw">import com.hypixel.hytale.server.core.util.UUIDUtil;
class="kw">import com.hypixel.hytale.server.core.util.concurrent.ThreadUtil;
class="kw">import java.util.ArrayList;
class="kw">import java.util.Collection;
class="kw">import java.util.Comparator;
class="kw">import java.util.HashMap;
class="kw">import java.util.Iterator;
class="kw">import java.util.List;
class="kw">import java.util.Map;
class="kw">import java.util.Set;
class="kw">import java.util.UUID;
class="kw">import java.util.Map.Entry;
class="kw">import java.util.concurrent.ConcurrentHashMap;
class="kw">import java.util.concurrent.ExecutorService;
class="kw">import java.util.concurrent.Executors;
class="kw">import java.util.concurrent.ScheduledFuture;
class="kw">import java.util.concurrent.TimeUnit;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;
class="kw">import org.joml.Vector3d;
class="kw">import org.joml.Vector3dc;

class="kw">public class VoiceModule class="kw">extends JavaPlugin {
   class="kw">private class="kw">static class="kw">final long POSITION_CACHE_UPDATE_INTERVAL_MS = 100L;
   class="kw">static class="kw">final long CLIP_FRAME_INTERVAL_MS = 20L;
   class="kw">public class="kw">static class="kw">final PluginManifest MANIFEST = PluginManifest.corePlugin(VoiceModule.class).depends(Universe.class).depends(EntityModule.class).build();
   class="kw">private class="kw">static VoiceModule instance;
   @Nonnull
   class="kw">private class="kw">final Config<VoiceModuleConfig> config = this.withConfig("VoiceModule", VoiceModuleConfig.CODEC);
   class="kw">private class="kw">static class="kw">final int MAX_PACKETS_PER_SECOND = 60;
   class="kw">private class="kw">static class="kw">final int BURST_CAPACITY = 25;
   class="kw">private class="kw">static class="kw">final int MAX_PACKET_SIZE = 1024;
   class="kw">private class="kw">final Map<UUID, VoicePlayerState> playerStates = new ConcurrentHashMap<>();
   class="kw">private class="kw">final Map<UUID, VoiceSpeaker> customSpeakers = new ConcurrentHashMap<>();
   class="kw">private class="kw">final VoiceChannels voiceChannels = new VoiceChannels();
   class="kw">private class="kw">final Object playerVoiceInterceptorLock = new Object();
   class="kw">private class="kw">volatile List<VoiceModule.RegisteredInterceptor> playerVoiceInterceptors = List.of();
   class="kw">private VoiceRouter voiceRouter;
   class="kw">private class="kw">static class="kw">final int VOICE_THREAD_POOL_SIZE = 4;
   class="kw">private class="kw">final ExecutorService[] voiceExecutors;
   class="kw">private class="kw">volatile boolean isShutdown = false;
   class="kw">private class="kw">final ConcurrentHashMap<UUID, VoiceModule.PositionSnapshot> positionCache = new ConcurrentHashMap<>();
   class="kw">private ScheduledFuture<?> positionUpdateTask;
   class="kw">private class="kw">final Set<ClipPlayback> activeClips = ConcurrentHashMap.newKeySet();
   class="kw">private class="kw">final Object clipPumpLock = new Object();
   class="kw">private ScheduledFuture<?> clipPumpTask;

   class="kw">public class="kw">static VoiceModule get() {
      class="kw">return instance;
   }

   class="kw">public VoiceModule(@Nonnull JavaPluginInit var1) {
      super(var1);
      instance = this;
      this.voiceExecutors = new ExecutorService[4];

      for (int var2 = 0; var2 < 4; var2++) {
         this.voiceExecutors[var2] = Executors.newSingleThreadExecutor(ThreadUtil.daemon("VoiceRouter-" + var2));
      }
   }

   @Override
   class="kw">protected void setup() {
      if (Constants.SINGLEPLAYER) {
         this.config.get().setVoiceEnabled(false);
      }

      this.voiceRouter = new VoiceRouter(this);
      this.getCommandRegistry().registerCommand(new VoiceCommand());
      ServerManager.get().registerSubPacketHandlers(VoicePacketHandler::new);
      StreamManager.getInstance().registerHandler(StreamType.Voice, VoiceStreamHandler::new);
      this.getLogger().at(Level.INFO).log("[Voice] Registered voice stream handler");
      this.getEventRegistry().register(PlayerConnectEvent.class, this::onPlayerConnect);
      this.getEventRegistry().register(PlayerDisconnectEvent.class, this::onPlayerDisconnect);
      if (Constants.SINGLEPLAYER) {
         this.getEventRegistry().register(SingleplayerRequestAccessEvent.class, this::onServerAccessChanged);
      }

      this.getLogger()
         .at(Level.INFO)
         .log(
            "[Voice] VoiceModule initialized (maxDistance=%.1f, refDistance=%.1f, enabled=%s, voiceStreamSupported=true)",
            this.getMaxHearingDistance(),
            this.getReferenceDistance(),
            this.isVoiceEnabled()
         );
   }

   @Override
   class="kw">protected void start() {
      this.positionUpdateTask = HytaleServer.SCHEDULED_EXECUTOR.scheduleAtFixedRate(this::updateAllPlayerPositions, 100L, 100L, TimeUnit.MILLISECONDS);
      this.getLogger().at(Level.INFO).log("[Voice] Started position cache update task (%dms interval)", 100L);
   }

   class="kw">private void updateAllPlayerPositions() {
      if (!this.isShutdown) {
         HashMap var1 = new HashMap<>();

         for (Entry var3 : this.playerStates.entrySet()) {
            UUID var4 = var3.getKey();
            PlayerRef var5 = Universe.get().getPlayer(var4);
            if (var5 != null) {
               World var6 = this.resolveWorld(var5.getReference());
               if (var6 != null) {
                  var1.computeIfAbsent(var6, var0 -> new ArrayList<>()).add(var4);
               }
            }
         }

         HashMap var7 = new HashMap<>();

         for (VoiceSpeaker var11 : this.customSpeakers.values()) {
            if (var11.isOpen()) {
               Ref var14 = var11.entityRef();
               if (var14 != null) {
                  World var16 = this.resolveWorld(var14);
                  if (var16 == null) {
                     if (!var14.isValid()) {
                        var11.close();
                     } else {
                        this.positionCache.remove(var11.id());
                     }
                  } else {
                     var7.computeIfAbsent(var16, var0 -> new ArrayList<>()).add(var11);
                  }
               }
            }
         }

         for (Entry var12 : var1.entrySet()) {
            World var15 = var12.getKey();
            this.scheduleWorldSample(var15, var12.getValue(), var7.remove(var15));
         }

         for (Entry var13 : var7.entrySet()) {
            this.scheduleWorldSample(var13.getKey(), null, var13.getValue());
         }
      }
   }

   class="kw">private void executeOnWorldOrSkip(@Nonnull World var1, @Nonnull String var2, @Nonnull Runnable var3) {
      try {
         var1.execute(var3);
      } catch (RuntimeException var5) {
         ((HytaleLogger.Api)this.getLogger().at(Level.FINE).withCause(var5)).log("[Voice] Skipped %s for an unavailable world", var2);
      }
   }

   class="kw">private void scheduleWorldSample(@Nonnull World var1, @Nullable List<UUID> var2, @Nullable List<VoiceSpeaker> var3) {
      this.executeOnWorldOrSkip(
         var1,
         "voice position sample",
         () -> {
            if (var2 != null) {
               for (UUID var5 : var2) {
                  try {
                     this.samplePlayerPositionOnWorldThread(var1, var5);
                  } catch (RuntimeException var8) {
                     ((HytaleLogger.Api)this.getLogger().at(Level.WARNING).withCause(var8)).log("[Voice] Failed to sample voice position for player %s", var5);
                  }
               }
            }

            if (var3 != null) {
               for (VoiceSpeaker var10 : var3) {
                  try {
                     this.updateEntitySpeakerPositionCache(var10, var1);
                  } catch (RuntimeException var7) {
                     ((HytaleLogger.Api)this.getLogger().at(Level.WARNING).withCause(var7))
                        .log("[Voice] Failed to sample voice position for speaker %s", var10.id());
                  }
               }
            }
         }
      );
   }

   @Nullable
   class="kw">private PlayerRef samplePlayerPositionOnWorldThread(@Nonnull World var1, @Nonnull UUID var2) {
      PlayerRef var3 = Universe.get().getPlayer(var2);
      if (var3 == null) {
         class="kw">return null;
      }

      Ref var4 = var3.getReference();
      if (var4 != null && var4.isValid()) {
         Store var5 = var4.getStore();
         if (var5 == null) {
            class="kw">return null;
         }

         EntityStore var6 = var5.getExternalData();
         if (var6 == null) {
            class="kw">return null;
         }

         World var7 = var6.getWorld();
         if (var7 != var1) {
            UUID var14 = var1.getWorldConfig().getUuid();
            this.positionCache.computeIfPresent(var2, (var1x, var2x) -> (VoiceModule.PositionSnapshot)(var2x.worldId().equals(var14) ? null : var2x));
            this.voiceRouter.removePlayerFromWorldSet(var2, var14);
            class="kw">return null;
         }

         TransformComponent var8 = var5.getComponent(var4, EntityModule.get().getTransformComponentType());
         if (var8 == null) {
            class="kw">return null;
         }

         float var9 = ModelComponent.getEyeHeight(var4, var5);
         boolean var10 = this.isEyeInFluid(var8.getPosition(), var9, var7);
         int var11 = entityNetworkId(var4, var5);
         boolean var12 = var5.getComponent(var4, DeathComponent.getComponentType()) != null;
         UUID var13 = var7.getWorldConfig().getUuid();
         this.voiceRouter.updateSpeakerPositionCache(var3, var8.getPosition(), var9, var10, var13, var11, var12);
         class="kw">return var3;
      } else {
         class="kw">return null;
      }
   }

   @Nullable
   class="kw">private World resolveWorld(@Nullable Ref<EntityStore> var1) {
      if (var1 == null) {
         class="kw">return null;
      }

      Store var2 = var1.getStore();
      if (var2 == null) {
         class="kw">return null;
      }

      EntityStore var3 = var2.getExternalData();
      class="kw">return var3 != null ? var3.getWorld() : null;
   }

   class="kw">private void updateEntitySpeakerPositionCache(@Nonnull VoiceSpeaker var1, @Nonnull World var2) {
      if (var1.isOpen()) {
         Ref var3 = var1.entityRef();
         if (var3 != null && var3.isValid()) {
            Store var4 = var3.getStore();
            if (var4 == null) {
               var1.close();
            } else {
               EntityStore var5 = var4.getExternalData();
               World var6 = var5 != null ? var5.getWorld() : null;
               if (var6 != null && var6 == var2) {
                  TransformComponent var13 = var4.getComponent(var3, EntityModule.get().getTransformComponentType());
                  if (var13 == null) {
                     this.positionCache.remove(var1.id());
                  } else {
                     float var8 = ModelComponent.getEyeHeight(var3, var4);
                     boolean var9 = this.isEyeInFluid(var13.getPosition(), var8, var6);
                     int var10 = entityNetworkId(var3, var4);
                     UUID var11 = var6.getWorldConfig().getUuid();
                     VoiceModule.PositionSnapshot var12 = VoiceModule.PositionSnapshot.atEyeHeight(var13.getPosition(), var8, var9, var11, var10, false);
                     this.positionCache.compute(var1.id(), (var2x, var3x) -> var1.isOpen() ? var12 : null);
                  }
               } else {
                  UUID var7 = var2.getWorldConfig().getUuid();
                  this.positionCache.computeIfPresent(var1.id(), (var1x, var2x) -> (VoiceModule.PositionSnapshot)(var2x.worldId().equals(var7) ? null : var2x));
               }
            }
         } else {
            var1.close();
         }
      }
   }

   @Override
   class="kw">protected void shutdown() {
      this.isShutdown = true;
      if (this.positionUpdateTask != null) {
         this.positionUpdateTask.cancel(false);
      }

      List var1;
      class="kw">synchronized (this.clipPumpLock) {
         if (this.clipPumpTask != null) {
            this.clipPumpTask.cancel(false);
            this.clipPumpTask = null;
         }

         var1 = new ArrayList<>(this.activeClips);
         this.activeClips.clear();
      }

      for (ClipPlayback var3 : var1) {
         var3.cancel();
      }

      for (ExecutorService var5 : this.voiceExecutors) {
         var5.shutdown();
      }

      try {
         for (ExecutorService var20 : this.voiceExecutors) {
            if (!var20.awaitTermination(5L, TimeUnit.SECONDS)) {
               this.getLogger().at(Level.WARNING).log("[Voice] VoiceExecutor did not terminate in time, forcing shutdown");
               var20.shutdownNow();
            }
         }
      } catch (InterruptedException var7) {
         this.getLogger().at(Level.WARNING).log("[Voice] VoiceExecutor shutdown interrupted");

         for (ExecutorService var6 : this.voiceExecutors) {
            var6.shutdownNow();
         }

         Thread.currentThread().interrupt();
      }

      for (VoiceSpeaker var16 : new ArrayList<>(this.customSpeakers.values())) {
         var16.close();
      }

      this.playerStates.clear();
      this.positionCache.clear();
      this.voiceChannels.clear();
      this.getLogger().at(Level.INFO).log("[Voice] VoiceModule shutting down");
   }

   class="kw">private void onServerAccessChanged(@Nonnull SingleplayerRequestAccessEvent var1) {
      if (var1.getAccess() != Access.Private && !this.isVoiceEnabled()) {
         this.setVoiceEnabled(true);
         this.getLogger().at(Level.INFO).log("[Voice] Auto-enabled voice for %s play", var1.getAccess());
      } else if (var1.getAccess() == Access.Private && this.isVoiceEnabled()) {
         this.setVoiceEnabled(false);
         this.getLogger().at(Level.INFO).log("[Voice] Auto-disabled voice after returning to singleplayer");
      }
   }

   class="kw">private void onPlayerConnect(@Nonnull PlayerConnectEvent var1) {
      PlayerRef var2 = var1.getPlayerRef();
      VoicePlayerState var3 = new VoicePlayerState(var2.getUuid(), this.getLogger(), 25);
      this.playerStates.put(var2.getUuid(), var3);
      this.getLogger().at(Level.FINE).log("[Voice] Player connected: %s (%s), totalPlayers=%d", var2.getUsername(), var2.getUuid(), this.playerStates.size());
      this.voiceRouter.sendVoiceConfig(var2);
      this.scheduleImmediatePositionUpdate(var2);
   }

   class="kw">public void scheduleImmediatePositionUpdate(@Nonnull PlayerRef var1) {
      UUID var2 = var1.getUuid();
      Ref var3 = var1.getReference();
      if (var3 != null) {
         Store var4 = var3.getStore();
         if (var4 != null) {
            EntityStore var5 = var4.getExternalData();
            if (var5 != null) {
               World var6 = var5.getWorld();
               if (var6 != null) {
                  this.executeOnWorldOrSkip(var6, "immediate player voice sample", () -> {
                     PlayerRef var3 = this.samplePlayerPositionOnWorldThread(var6, var2);
                     if (var3 != null) {
                        this.getLogger().at(Level.FINE).log("[Voice] Immediate position cache populated for %s", var3.getUsername());
                     }
                  });
               }
            }
         }
      }
   }

   class="kw">private void onPlayerDisconnect(@Nonnull PlayerDisconnectEvent var1) {
      PlayerRef var2 = var1.getPlayerRef();
      VoicePlayerState var3 = this.playerStates.remove(var2.getUuid());
      this.positionCache.remove(var2.getUuid());
      this.voiceRouter.removePlayerFromWorldSets(var2.getUuid());
      this.setPlayerVoiceChannel(var2.getUuid(), null);
      String var4 = var3 != null ? var3.getStatsString() : "no state";
      this.getLogger()
         .at(Level.FINE)
         .log("[Voice] Player disconnected: %s (%s), stats=[%s], remainingPlayers=%d", var2.getUsername(), var2.getUuid(), var4, this.playerStates.size());
   }

   @Nullable
   class="kw">public VoicePlayerState getPlayerState(@Nonnull UUID var1) {
      class="kw">return this.playerStates.get(var1);
   }

   class="kw">public void setPlayerVoiceChannel(@Nonnull UUID var1, @Nullable String var2) {
      this.voiceChannels.setChannel(var1, var2);
   }

   @Nonnull
   VoiceChannels getVoiceChannels() {
      class="kw">return this.voiceChannels;
   }

   class="kw">public VoiceRouter getVoiceRouter() {
      class="kw">return this.voiceRouter;
   }

   @Nonnull
   class="kw">public Registration addPlayerVoiceInterceptor(@Nonnull PlayerVoiceInterceptor var1) {
      class="kw">return this.addPlayerVoiceInterceptor(EventPriority.NORMAL, var1);
   }

   @Nonnull
   class="kw">public Registration addPlayerVoiceInterceptor(@Nonnull EventPriority var1, @Nonnull PlayerVoiceInterceptor var2) {
      VoiceModule.RegisteredInterceptor var3 = new VoiceModule.RegisteredInterceptor(var1.getValue(), var2);
      class="kw">synchronized (this.playerVoiceInterceptorLock) {
         ArrayList var5 = new ArrayList<>(this.playerVoiceInterceptors);
         var5.add(var3);
         var5.sort(Comparator.comparingInt(VoiceModule.RegisteredInterceptor::priority));
         this.playerVoiceInterceptors = var5;
      }

      class="kw">return new Registration(() -> true, () -> {
         class="kw">synchronized (this.playerVoiceInterceptorLock) {
            ArrayList var3 = new ArrayList<>(this.playerVoiceInterceptors);
            var3.remove(var3);
            this.playerVoiceInterceptors = var3;
         }
      });
   }

   boolean hasPlayerVoiceInterceptors() {
      class="kw">return !this.playerVoiceInterceptors.isEmpty();
   }

   void runPlayerVoiceInterceptors(@Nonnull PlayerVoiceFrame var1) {
      for (VoiceModule.RegisteredInterceptor var3 : this.playerVoiceInterceptors) {
         PlayerVoiceInterceptor var4 = var3.interceptor();

         try {
            var4.intercept(var1);
         } catch (RuntimeException var6) {
            ((HytaleLogger.Api)this.getLogger().at(Level.WARNING).withCause(var6))
               .log("[Voice] Player voice interceptor %s threw and was skipped for this frame", var4.getClass().getName());
         }
      }
   }

   @Nonnull
   class="kw">public VoiceSpeaker openEntityVoice(@Nonnull Ref<EntityStore> var1) {
      EntityVoiceSpeaker var2 = this.registerSpeaker(new EntityVoiceSpeaker(this, newVoiceStreamId(), var1));
      this.scheduleImmediateEntitySpeakerUpdate(var2);
      class="kw">return var2;
   }

   class="kw">private void scheduleImmediateEntitySpeakerUpdate(@Nonnull VoiceSpeaker var1) {
      Ref var2 = var1.entityRef();
      if (var2 != null) {
         World var3 = this.resolveWorld(var2);
         if (var3 != null) {
            this.executeOnWorldOrSkip(var3, "immediate entity voice sample", () -> this.updateEntitySpeakerPositionCache(var1, var3));
         }
      }
   }

   @Nonnull
   class="kw">public PositionalVoiceSpeaker openPositionalVoice(@Nonnull World var1, @Nonnull Vector3d var2) {
      UUID var3 = var1.getWorldConfig().getUuid();
      class="kw">return this.registerSpeaker(new PositionalVoiceSpeaker(this, newVoiceStreamId(), var3, var2));
   }

   @Nonnull
   class="kw">public VoiceSpeaker openDirectVoice(@Nonnull Collection<UUID> var1) {
      class="kw">return this.registerSpeaker(new DirectVoiceSpeaker(this, newVoiceStreamId(), var1));
   }

   @Nonnull
   class="kw">private <T class="kw">extends VoiceSpeaker> T registerSpeaker(@Nonnull T var1) {
      this.customSpeakers.put(var1.id(), var1);
      this.getLogger().at(Level.FINE).log("[Voice] Opened custom voice speaker %s", var1.id());
      class="kw">return var1;
   }

   class="kw">private class="kw">static UUID newVoiceStreamId() {
      class="kw">return UUIDUtil.generateVersion8UUID();
   }

   void removeSpeaker(@Nonnull UUID var1) {
      this.customSpeakers.remove(var1);
      this.positionCache.remove(var1);
   }

   @Nonnull
   ClipPlayback startClip(@Nonnull VoiceSpeaker var1, @Nonnull List<byte[]> var2) {
      ClipPlayback var3 = new ClipPlayback(var1, var2);
      boolean var4 = false;
      class="kw">synchronized (this.clipPumpLock) {
         if (!this.isShutdown) {
            this.activeClips.add(var3);
            if (this.clipPumpTask == null) {
               this.clipPumpTask = HytaleServer.SCHEDULED_EXECUTOR.scheduleAtFixedRate(this::pumpClips, 0L, 20L, TimeUnit.MILLISECONDS);
            }

            var4 = true;
         }
      }

      if (!var4) {
         var3.cancel();
      }

      class="kw">return var3;
   }

   class="kw">private void pumpClips() {
      Iterator var1 = this.activeClips.iterator();

      while (var1.hasNext()) {
         ClipPlayback var2 = var1.next();

         boolean var3;
         try {
            var3 = var2.advance();
         } catch (RuntimeException var7) {
            ((HytaleLogger.Api)this.getLogger().at(Level.WARNING).withCause(var7)).log("[Voice] Clip pump error, dropping clip");
            var2.fail(var7);
            var3 = false;
         }

         if (!var3) {
            var1.remove();
         }
      }

      class="kw">synchronized (this.clipPumpLock) {
         if (this.activeClips.isEmpty() && this.clipPumpTask != null) {
            this.clipPumpTask.cancel(false);
            this.clipPumpTask = null;
         }
      }
   }

   class="kw">public boolean isVoiceEnabled() {
      class="kw">return this.config.get().isVoiceEnabled();
   }

   class="kw">public void setVoiceEnabled(boolean var1) {
      boolean var2 = this.config.get().isVoiceEnabled();
      this.config.get().setVoiceEnabled(var1);
      if (var2 != var1) {
         this.getLogger().at(Level.INFO).log("[Voice] Voice enabled changed: %s -> %s", var2, var1);
         this.broadcastConfigToAllPlayers();
         this.config.save();
      }
   }

   class="kw">public boolean isDeadPlayersCanHear() {
      class="kw">return this.config.get().isDeadPlayersCanHear();
   }

   class="kw">public float getMaxHearingDistance() {
      class="kw">return this.config.get().getMaxHearingDistance();
   }

   class="kw">public void setMaxHearingDistance(float var1) {
      float var2 = this.config.get().getMaxHearingDistance();
      this.config.get().setMaxHearingDistance(var1);
      if (var2 != var1) {
         this.getLogger().at(Level.INFO).log("[Voice] Max hearing distance changed: %.1f -> %.1f", var2, var1);
         this.broadcastConfigToAllPlayers();
         this.config.save();
      }
   }

   class="kw">public float getReferenceDistance() {
      class="kw">return this.config.get().getFullVolumeDistance();
   }

   class="kw">public void setReferenceDistance(float var1) {
      float var2 = this.config.get().getFullVolumeDistance();
      this.config.get().setFullVolumeDistance(var1);
      if (var2 != var1) {
         this.getLogger().at(Level.INFO).log("[Voice] Full volume distance changed: %.1f -> %.1f", var2, var1);
         this.broadcastConfigToAllPlayers();
         this.config.save();
      }
   }

   class="kw">private void broadcastConfigToAllPlayers() {
      for (Entry var2 : this.playerStates.entrySet()) {
         PlayerRef var3 = Universe.get().getPlayer(var2.getKey());
         if (var3 != null) {
            this.voiceRouter.sendVoiceConfig(var3);
         }
      }
   }

   class="kw">private void broadcastMuteUpdate(@Nonnull UUID var1, boolean var2) {
      this.broadcastConfigToAllPlayers();
      this.getLogger().at(Level.INFO).log("[Voice] Broadcast config update for mute change: playerId=%s, isMuted=%s", var1, var2);
   }

   class="kw">public boolean isPlayerMuted(@Nonnull UUID var1) {
      class="kw">return this.config.get().isPlayerMuted(var1);
   }

   class="kw">public boolean mutePlayer(@Nonnull UUID var1) {
      boolean var2 = this.config.get().mutePlayer(var1);
      if (var2) {
         this.getLogger().at(Level.INFO).log("[Voice] Player globally muted: %s", var1);
         this.broadcastMuteUpdate(var1, true);
         this.config.save();
      }

      class="kw">return var2;
   }

   class="kw">public boolean unmutePlayer(@Nonnull UUID var1) {
      boolean var2 = this.config.get().unmutePlayer(var1);
      if (var2) {
         this.getLogger().at(Level.INFO).log("[Voice] Player globally unmuted: %s", var1);
         this.broadcastMuteUpdate(var1, false);
         this.config.save();
      }

      class="kw">return var2;
   }

   class="kw">public Set<UUID> getGloballyMutedPlayers() {
      class="kw">return this.config.get().getMutedPlayers();
   }

   class="kw">public int getMaxPacketsPerSecond() {
      class="kw">return 60;
   }

   class="kw">public int getBurstCapacity() {
      class="kw">return 25;
   }

   class="kw">public int getMaxPacketSize() {
      class="kw">return 1024;
   }

   class="kw">private class="kw">static int entityNetworkId(@Nonnull Ref<EntityStore> var0, @Nonnull ComponentAccessor<EntityStore> var1) {
      NetworkId var2 = var1.getComponent(var0, NetworkId.getComponentType());
      class="kw">return var2 != null ? var2.getId() : 0;
   }

   class="kw">private boolean isEyeInFluid(@Nonnull Vector3d var1, float var2, @Nonnull World var3) {
      int var4 = MathUtil.floor(var1.x());
      int var5 = MathUtil.floor(var1.y() + var2);
      int var6 = MathUtil.floor(var1.z());
      ChunkStore var7 = var3.getChunkStore();
      long var8 = ChunkUtil.indexChunkFromBlock(var4, var6);
      Ref var10 = var7.getChunkReference(var8);
      if (var10 != null && var10.isValid()) {
         Store var11 = var7.getStore();
         ChunkColumn var12 = var11.getComponent(var10, ChunkColumn.getComponentType());
         class="kw">return var12 == null ? false : WorldUtil.getFluidIdAtPosition(var11, var12, var4, var5, var6) != 0;
      } else {
         class="kw">return false;
      }
   }

   void updatePositionCache(@Nonnull UUID var1, @Nonnull VoiceModule.PositionSnapshot var2) {
      this.positionCache.put(var1, var2);
   }

   @Nullable
   class="kw">public VoiceModule.PositionSnapshot getCachedPosition(@Nonnull UUID var1) {
      class="kw">return this.positionCache.get(var1);
   }

   class="kw">public ExecutorService getVoiceExecutor(@Nonnull UUID var1) {
      int var2 = Math.floorMod(var1.hashCode(), 4);
      class="kw">return this.voiceExecutors[var2];
   }

   class="kw">public boolean isShutdown() {
      class="kw">return this.isShutdown;
   }

   class="kw">public Map<UUID, VoicePlayerState> getPlayerStates() {
      class="kw">return this.playerStates;
   }

   class="kw">public record PositionSnapshot(@Nonnull Vector3dc position, boolean isUnderwater, @Nonnull UUID worldId, int networkId, boolean isDead) {
      class="kw">public PositionSnapshot {
      }

      class="kw">static VoiceModule.PositionSnapshot atEyeHeight(@Nonnull Vector3dc var0, float var1, boolean var2, @Nonnull UUID var3, int var4, boolean var5) {
         Vector3d var6 = new Vector3d(var0.x(), var0.y() + var1, var0.z());
         class="kw">return new VoiceModule.PositionSnapshot(var6, var2, var3, var4, var5);
      }
   }

   class="kw">private record RegisteredInterceptor(int priority, @Nonnull PlayerVoiceInterceptor interceptor) {
      class="kw">private RegisteredInterceptor {
      }
   }
}