aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java2
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/chat/filters/AdFilter.java4
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java19
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/DungeonBuffWidget.java29
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/DungeonPlayerWidget.java6
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/IslandOwnersWidget.java3
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/IslandSelfWidget.java8
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/PlayerListWidget.java23
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/component/PlayerComponent.java14
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/RenderHelper.java45
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/RenderUtils.java2
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/culling/OcclusionCulling.java48
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/culling/WorldProvider.java29
-rw-r--r--src/main/java/me/xmrvizzy/skyblocker/utils/culling/package-info.java4
-rw-r--r--src/main/resources/assets/skyblocker/lang/en_us.json4
15 files changed, 196 insertions, 44 deletions
diff --git a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java
index cc712405..3692db1b 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/SkyblockerMod.java
@@ -19,6 +19,7 @@ import me.xmrvizzy.skyblocker.skyblock.rift.TheRift;
import me.xmrvizzy.skyblocker.skyblock.tabhud.TabHud;
import me.xmrvizzy.skyblocker.skyblock.tabhud.util.PlayerListMgr;
import me.xmrvizzy.skyblocker.utils.*;
+import me.xmrvizzy.skyblocker.utils.culling.OcclusionCulling;
import me.xmrvizzy.skyblocker.utils.title.TitleContainer;
import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
@@ -83,6 +84,7 @@ public class SkyblockerMod implements ClientModInitializer {
DungeonMap.init();
TheRift.init();
TitleContainer.init();
+ OcclusionCulling.init();
containerSolverManager.init();
scheduler.scheduleCyclic(Utils::update, 20);
scheduler.scheduleCyclic(DiscordRPCManager::updateDataAndPresence, 100);
diff --git a/src/main/java/me/xmrvizzy/skyblocker/chat/filters/AdFilter.java b/src/main/java/me/xmrvizzy/skyblocker/chat/filters/AdFilter.java
index 67734438..6b681d4c 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/chat/filters/AdFilter.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/chat/filters/AdFilter.java
@@ -18,8 +18,8 @@ public class AdFilter extends ChatPatternListener {
// Groups:
// 1. Player name
// 2. Message
- // (?:§8\[[§fadbc0-9]+§8\] )?§[67abc](?:\[[§A-Za-z0-9+]+\] )?([A-Za-z0-9_]+)§[f7]: (.+)
- super("(?:§8\\[[§fadbc0-9]+§8\\] )?§[67abc](?:\\[[§A-Za-z0-9+]+\\] )?([A-Za-z0-9_]+)§[f7]: (.+)");
+ // (?:§8\[[§feadbc0-9]+§8\] )?(?:.+ )?§[67abc](?:\[[§A-Za-z0-9+]+\] )?([A-Za-z0-9_]+)§[f7]: (.+)
+ super("(?:§8\\[[§feadbc0-9]+§8\\] )?(?:.+ )?§[67abc](?:\\[[§A-Za-z0-9+]+\\] )?([A-Za-z0-9_]+)§[f7]: (.+)");
}
@Override
diff --git a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java
index bd616c2c..04cfaea3 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/config/SkyblockerConfig.java
@@ -188,6 +188,25 @@ public class SkyblockerConfig implements ConfigData {
@ConfigEntry.BoundedDiscrete(min = 10, max = 200)
@ConfigEntry.Gui.Tooltip()
public int tabHudScale = 100;
+ @ConfigEntry.Gui.Tooltip
+ public boolean plainPlayerNames = false;
+ @ConfigEntry.Gui.EnumHandler(option = ConfigEntry.Gui.EnumHandler.EnumDisplayOption.BUTTON)
+ @ConfigEntry.Gui.Tooltip
+ public NameSorting nameSorting = NameSorting.DEFAULT;
+
+ }
+
+ public enum NameSorting {
+ DEFAULT,
+ ALPHABETICAL;
+
+ @Override
+ public String toString() {
+ return switch (this) {
+ case DEFAULT -> "Default";
+ case ALPHABETICAL -> "Alphabetical";
+ };
+ }
}
public static class Bars {
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/DungeonBuffWidget.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/DungeonBuffWidget.java
index 6ad5268e..d56d3522 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/DungeonBuffWidget.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/DungeonBuffWidget.java
@@ -5,6 +5,9 @@ import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
+import java.util.Arrays;
+import java.util.Comparator;
+
// this widget shows a list of obtained dungeon buffs
// TODO: could be more pretty, can't be arsed atm
@@ -31,14 +34,32 @@ public class DungeonBuffWidget extends Widget {
return;
}
- for (int i = 1; i < lines.length; i++) {
- if (lines[i].length() < 3) { // empty line is §s
+ //Filter out text unrelated to blessings
+ lines = Arrays.stream(lines).filter(s -> s.contains("Blessing")).toArray(String[]::new);
+
+ //Alphabetically sort the blessings
+ Arrays.sort(lines, Comparator.comparing(String::toLowerCase));
+
+ for (String line : lines) {
+ if (line.length() < 3) { // empty line is §s
break;
}
- this.addComponent(new PlainTextComponent(Text.of(lines[i])));
+ int color = getBlessingColor(line);
+ this.addComponent(new PlainTextComponent(Text.literal(line).styled(style -> style.withColor(color))));
}
this.pack();
}
-}
+ @SuppressWarnings("DataFlowIssue")
+ public int getBlessingColor(String blessing) {
+ if (blessing.contains("Life")) return Formatting.LIGHT_PURPLE.getColorValue();
+ if (blessing.contains("Power")) return Formatting.RED.getColorValue();
+ if (blessing.contains("Stone")) return Formatting.GREEN.getColorValue();
+ if (blessing.contains("Time")) return 0xafb8c1;
+ if (blessing.contains("Wisdom")) return Formatting.AQUA.getColorValue();
+
+ return 0xffffff;
+ }
+
+} \ No newline at end of file
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/DungeonPlayerWidget.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/DungeonPlayerWidget.java
index c1f9e235..443cca55 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/DungeonPlayerWidget.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/DungeonPlayerWidget.java
@@ -25,10 +25,10 @@ public class DungeonPlayerWidget extends Widget {
// group 1: name
// group 2: class (or literal "EMPTY" pre dungeon start)
// group 3: level (or nothing, if pre dungeon start)
- // as a side effect, this regex keeps the iron man icon in the name
- // not sure if that should be
+ // this regex filters out the ironman icon as well as rank prefixes and emblems
+ // \[\d*\] (?:\[[A-Za-z]+\] )?(?<name>[A-Za-z0-9_]*) (?:.* )?\((?<class>\S*) ?(?<level>[LXVI]*)\)
private static final Pattern PLAYER_PATTERN = Pattern
- .compile("\\[\\d*\\] (?<name>.*) \\((?<class>\\S*) ?(?<level>[LXVI]*)\\)");
+ .compile("\\[\\d*\\] (?:\\[[A-Za-z]+\\] )?(?<name>[A-Za-z0-9_]*) (?:.* )?\\((?<class>\\S*) ?(?<level>[LXVI]*)\\)");
private static final HashMap<String, ItemStack> ICOS = new HashMap<>();
private static final ArrayList<String> MSGS = new ArrayList<>();
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/IslandOwnersWidget.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/IslandOwnersWidget.java
index 6c2d6b47..e81a6d85 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/IslandOwnersWidget.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/IslandOwnersWidget.java
@@ -20,8 +20,9 @@ public class IslandOwnersWidget extends Widget {
// matches an owner
// group 1: player name
// group 2: last seen, if owner not online
+ // ^(?<nameA>.*) \((?<lastseen>.*)\)$|^\[\d*\] (?:\[[A-Za-z]+\] )?(?<nameB>[A-Za-z0-9_]*)(?: .*)?$|^(?<nameC>.*)$
private static final Pattern OWNER_PATTERN = Pattern
- .compile("^(?<nameA>.*) \\((?<lastseen>.*)\\)$|^\\[\\d*\\] (?<nameB>.*)$|^(?<nameC>.*)$");
+ .compile("^(?<nameA>.*) \\((?<lastseen>.*)\\)$|^\\[\\d*\\] (?:\\[[A-Za-z]+\\] )?(?<nameB>[A-Za-z0-9_]*)(?: .*)?$|^(?<nameC>.*)$");
public IslandOwnersWidget() {
super(TITLE, Formatting.DARK_PURPLE.getColorValue());
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/IslandSelfWidget.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/IslandSelfWidget.java
index 4324dad9..4b03da6e 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/IslandSelfWidget.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/IslandSelfWidget.java
@@ -19,7 +19,8 @@ public class IslandSelfWidget extends Widget {
// matches an owner
// group 1: player name, optionally offline time
- private static final Pattern OWNER_PATTERN = Pattern.compile("^\\[\\d*\\] (.*)$|^(.*)$");
+ // ^\[\d*\] (?:\[[A-Za-z]+\] )?([A-Za-z0-9_() ]*)(?: .*)?$|^(.*)$
+ private static final Pattern OWNER_PATTERN = Pattern.compile("^\\[\\d*\\] (?:\\[[A-Za-z]+\\] )?([A-Za-z0-9_() ]*)(?: .*)?$|^(.*)$");
public IslandSelfWidget() {
super(TITLE, Formatting.DARK_PURPLE.getColorValue());
@@ -28,8 +29,9 @@ public class IslandSelfWidget extends Widget {
if (m == null) {
break;
}
- PlainTextComponent ptc = new PlainTextComponent(Text.of(m.group(1)));
- this.addComponent(ptc);
+
+ Text entry = (m.group(1) != null) ? Text.of(m.group(1)) : Text.of(m.group(2));
+ this.addComponent(new PlainTextComponent(entry));
}
this.pack();
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/PlayerListWidget.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/PlayerListWidget.java
index 2cd710eb..439fcb56 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/PlayerListWidget.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/PlayerListWidget.java
@@ -1,19 +1,18 @@
package me.xmrvizzy.skyblocker.skyblock.tabhud.widget;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-
+import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import me.xmrvizzy.skyblocker.skyblock.tabhud.util.PlayerListMgr;
import me.xmrvizzy.skyblocker.skyblock.tabhud.widget.component.PlainTextComponent;
import me.xmrvizzy.skyblocker.skyblock.tabhud.widget.component.PlayerComponent;
import me.xmrvizzy.skyblocker.skyblock.tabhud.widget.component.TableComponent;
-
import net.minecraft.client.network.PlayerListEntry;
import net.minecraft.text.MutableText;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
+import java.util.ArrayList;
+import java.util.Comparator;
+
// this widget shows a list of players with their skins.
// responsible for non-private-island areas
@@ -22,7 +21,7 @@ public class PlayerListWidget extends Widget {
private static final MutableText TITLE = Text.literal("Players").formatted(Formatting.GREEN,
Formatting.BOLD);
- private ArrayList<PlayerListEntry> list = new ArrayList<>();
+ private final ArrayList<PlayerListEntry> list = new ArrayList<>();
public PlayerListWidget() {
super(TITLE, Formatting.GREEN.getColorValue());
@@ -42,19 +41,15 @@ public class PlayerListWidget extends Widget {
// https://stackoverflow.com/questions/7139382/java-rounding-up-to-an-int-using-math-ceil#21830188
int tblW = ((listlen - 80) - 1) / 20 + 1;
- TableComponent tc = new TableComponent(tblW, (listlen - 80 >= 20) ? 20 : listlen - 80,
- Formatting.GREEN.getColorValue());
+ TableComponent tc = new TableComponent(tblW, Math.min(listlen - 80, 20), Formatting.GREEN.getColorValue());
for (int i = 80; i < listlen; i++) {
list.add(PlayerListMgr.getRaw(i));
}
- Collections.sort(list, new Comparator<PlayerListEntry>() {
- @Override
- public int compare(PlayerListEntry o1, PlayerListEntry o2) {
- return o1.getProfile().getName().toLowerCase().compareTo(o2.getProfile().getName().toLowerCase());
- }
- });
+ if (SkyblockerConfig.get().general.tabHud.nameSorting == SkyblockerConfig.NameSorting.ALPHABETICAL) {
+ list.sort(Comparator.comparing(o -> o.getProfile().getName().toLowerCase()));
+ }
int x = 0, y = 0;
diff --git a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/component/PlayerComponent.java b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/component/PlayerComponent.java
index fd66ec73..1be6adda 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/component/PlayerComponent.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/skyblock/tabhud/widget/component/PlayerComponent.java
@@ -1,8 +1,11 @@
package me.xmrvizzy.skyblocker.skyblock.tabhud.widget.component;
+import me.xmrvizzy.skyblocker.config.SkyblockerConfig;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.PlayerSkinDrawer;
import net.minecraft.client.network.PlayerListEntry;
+import net.minecraft.scoreboard.Team;
+import net.minecraft.text.Text;
import net.minecraft.util.Identifier;
/**
@@ -12,12 +15,15 @@ public class PlayerComponent extends Component {
private static final int SKIN_ICO_DIM = 8;
- private String name;
- private Identifier tex;
+ private final Text name;
+ private final Identifier tex;
public PlayerComponent(PlayerListEntry ple) {
-
- name = ple.getProfile().getName();
+
+ boolean plainNames = SkyblockerConfig.get().general.tabHud.plainPlayerNames;
+ Team team = ple.getScoreboardTeam();
+ String username = ple.getProfile().getName();
+ name = (team != null && !plainNames) ? Text.empty().append(team.getPrefix()).append(Text.literal(username).formatted(team.getColor())).append(team.getSuffix()) : Text.of(username);
tex = ple.getSkinTexture();
this.width = SKIN_ICO_DIM + PAD_S + txtRend.getWidth(name);
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/RenderHelper.java b/src/main/java/me/xmrvizzy/skyblocker/utils/RenderHelper.java
index 6fa93735..a1221549 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/utils/RenderHelper.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/utils/RenderHelper.java
@@ -2,22 +2,29 @@ package me.xmrvizzy.skyblocker.utils;
import me.x150.renderer.render.Renderer3d;
import me.xmrvizzy.skyblocker.mixin.accessor.BeaconBlockEntityRendererInvoker;
+import me.xmrvizzy.skyblocker.utils.culling.OcclusionCulling;
import me.xmrvizzy.skyblocker.utils.title.Title;
import me.xmrvizzy.skyblocker.utils.title.TitleContainer;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderContext;
import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.render.block.entity.BeaconBlockEntityRenderer;
+import net.minecraft.client.render.BufferBuilder;
+import net.minecraft.client.render.Camera;
+import net.minecraft.client.render.Tessellator;
+import net.minecraft.client.render.VertexConsumerProvider;
+import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.sound.SoundEvent;
import net.minecraft.text.Text;
import net.minecraft.util.Formatting;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
-
import java.awt.*;
+import com.mojang.blaze3d.systems.RenderSystem;
+
public class RenderHelper {
private static final Vec3d ONE = new Vec3d(1, 1, 1);
+ private static final int MAX_OVERWORLD_BUILD_HEIGHT = 319;
public static void renderFilledThroughWallsWithBeaconBeam(WorldRenderContext context, BlockPos pos, float[] colorComponents, float alpha) {
renderFilledThroughWalls(context, pos, colorComponents, alpha);
@@ -25,26 +32,40 @@ public class RenderHelper {
}
public static void renderFilledThroughWalls(WorldRenderContext context, BlockPos pos, float[] colorComponents, float alpha) {
- Renderer3d.renderThroughWalls();
- renderFilled(context, pos, colorComponents, alpha);
- Renderer3d.stopRenderThroughWalls();
+ if (FrustumUtils.isVisible(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1)) {
+ Renderer3d.renderThroughWalls();
+ renderFilled(context, pos, colorComponents, alpha);
+ Renderer3d.stopRenderThroughWalls();
+ }
}
public static void renderFilledIfVisible(WorldRenderContext context, BlockPos pos, float[] colorComponents, float alpha) {
- if (FrustumUtils.isVisible(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1)) {
+ if (OcclusionCulling.isVisible(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, pos.getY() + 1, pos.getZ() + 1)) {
renderFilled(context, pos, colorComponents, alpha);
}
}
- public static void renderFilled(WorldRenderContext context, BlockPos pos, float[] colorComponents, float alpha) {
+ private static void renderFilled(WorldRenderContext context, BlockPos pos, float[] colorComponents, float alpha) {
Renderer3d.renderFilled(context.matrixStack(), new Color(colorComponents[0], colorComponents[1], colorComponents[2], alpha), Vec3d.of(pos), ONE);
}
- public static void renderBeaconBeam(WorldRenderContext context, BlockPos pos, float[] colorComponents) {
- context.matrixStack().push();
- context.matrixStack().translate(pos.getX() - context.camera().getPos().x, pos.getY() - context.camera().getPos().y, pos.getZ() - context.camera().getPos().z);
- BeaconBlockEntityRendererInvoker.renderBeam(context.matrixStack(), context.consumers(), context.tickDelta(), context.world().getTime(), 0, BeaconBlockEntityRenderer.MAX_BEAM_HEIGHT, colorComponents);
- context.matrixStack().pop();
+ private static void renderBeaconBeam(WorldRenderContext context, BlockPos pos, float[] colorComponents) {
+ if (FrustumUtils.isVisible(pos.getX(), pos.getY(), pos.getZ(), pos.getX() + 1, MAX_OVERWORLD_BUILD_HEIGHT, pos.getZ() + 1)) {
+ MatrixStack matrices = context.matrixStack();
+ Vec3d camera = context.camera().getPos();
+
+ matrices.push();
+ matrices.translate(pos.getX() - camera.x, pos.getY() - camera.y, pos.getZ() - camera.z);
+
+ Tessellator tessellator = RenderSystem.renderThreadTesselator();
+ BufferBuilder buffer = tessellator.getBuffer();
+ VertexConsumerProvider.Immediate consumer = VertexConsumerProvider.immediate(buffer);
+
+ BeaconBlockEntityRendererInvoker.renderBeam(matrices, consumer, context.tickDelta(), context.world().getTime(), 0, MAX_OVERWORLD_BUILD_HEIGHT, colorComponents);
+
+ consumer.draw();
+ matrices.pop();
+ }
}
public static void displayTitleAndPlaySound(int stayTicks, int fadeOutTicks, String titleKey, Formatting formatting) {
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/RenderUtils.java b/src/main/java/me/xmrvizzy/skyblocker/utils/RenderUtils.java
index 73ad468f..61f79ae1 100644
--- a/src/main/java/me/xmrvizzy/skyblocker/utils/RenderUtils.java
+++ b/src/main/java/me/xmrvizzy/skyblocker/utils/RenderUtils.java
@@ -82,7 +82,7 @@ public class RenderUtils {
e.getZ() - MathHelper.lerp(tickDelta, e.lastRenderZ, e.getZ()));
}
- public static Boolean pointExistsInArea(int x, int y, int x1, int y1, int x2, int y2) {
+ public static boolean pointExistsInArea(int x, int y, int x1, int y1, int x2, int y2) {
return x >= x1 && x <= x2 && y >= y1 && y <= y2;
}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/culling/OcclusionCulling.java b/src/main/java/me/xmrvizzy/skyblocker/utils/culling/OcclusionCulling.java
new file mode 100644
index 00000000..e9a25fc3
--- /dev/null
+++ b/src/main/java/me/xmrvizzy/skyblocker/utils/culling/OcclusionCulling.java
@@ -0,0 +1,48 @@
+package me.xmrvizzy.skyblocker.utils.culling;
+
+import com.logisticscraft.occlusionculling.OcclusionCullingInstance;
+import com.logisticscraft.occlusionculling.cache.ArrayOcclusionCache;
+import com.logisticscraft.occlusionculling.util.Vec3d;
+
+import me.xmrvizzy.skyblocker.utils.FrustumUtils;
+import net.minecraft.client.MinecraftClient;
+
+public class OcclusionCulling {
+ private static final int TRACING_DISTANCE = 128;
+ private static final MinecraftClient CLIENT = MinecraftClient.getInstance();
+ private static OcclusionCullingInstance instance = null;
+
+ // Reused objects to reduce allocation overhead
+ private static Vec3d cameraPos = new Vec3d(0, 0, 0);
+ private static Vec3d min = new Vec3d(0, 0, 0);
+ private static Vec3d max = new Vec3d(0, 0, 0);
+
+ /**
+ * Initializes the occlusion culling instance
+ */
+ public static void init() {
+ instance = new OcclusionCullingInstance(TRACING_DISTANCE, new WorldProvider(), new ArrayOcclusionCache(TRACING_DISTANCE), 2);
+ }
+
+ private static void updateCameraPos() {
+ var camera = CLIENT.gameRenderer.getCamera().getPos();
+ cameraPos.set(camera.x, camera.y, camera.z);
+ }
+
+ /**
+ * This first checks checks if the bounding box is within the camera's FOV, if
+ * it is then it checks for whether it's occluded or not.
+ *
+ * @return A boolean representing whether the bounding box is fully visible or
+ * not.
+ */
+ public static boolean isVisible(double x1, double y1, double z1, double x2, double y2, double z2) {
+ if (!FrustumUtils.isVisible(x1, y1, z1, x2, y2, z2)) return false;
+
+ updateCameraPos();
+ min.set(x1, y1, z1);
+ max.set(x2, y2, z2);
+
+ return instance.isAABBVisible(min, max, cameraPos);
+ }
+}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/culling/WorldProvider.java b/src/main/java/me/xmrvizzy/skyblocker/utils/culling/WorldProvider.java
new file mode 100644
index 00000000..47d92c1f
--- /dev/null
+++ b/src/main/java/me/xmrvizzy/skyblocker/utils/culling/WorldProvider.java
@@ -0,0 +1,29 @@
+package me.xmrvizzy.skyblocker.utils.culling;
+
+import com.logisticscraft.occlusionculling.DataProvider;
+
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.world.ClientWorld;
+import net.minecraft.util.math.BlockPos;
+
+public class WorldProvider implements DataProvider {
+ private final static MinecraftClient CLIENT = MinecraftClient.getInstance();
+ private ClientWorld world = null;
+
+ @Override
+ public boolean prepareChunk(int chunkX, int chunkZ) {
+ this.world = CLIENT.world;
+ return this.world != null;
+ }
+
+ @Override
+ public boolean isOpaqueFullCube(int x, int y, int z) {
+ BlockPos pos = new BlockPos(x, y, z);
+ return this.world.getBlockState(pos).isOpaqueFullCube(this.world, pos);
+ }
+
+ @Override
+ public void cleanup() {
+ this.world = null;
+ }
+}
diff --git a/src/main/java/me/xmrvizzy/skyblocker/utils/culling/package-info.java b/src/main/java/me/xmrvizzy/skyblocker/utils/culling/package-info.java
new file mode 100644
index 00000000..c25e7f7a
--- /dev/null
+++ b/src/main/java/me/xmrvizzy/skyblocker/utils/culling/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Package dedicated to occlusion culling utilities
+ */
+package me.xmrvizzy.skyblocker.utils.culling; \ No newline at end of file
diff --git a/src/main/resources/assets/skyblocker/lang/en_us.json b/src/main/resources/assets/skyblocker/lang/en_us.json
index 9dc2a856..0cf9933c 100644
--- a/src/main/resources/assets/skyblocker/lang/en_us.json
+++ b/src/main/resources/assets/skyblocker/lang/en_us.json
@@ -36,6 +36,10 @@
"text.autoconfig.skyblocker.option.general.tabHud.tabHudEnabled": "Enable fancy tab HUD",
"text.autoconfig.skyblocker.option.general.tabHud.tabHudScale": "Scale factor of fancy tab HUD",
"text.autoconfig.skyblocker.option.general.tabHud.tabHudScale.@Tooltip": "Value in %, relative to your vanilla GUI scale",
+ "text.autoconfig.skyblocker.option.general.tabHud.plainPlayerNames": "Plain Player Names",
+ "text.autoconfig.skyblocker.option.general.tabHud.plainPlayerNames.@Tooltip":"Enable to display player names without any special formatting on public islands.",
+ "text.autoconfig.skyblocker.option.general.tabHud.nameSorting": "Player Name Sorting Method",
+ "text.autoconfig.skyblocker.option.general.tabHud.nameSorting.@Tooltip": "Alphabetical sorting sorts names alphabetically while Default has no particular order.",
"text.autoconfig.skyblocker.option.general.itemTooltip": "Item Tooltip",
"text.autoconfig.skyblocker.option.general.itemTooltip.enableNPCPrice": "Enable NPC Price",
"text.autoconfig.skyblocker.option.general.itemTooltip.enableMotesPrice": "Enable Motes Price",