MarkerReference interface

Пакет: com.hypixel.hytale.server.core.universe.world.worldmap

Файл: com/hypixel/hytale/server/core/universe/world/worldmap/WorldMapManager.java

Поля (1)

МодификаторыТипИмя
CodecMapCodec<WorldMapManager.MarkerReference> CODEC

Методы (2)

МодификаторыВозвратСигнатура
abstract String getMarkerIdString getMarkerId()
abstract void removevoid remove()

Исходный код

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

class="kw">import com.hypixel.fastutil.longs.Long2ObjectConcurrentHashMap;
class="kw">import com.hypixel.hytale.codec.Codec;
class="kw">import com.hypixel.hytale.codec.KeyedCodec;
class="kw">import com.hypixel.hytale.codec.builder.BuilderCodec;
class="kw">import com.hypixel.hytale.codec.lookup.CodecMapCodec;
class="kw">import com.hypixel.hytale.common.util.CompletableFutureUtil;
class="kw">import com.hypixel.hytale.component.Ref;
class="kw">import com.hypixel.hytale.component.Store;
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.Color;
class="kw">import com.hypixel.hytale.protocol.packets.player.RemoveMapMarker;
class="kw">import com.hypixel.hytale.protocol.packets.worldmap.CreateUserMarker;
class="kw">import com.hypixel.hytale.protocol.packets.worldmap.MapImage;
class="kw">import com.hypixel.hytale.protocol.packets.worldmap.MapMarker;
class="kw">import com.hypixel.hytale.server.core.HytaleServer;
class="kw">import com.hypixel.hytale.server.core.Message;
class="kw">import com.hypixel.hytale.server.core.config.ServerWorldMapConfig;
class="kw">import com.hypixel.hytale.server.core.config.WorldWorldMapConfig;
class="kw">import com.hypixel.hytale.server.core.entity.entities.Player;
class="kw">import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerConfigData;
class="kw">import com.hypixel.hytale.server.core.entity.entities.player.data.PlayerWorldData;
class="kw">import com.hypixel.hytale.server.core.modules.entity.component.DisplayNameComponent;
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.map.WorldMap;
class="kw">import com.hypixel.hytale.server.core.universe.world.storage.EntityStore;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MapMarkerOverride;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.markers.MarkersCollector;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.DeathMarkerProvider;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.OtherPlayersMarkerProvider;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.POIMarkerProvider;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.PersonalMarkersProvider;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.RespawnMarkerProvider;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.SharedMarkersProvider;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.markers.providers.SpawnMarkerProvider;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.markers.user.UserMapMarker;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.markers.user.UserMapMarkersStore;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.markers.user.UserMarkerValidator;
class="kw">import com.hypixel.hytale.server.core.universe.world.worldmap.markers.worldstore.WorldMarkersResource;
class="kw">import com.hypixel.hytale.server.core.util.thread.TickingThread;
class="kw">import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
class="kw">import it.unimi.dsi.fastutil.longs.LongSet;
class="kw">import it.unimi.dsi.fastutil.longs.LongSets;
class="kw">import it.unimi.dsi.fastutil.longs.Long2ObjectMap.Entry;
class="kw">import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
class="kw">import it.unimi.dsi.fastutil.objects.Object2ObjectMaps;
class="kw">import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
class="kw">import it.unimi.dsi.fastutil.objects.ObjectIterator;
class="kw">import java.util.ArrayList;
class="kw">import java.util.List;
class="kw">import java.util.Map;
class="kw">import java.util.UUID;
class="kw">import java.util.concurrent.CompletableFuture;
class="kw">import java.util.concurrent.ConcurrentHashMap;
class="kw">import java.util.concurrent.atomic.AtomicInteger;
class="kw">import java.util.logging.Level;
class="kw">import javax.annotation.Nonnull;
class="kw">import javax.annotation.Nullable;

class="kw">public class WorldMapManager class="kw">extends TickingThread {
   class="kw">private class="kw">static class="kw">final int IMAGE_KEEP_ALIVE = 60;
   class="kw">private class="kw">static class="kw">final float DEFAULT_UNLOAD_DELAY = 1.0F;
   class="kw">private class="kw">static class="kw">final int MAX_GENERATIONS_PER_TICK = 64;
   @Nonnull
   class="kw">private class="kw">final HytaleLogger logger;
   @Nonnull
   class="kw">private class="kw">final World world;
   class="kw">private class="kw">final Long2ObjectConcurrentHashMap<WorldMapManager.ImageEntry> images = new Long2ObjectConcurrentHashMap<>(
      true, ChunkUtil.indexChunk(Integer.MIN_VALUE, Integer.MIN_VALUE)
   );
   class="kw">private class="kw">final Long2ObjectConcurrentHashMap<CompletableFuture<MapImage>> generating = new Long2ObjectConcurrentHashMap<>(
      true, ChunkUtil.indexChunk(Integer.MIN_VALUE, Integer.MIN_VALUE)
   );
   class="kw">private class="kw">final Long2ObjectConcurrentHashMap<CompletableFuture<MapImage>> generationQueue = new Long2ObjectConcurrentHashMap<>(
      true, ChunkUtil.indexChunk(Integer.MIN_VALUE, Integer.MIN_VALUE)
   );
   class="kw">private class="kw">final Map<String, WorldMapManager.MarkerProvider> markerProviders = new ConcurrentHashMap<>();
   class="kw">private class="kw">final Map<String, MapMarker> pointsOfInterest = new ConcurrentHashMap<>();
   class="kw">private class="kw">final Map<String, MapMarkerOverride> markerOverrides = new ConcurrentHashMap<>();
   class="kw">private class="kw">final Object2ObjectMap<String, MapMarkerOverride> markerOverridesLocal = new Object2ObjectOpenHashMap();
   class="kw">private class="kw">final Object2ObjectMap<String, MapMarkerOverride> markerOverridesLocalView = Object2ObjectMaps.unmodifiable(this.markerOverridesLocal);
   @Nonnull
   class="kw">private WorldMapSettings worldMapSettings = WorldMapSettings.DISABLED;
   @Nullable
   class="kw">private IWorldMap generator;
   @Nonnull
   class="kw">private CompletableFuture<Void> generatorLoaded = new CompletableFuture<>();
   class="kw">private float unloadDelay = 1.0F;

   class="kw">public WorldMapManager(@Nonnull World var1) {
      super("WorldMap - " + var1.getName(), 10, true);
      this.logger = HytaleLogger.get("World|" + var1.getName() + "|M");
      this.world = var1;
      this.addMarkerProvider("spawn", SpawnMarkerProvider.INSTANCE);
      this.addMarkerProvider("playerIcons", OtherPlayersMarkerProvider.INSTANCE);
      this.addMarkerProvider("death", DeathMarkerProvider.INSTANCE);
      this.addMarkerProvider("respawn", RespawnMarkerProvider.INSTANCE);
      this.addMarkerProvider("personal", PersonalMarkersProvider.INSTANCE);
      this.addMarkerProvider("shared", SharedMarkersProvider.INSTANCE);
      this.addMarkerProvider("poi", POIMarkerProvider.INSTANCE);
   }

   @Nullable
   class="kw">public IWorldMap getGenerator() {
      class="kw">return this.generator;
   }

   class="kw">public void setGenerator(@Nullable IWorldMap var1) {
      boolean var2 = this.shouldTick();
      if (this.generator != null) {
         this.generator.shutdown();
      }

      this.generator = var1;
      if (var1 != null) {
         this.logger.at(Level.INFO).log("Initializing world map generator: %s", var1.toString());
         this.generatorLoaded.complete(null);
         this.generatorLoaded = new CompletableFuture<>();
         this.applyWorldMapOverrides(var1);
         this.images.clear();
         this.generating.clear();
         this.cancelQueuedGenerations();

         for (Player var4 : this.world.getPlayers()) {
            var4.getWorldMapTracker().clear();
         }

         this.updateTickingState(var2);
         this.sendSettings();
         this.logger.at(Level.INFO).log("Generating Points of Interest...");
         CompletableFutureUtil._catch(var1.generatePointsOfInterest(this.world).thenAcceptAsync(var1x -> {
            this.pointsOfInterest.putAll((Map<? class="kw">extends String, ? class="kw">extends MapMarker>)var1x);
            this.logger.at(Level.INFO).log("Finished Generating Points of Interest!");
         }));
      } else {
         this.logger.at(Level.INFO).log("World map disabled!");
         this.worldMapSettings = WorldMapSettings.DISABLED;
         this.sendSettings();
      }
   }

   class="kw">private void applyWorldMapOverrides(@Nonnull IWorldMap var1) {
      WorldMapSettings var2 = var1.getWorldMapSettings();
      int var3 = var2.getViewRadiusMin();
      int var4 = var2.getViewRadiusMax();
      WorldWorldMapConfig var5 = this.world.getWorldConfig().getWorldMapConfig();
      if (var5 != null) {
         var3 = var5.getViewRadiusMin();
         var4 = var5.getViewRadiusMax();
      }

      ServerWorldMapConfig var6 = HytaleServer.get().getConfig().getWorldMapConfig();
      var3 = Math.max(var3, var6.getViewRadiusMin());
      var4 = Math.min(var4, var6.getViewRadiusMax());
      if (var3 > var4) {
         var3 = var4;
      }

      this.worldMapSettings = var2.withViewRadiusLimits(var3, var4);
   }

   @Override
   class="kw">protected boolean isIdle() {
      class="kw">return this.world.getPlayerCount() == 0;
   }

   @Override
   class="kw">protected void tick(float var1) {
      this.markerOverridesLocal.clear();
      this.markerOverridesLocal.putAll(this.markerOverrides);

      for (Player var3 : this.world.getPlayers()) {
         var3.getWorldMapTracker().tick(var1);
      }

      this.flushGenerationQueue();
      this.unloadDelay -= var1;
      if (this.unloadDelay <= 0.0F) {
         this.unloadDelay = 1.0F;
         this.unloadImages();
      }
   }

   @Override
   class="kw">protected void onShutdown() {
   }

   class="kw">private void flushGenerationQueue() {
      if (this.generator != null && !this.generationQueue.isEmpty()) {
         Long2ObjectOpenHashMap var1 = new Long2ObjectOpenHashMap(64);
         ObjectIterator var2 = this.generationQueue.long2ObjectEntrySet().iterator();

         while (var2.hasNext() && var1.size() < 64) {
            Entry var3 = (Entry<CompletableFuture<MapImage>>)var2.next();
            var1.put(var3.getLongKey(), (CompletableFuture)var3.getValue());
            var2.remove();
         }

         if (!var1.isEmpty()) {
            int var5 = MathUtil.fastFloor(32.0F * this.worldMapSettings.getImageScale());
            LongSet var4 = LongSets.unmodifiable(new LongOpenHashSet(var1.keySet()));
            this.generator.generate(this.world, var5, var5, var4).handle((var2x, var3x) -> {
               if (var3x != null) {
                  ((HytaleLogger.Api)this.logger.at(Level.SEVERE).withCause(var3x)).log("World map generation batch failed");
               }

               this.completeBatch(var1, var3x != null ? null : var2x);
               class="kw">return null;
            });
         }
      }
   }

   class="kw">private void cancelQueuedGenerations() {
      ObjectIterator var1 = this.generationQueue.long2ObjectEntrySet().iterator();

      while (var1.hasNext()) {
         ((CompletableFuture)((Entry)var1.next()).getValue()).complete(null);
      }

      this.generationQueue.clear();
   }

   class="kw">private void completeBatch(@Nonnull Long2ObjectOpenHashMap<CompletableFuture<MapImage>> var1, @Nullable WorldMap var2) {
      ObjectIterator var3 = var1.long2ObjectEntrySet().iterator();

      while (var3.hasNext()) {
         Entry var4 = (Entry<CompletableFuture<MapImage>>)var3.next();
         long var5 = var4.getLongKey();
         MapImage var7 = var2 != null ? (MapImage)var2.getChunks().get(var5) : null;
         if (this.generating.remove(var5) != null && var7 != null) {
            this.images.put(var5, new WorldMapManager.ImageEntry(var7));
         }

         ((CompletableFuture)var4.getValue()).complete(var7);
      }
   }

   class="kw">public void unloadImages() {
      int var1 = this.images.size();
      if (var1 != 0) {
         List var2 = this.world.getPlayers();
         LongSet var3 = new LongOpenHashSet();
         this.images.forEach((var3x, var5) -> {
            if (this.isWorldMapEnabled() && isWorldMapImageVisibleToAnyPlayer(var2, var3x, this.worldMapSettings)) {
               var5.keepAlive.set(60);
            } else {
               if (var5.keepAlive.decrementAndGet() <= 0) {
                  var3.add(var3x);
               }
            }
         });
         if (!var3.isEmpty()) {
            var3.forEach(var1x -> {
               this.logger.at(Level.FINE).log("Unloading world map image: %s", var1x);
               this.images.remove(var1x);
            });
         }

         int var4 = var3.size();
         if (var4 > 0) {
            this.logger.at(Level.FINE).log("Cleaned %s world map images from memory, with %s images remaining in memory.", var4, var1 - var4);
         }
      }
   }

   class="kw">public boolean isWorldMapEnabled() {
      class="kw">return this.worldMapSettings.getSettingsPacket().enabled;
   }

   class="kw">public class="kw">static boolean isWorldMapImageVisibleToAnyPlayer(@Nonnull List<Player> var0, long var1, @Nonnull WorldMapSettings var3) {
      for (Player var5 : var0) {
         int var6 = var3.getViewRadius(var5.getViewRadius());
         if (var5.getWorldMapTracker().shouldBeVisible(var6, var1)) {
            class="kw">return true;
         }
      }

      class="kw">return false;
   }

   @Nonnull
   class="kw">public World getWorld() {
      class="kw">return this.world;
   }

   @Nonnull
   class="kw">public WorldMapSettings getWorldMapSettings() {
      class="kw">return this.worldMapSettings;
   }

   class="kw">public Map<String, WorldMapManager.MarkerProvider> getMarkerProviders() {
      class="kw">return this.markerProviders;
   }

   class="kw">public void addMarkerProvider(@Nonnull String var1, @Nonnull WorldMapManager.MarkerProvider var2) {
      this.markerProviders.put(var1, var2);
   }

   class="kw">public Map<String, MapMarker> getPointsOfInterest() {
      class="kw">return this.pointsOfInterest;
   }

   @Nullable
   class="kw">public MapImage getImageIfInMemory(int var1, int var2) {
      class="kw">return this.getImageIfInMemory(ChunkUtil.indexChunk(var1, var2));
   }

   @Nullable
   class="kw">public MapImage getImageIfInMemory(long var1) {
      WorldMapManager.ImageEntry var3 = this.images.get(var1);
      class="kw">return var3 != null ? var3.image : null;
   }

   @Nonnull
   class="kw">public CompletableFuture<MapImage> getImageAsync(int var1, int var2) {
      class="kw">return this.getImageAsync(ChunkUtil.indexChunk(var1, var2));
   }

   @Nonnull
   class="kw">public CompletableFuture<MapImage> getImageAsync(long var1) {
      WorldMapManager.ImageEntry var3 = this.images.get(var1);
      if (var3 != null) {
         class="kw">return CompletableFuture.completedFuture(var3.image);
      }

      CompletableFuture var4 = this.generating.get(var1);
      if (var4 != null) {
         class="kw">return var4;
      }

      CompletableFuture var5 = new CompletableFuture<>();
      CompletableFuture var6 = this.generating.putIfAbsent(var1, var5);
      if (var6 != null) {
         class="kw">return var6;
      }

      this.generationQueue.put(var1, var5);
      if (this.generationQueue.size() == 1) {
         this.flushGenerationQueue();
      }

      class="kw">return var5;
   }

   class="kw">public void generate() {
   }

   class="kw">public void sendSettings() {
      for (Player var2 : this.world.getPlayers()) {
         var2.getWorldMapTracker().sendSettings(this.world);
      }
   }

   class="kw">public boolean shouldTick() {
      class="kw">return this.world.getWorldConfig().isCompassUpdating() || this.isWorldMapEnabled();
   }

   @Nonnull
   class="kw">public Map<String, MapMarkerOverride> getMarkerOverridesView() {
      this.assertThread();
      class="kw">return this.markerOverridesLocalView;
   }

   class="kw">public boolean addMarkerOverride(@Nonnull String var1, @Nonnull MapMarkerOverride var2) {
      class="kw">return !var1.isEmpty() && !var2.isEmpty() ? this.markerOverrides.putIfAbsent(var1, var2) == null : false;
   }

   class="kw">public boolean removeMarkerOverride(@Nonnull String var1) {
      class="kw">return var1.isEmpty() ? false : this.markerOverrides.remove(var1) != null;
   }

   class="kw">public boolean removeMarkerOverride(@Nonnull String var1, @Nonnull MapMarkerOverride var2) {
      class="kw">return !var1.isEmpty() && !var2.isEmpty() ? this.markerOverrides.remove(var1, var2) : false;
   }

   class="kw">public void removeAllMarkerOverrides() {
      this.markerOverrides.clear();
   }

   class="kw">public void updateTickingState(boolean var1) {
      boolean var2 = this.shouldTick();
      if (var1 != var2) {
         if (var2) {
            this.start();
         } else {
            this.stop();
         }
      }
   }

   class="kw">public void handleUserCreateMarker(PlayerRef var1, CreateUserMarker var2) {
      Ref var3 = var1.getReference();
      if (var3 != null) {
         UserMarkerValidator.PlaceResult var4 = UserMarkerValidator.validatePlacing(var3, var2);
         if (var4 class="kw">instanceof UserMarkerValidator.CanSpawn var5) {
            Store var13 = var3.getStore();
            UserMapMarkersStore var14 = var5.markersStore();
            DisplayNameComponent var15 = var13.getComponent(var3, DisplayNameComponent.getComponentType());
            String var9 = var15 == null ? var1.getUsername() : var15.getDisplayName().getRawText();
            UserMapMarker var10 = new UserMapMarker();
            var10.setId("user_" + (var2.shared ? "shared" : "personal") + "_" + UUID.randomUUID());
            var10.setPosition(var2.x, var2.z);
            var10.setName(var2.name);
            var10.setIcon(var2.markerImage == null ? "User1.png" : var2.markerImage);
            var10.setColorTint(var2.tintColor == null ? new Color((byte)0, (byte)0, (byte)0) : var2.tintColor);
            var10.withCreatedByName(var9);
            var10.withCreatedByUuid(var1.getUuid());
            var14.addUserMapMarker(var10);
         } else {
            if (var4 class="kw">instanceof UserMarkerValidator.Fail(Message var7)) {
               var1.sendMessage(var7.color("#ffc800"));
            }
         }
      }
   }

   class="kw">public void handleUserRemoveMarker(PlayerRef var1, RemoveMapMarker var2) {
      Ref var3 = var1.getReference();
      if (var3 != null) {
         Store var4 = var3.getStore();
         World var5 = var4.getExternalData().getWorld();
         Player var6 = var4.getComponent(var3, Player.getComponentType());
         PlayerWorldData var7 = var6.getPlayerConfigData().getPerWorldData(var5.getName());
         boolean var8 = var7.removeLastDeath(var2.markerId);
         if (!var8) {
            WorldMapManager.MarkerAndItsStore var9 = this.findUserMapMarker(var2.markerId, var6, var5);
            if (var9 == null) {
               var1.sendMessage(Message.translation("server.worldmap.markers.edit.notFound").color("#ffc800"));
               HytaleLogger.getLogger()
                  .at(Level.WARNING)
                  .log("Couldn't find marker to remove '%s' from %s %s", var2.markerId, var1.getUsername(), var1.getUuid());
            } else {
               UserMarkerValidator.RemoveResult var10 = UserMarkerValidator.validateRemove(var3, var9.marker);
               if (!(var10 class="kw">instanceof UserMarkerValidator.CanRemove)) {
                  if (var10 class="kw">instanceof UserMarkerValidator.Fail(Message var12)) {
                     var1.sendMessage(var12.color("#ffc800"));
                  }
               } else {
                  var9.store.removeUserMapMarker(var9.marker.getId());
               }
            }
         }
      }
   }

   @Nullable
   class="kw">private WorldMapManager.MarkerAndItsStore findUserMapMarker(String var1, Player var2, World var3) {
      PlayerWorldData var4 = var2.getPlayerConfigData().getPerWorldData(var3.getName());
      UserMapMarker var5 = var4.getUserMapMarker(var1);
      if (var5 != null) {
         class="kw">return new WorldMapManager.MarkerAndItsStore(var5, var4);
      }

      WorldMarkersResource var6 = var3.getChunkStore().getStore().getResource(WorldMarkersResource.getResourceType());
      UserMapMarker var7 = var6.getUserMapMarker(var1);
      class="kw">return var7 != null ? new WorldMapManager.MarkerAndItsStore(var7, var6) : null;
   }

   class="kw">public void clearImages() {
      this.images.clear();
      this.generating.clear();
      this.cancelQueuedGenerations();
   }

   class="kw">public void clearImagesInChunks(@Nonnull LongSet var1) {
      var1.forEach(var1x -> {
         this.images.remove(var1x);
         this.generating.remove(var1x);
         CompletableFuture var3 = this.generationQueue.remove(var1x);
         if (var3 != null) {
            var3.complete(null);
         }
      });
   }

   class="kw">private void assertThread() {
      if (!this.isInThread()) {
         throw new IllegalStateException("Assert not in WorldMapManager thread! Called from: " + Thread.currentThread());
      }
   }

   class="kw">public class="kw">static void sendSettingsToAllWorlds() {
      for (World var1 : Universe.get().getWorlds().values()) {
         var1.execute(() -> var1.getWorldMapManager().sendSettings());
      }
   }

   class="kw">static {
      WorldMapManager.MarkerReference.CODEC.register("Player", WorldMapManager.PlayerMarkerReference.class, WorldMapManager.PlayerMarkerReference.CODEC);
   }

   class="kw">public class="kw">static class ImageEntry {
      class="kw">private class="kw">final AtomicInteger keepAlive = new AtomicInteger();
      class="kw">private class="kw">final MapImage image;

      class="kw">public ImageEntry(MapImage var1) {
         this.image = var1;
      }
   }

   class="kw">private record MarkerAndItsStore(UserMapMarker marker, UserMapMarkersStore store) {
      class="kw">private MarkerAndItsStore {
      }
   }

   class="kw">public class="kw">interface MarkerProvider {
      void update(@Nonnull World var1, @Nonnull Player var2, @Nonnull MarkersCollector var3);
   }

   class="kw">public class="kw">interface MarkerReference {
      CodecMapCodec<WorldMapManager.MarkerReference> CODEC = new CodecMapCodec<>();

      String getMarkerId();

      void remove();
   }

   class="kw">public class="kw">static class PlayerMarkerReference class="kw">implements WorldMapManager.MarkerReference {
      class="kw">public class="kw">static class="kw">final BuilderCodec<WorldMapManager.PlayerMarkerReference> CODEC = BuilderCodec.<WorldMapManager.PlayerMarkerReference>builder(
            WorldMapManager.PlayerMarkerReference.class, WorldMapManager.PlayerMarkerReference::new
         )
         .addField(new KeyedCodec<>("Player", Codec.UUID_BINARY), (var0, var1) -> var0.player = var1, var0 -> var0.player)
         .addField(new KeyedCodec<>("World", Codec.STRING), (var0, var1) -> var0.world = var1, var0 -> var0.world)
         .addField(new KeyedCodec<>("MarkerId", Codec.STRING), (var0, var1) -> var0.markerId = var1, var0 -> var0.markerId)
         .build();
      class="kw">private UUID player;
      class="kw">private String world;
      class="kw">private String markerId;

      class="kw">private PlayerMarkerReference() {
      }

      class="kw">public PlayerMarkerReference(@Nonnull UUID var1, @Nonnull String var2, @Nonnull String var3) {
         this.player = var1;
         this.world = var2;
         this.markerId = var3;
      }

      class="kw">public UUID getPlayer() {
         class="kw">return this.player;
      }

      @Override
      class="kw">public String getMarkerId() {
         class="kw">return this.markerId;
      }

      @Override
      class="kw">public void remove() {
         PlayerRef var1 = Universe.get().getPlayer(this.player);
         if (var1 != null) {
            Player var2 = var1.getComponent(Player.getComponentType());
            this.removeMarkerFromOnlinePlayer(var2);
         } else {
            this.removeMarkerFromOfflinePlayer();
         }
      }

      class="kw">private void removeMarkerFromOnlinePlayer(@Nonnull Player var1) {
         PlayerConfigData var2 = var1.getPlayerConfigData();
         String var3 = this.world;
         if (var3 == null) {
            var3 = var1.getWorld().getName();
         }

         removeMarkerFromData(var2, var3, this.markerId);
      }

      class="kw">private void removeMarkerFromOfflinePlayer() {
         Universe.get().getPlayerStorage().update(this.player, var1 -> {
            Player var2 = var1.getComponent(Player.getComponentType());
            PlayerConfigData var3 = var2.getPlayerConfigData();
            String var4 = this.world;
            if (var4 == null) {
               var4 = var3.getWorld();
            }

            removeMarkerFromData(var3, var4, this.markerId);
         });
      }

      class="kw">private class="kw">static void removeMarkerFromData(@Nonnull PlayerConfigData var0, @Nonnull String var1, @Nonnull String var2) {
         PlayerWorldData var3 = var0.getPerWorldData(var1);
         ArrayList var4 = new ArrayList<>(var3.getUserMapMarkers());
         var4.removeIf(var1x -> var2.equals(var1x.getId()));
         var3.setUserMapMarkers(var4);
      }
   }
}