diff --git a/src/de/steamwar/lobby/Displayable.java b/src/de/steamwar/lobby/Displayable.java
new file mode 100644
index 0000000..7fd21c5
--- /dev/null
+++ b/src/de/steamwar/lobby/Displayable.java
@@ -0,0 +1,91 @@
+/*
+ * This file is a part of the SteamWar software.
+ *
+ * Copyright (C) 2021 SteamWar.de-Serverteam
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package de.steamwar.lobby;
+
+import de.steamwar.lobby.listener.BasicListener;
+import org.bukkit.Location;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Consumer;
+
+public class Displayable extends BasicListener {
+
+ private final Set visible = new HashSet<>();
+
+ private final int chunkX;
+ private final int chunkZ;
+ private final Consumer show;
+ private final Consumer hide;
+
+ public Displayable(Location location, Consumer show, Consumer hide) {
+ this.chunkX = posToChunk(location.getX());
+ this.chunkZ = posToChunk(location.getZ());
+ this.show = show;
+ this.hide = hide;
+ }
+
+ @EventHandler
+ public void onJoin(PlayerJoinEvent e) {
+ checkLocation(e.getPlayer(), e.getPlayer().getLocation());
+ }
+
+ @EventHandler
+ public void onMove(PlayerMoveEvent e) {
+ checkLocation(e.getPlayer(), e.getTo());
+ }
+
+ private void checkLocation(Player player, Location at) {
+ boolean shown = visible.contains(player);
+ int viewDistance = player.getClientViewDistance();
+ boolean see = Math.abs(chunkX - posToChunk(at.getX())) < viewDistance && Math.abs(chunkZ - posToChunk(at.getZ())) < viewDistance;
+
+ if(!shown && see) {
+ show.accept(player);
+ visible.add(player);
+ }
+
+ if(shown && !see) {
+ hide.accept(player);
+ visible.remove(player);
+ }
+ }
+
+ @EventHandler
+ public void onQuit(PlayerQuitEvent e) {
+ visible.remove(e.getPlayer());
+ }
+
+ public void delete() {
+ visible.forEach(hide);
+ visible.clear();
+ HandlerList.unregisterAll(this);
+ }
+
+ private int posToChunk(double coord) {
+ return (int)(coord / 16) - (coord < 0 ? 1 : 0);
+ }
+}