1 package com.irtimaled.bbor.client;
3 import com.irtimaled.bbor.client.interop.ClientInterop;
4 import com.irtimaled.bbor.client.models.Point;
5 import com.irtimaled.bbor.client.providers.BeaconProvider;
6 import com.irtimaled.bbor.client.providers.BedrockCeilingProvider;
7 import com.irtimaled.bbor.client.providers.BiomeBorderProvider;
8 import com.irtimaled.bbor.client.providers.ConduitProvider;
9 import com.irtimaled.bbor.client.providers.CustomBeaconProvider;
10 import com.irtimaled.bbor.client.providers.CustomBoxProvider;
11 import com.irtimaled.bbor.client.providers.CustomLineProvider;
12 import com.irtimaled.bbor.client.providers.CustomSphereProvider;
13 import com.irtimaled.bbor.client.providers.FlowerForestProvider;
14 import com.irtimaled.bbor.client.providers.IBoundingBoxProvider;
15 import com.irtimaled.bbor.client.providers.ICachingProvider;
16 import com.irtimaled.bbor.client.providers.MobSpawnerProvider;
17 import com.irtimaled.bbor.client.providers.SlimeChunkProvider;
18 import com.irtimaled.bbor.client.providers.SpawnableBlocksProvider;
19 import com.irtimaled.bbor.client.providers.SpawningSphereProvider;
20 import com.irtimaled.bbor.client.providers.WorldSpawnProvider;
21 import com.irtimaled.bbor.client.renderers.AbstractRenderer;
22 import com.irtimaled.bbor.client.renderers.RenderHelper;
23 import com.irtimaled.bbor.client.renderers.RenderQueue;
24 import com.irtimaled.bbor.common.MathHelper;
25 import com.irtimaled.bbor.common.TypeHelper;
26 import com.irtimaled.bbor.common.models.AbstractBoundingBox;
27 import com.irtimaled.bbor.common.models.DimensionId;
28 import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
29 import net.minecraft.client.util.math.MatrixStack;
31 import java.util.ArrayList;
32 import java.util.Comparator;
33 import java.util.HashSet;
34 import java.util.LinkedList;
35 import java.util.List;
38 import java.util.concurrent.atomic.AtomicLong;
40 public class ClientRenderer {
41 private static final int CHUNK_SIZE = 16;
42 private static final Map<Class<? extends AbstractBoundingBox>, AbstractRenderer> boundingBoxRendererMap = new Object2ObjectOpenHashMap<>();
44 private static boolean active;
45 private static final Set<IBoundingBoxProvider> providers = new HashSet<>();
47 private static AtomicLong lastDurationNanos = new AtomicLong(0L);
49 public static boolean getActive() {
53 public static void toggleActive() {
60 static void deactivate() {
74 registerProvider(new SlimeChunkProvider());
75 registerProvider(new WorldSpawnProvider());
76 registerProvider(new SpawningSphereProvider());
77 registerProvider(new BeaconProvider());
78 registerProvider(new CustomBoxProvider());
79 registerProvider(new CustomBeaconProvider());
80 registerProvider(new BiomeBorderProvider());
81 registerProvider(new MobSpawnerProvider());
82 registerProvider(new ConduitProvider());
83 registerProvider(new SpawnableBlocksProvider());
84 registerProvider(new CustomLineProvider());
85 registerProvider(new CustomSphereProvider());
86 registerProvider(new FlowerForestProvider());
87 registerProvider(new BedrockCeilingProvider());
90 public static <T extends AbstractBoundingBox> void registerProvider(IBoundingBoxProvider<T> provider) {
91 providers.add(provider);
94 public static <T extends AbstractBoundingBox> AbstractRenderer<T> registerRenderer(Class<? extends T> type, AbstractRenderer<T> renderer) {
95 boundingBoxRendererMap.put(type, renderer);
99 public static AbstractRenderer getRenderer(Class<? extends AbstractBoundingBox> clazz) {
100 return boundingBoxRendererMap.get(clazz);
103 private static boolean isWithinRenderDistance(AbstractBoundingBox boundingBox) {
104 int renderDistanceBlocks = ClientInterop.getRenderDistanceChunks() * CHUNK_SIZE;
105 int minX = MathHelper.floor(Player.getX() - renderDistanceBlocks);
106 int maxX = MathHelper.floor(Player.getX() + renderDistanceBlocks);
107 int minZ = MathHelper.floor(Player.getZ() - renderDistanceBlocks);
108 int maxZ = MathHelper.floor(Player.getZ() + renderDistanceBlocks);
110 return boundingBox.intersectsBounds(minX, minZ, maxX, maxZ);
113 public static void render(MatrixStack matrixStack, DimensionId dimensionId) {
116 long startTime = System.nanoTime();
118 RenderHelper.beforeRender();
120 getBoundingBoxes(dimensionId).forEach(key -> {
121 AbstractRenderer renderer = key.getRenderer();
122 if (renderer != null) renderer.render(matrixStack, key);
125 RenderQueue.renderDeferred();
127 RenderHelper.afterRender();
129 lastDurationNanos.set(System.nanoTime() - startTime);
132 public static List<AbstractBoundingBox> getBoundingBoxes(DimensionId dimensionId) {
133 List<AbstractBoundingBox> tmp = new LinkedList<>();
134 for (IBoundingBoxProvider<?> provider : providers) {
135 if (provider.canProvide(dimensionId)) {
136 for (AbstractBoundingBox boundingBox : provider.get(dimensionId)) {
137 if (isWithinRenderDistance(boundingBox)) {
138 tmp.add(boundingBox);
144 Point point = Player.getPoint();
145 final ArrayList<AbstractBoundingBox> result = new ArrayList<>(tmp);
146 result.sort(Comparator.comparingDouble((AbstractBoundingBox boundingBox) -> boundingBox.getDistance(point.getX(), point.getY(), point.getZ())).reversed());
151 public static void clear() {
152 for(IBoundingBoxProvider<?> provider : providers) {
153 TypeHelper.doIfType(provider, ICachingProvider.class, ICachingProvider::clearCache);
157 public static long getLastDurationNanos() {
158 return lastDurationNanos.get();