]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/blob - src/main/java/com/irtimaled/bbor/client/ClientRenderer.java
General performance improvements and serverside fixes
[BoundingBoxOutlineReloaded.git] / src / main / java / com / irtimaled / bbor / client / ClientRenderer.java
1 package com.irtimaled.bbor.client;
2
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.Object2ObjectMaps;
29 import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
30 import net.fabricmc.api.EnvType;
31 import net.fabricmc.loader.api.FabricLoader;
32 import net.minecraft.client.util.math.MatrixStack;
33
34 import java.util.ArrayList;
35 import java.util.Comparator;
36 import java.util.HashSet;
37 import java.util.LinkedList;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.Set;
41 import java.util.concurrent.atomic.AtomicLong;
42 import java.util.function.Supplier;
43
44 public class ClientRenderer {
45     private static final int CHUNK_SIZE = 16;
46     private static final Map<Class<? extends AbstractBoundingBox>, AbstractRenderer> boundingBoxRendererMap = Object2ObjectMaps.synchronize(new Object2ObjectOpenHashMap<>());
47
48     private static boolean active;
49     private static final Set<IBoundingBoxProvider> providers = new HashSet<>();
50
51     private static AtomicLong lastDurationNanos = new AtomicLong(0L);
52
53     public static boolean getActive() {
54         return active;
55     }
56
57     public static void toggleActive() {
58         active = !active;
59         if (!active) return;
60
61         Player.setActiveY();
62     }
63
64     static void deactivate() {
65         active = false;
66     }
67
68     static {
69         if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) {
70             registerProvider(new SlimeChunkProvider());
71             registerProvider(new WorldSpawnProvider());
72             registerProvider(new SpawningSphereProvider());
73             registerProvider(new BeaconProvider());
74             registerProvider(new CustomBoxProvider());
75             registerProvider(new CustomBeaconProvider());
76             registerProvider(new BiomeBorderProvider());
77             registerProvider(new MobSpawnerProvider());
78             registerProvider(new ConduitProvider());
79             registerProvider(new SpawnableBlocksProvider());
80             registerProvider(new CustomLineProvider());
81             registerProvider(new CustomSphereProvider());
82             registerProvider(new FlowerForestProvider());
83             registerProvider(new BedrockCeilingProvider());
84         }
85     }
86
87     public static <T extends AbstractBoundingBox> void registerProvider(IBoundingBoxProvider<T> provider) {
88         providers.add(provider);
89     }
90
91     public static <T extends AbstractBoundingBox> AbstractRenderer<T> registerRenderer(Class<? extends T> type, Supplier<AbstractRenderer<T>> renderer) {
92         if (FabricLoader.getInstance().getEnvironmentType() != EnvType.CLIENT) return null;
93         final AbstractRenderer<T> renderer1 = renderer.get();
94         boundingBoxRendererMap.put(type, renderer1);
95         return renderer1;
96     }
97
98     public static AbstractRenderer getRenderer(Class<? extends AbstractBoundingBox> clazz) {
99         return boundingBoxRendererMap.get(clazz);
100     }
101
102     private static boolean isWithinRenderDistance(AbstractBoundingBox boundingBox) {
103         int renderDistanceBlocks = ClientInterop.getRenderDistanceChunks() * CHUNK_SIZE;
104         int minX = MathHelper.floor(Player.getX() - renderDistanceBlocks);
105         int maxX = MathHelper.floor(Player.getX() + renderDistanceBlocks);
106         int minZ = MathHelper.floor(Player.getZ() - renderDistanceBlocks);
107         int maxZ = MathHelper.floor(Player.getZ() + renderDistanceBlocks);
108
109         return boundingBox.intersectsBounds(minX, minZ, maxX, maxZ);
110     }
111
112     public static void render(MatrixStack matrixStack, DimensionId dimensionId) {
113         if (!active) return;
114
115         long startTime = System.nanoTime();
116         matrixStack.push();
117         RenderHelper.beforeRender();
118
119         for (AbstractBoundingBox key : getBoundingBoxes(dimensionId)) {
120             AbstractRenderer renderer = key.getRenderer();
121             if (renderer != null) renderer.render(matrixStack, key);
122         }
123
124         RenderQueue.renderDeferred();
125
126         RenderHelper.afterRender();
127         matrixStack.pop();
128         lastDurationNanos.set(System.nanoTime() - startTime);
129     }
130
131     public static List<AbstractBoundingBox> getBoundingBoxes(DimensionId dimensionId) {
132         List<AbstractBoundingBox> tmp = new LinkedList<>();
133         for (IBoundingBoxProvider<?> provider : providers) {
134             if (provider.canProvide(dimensionId)) {
135                 for (AbstractBoundingBox boundingBox : provider.get(dimensionId)) {
136                     if (boundingBox.isVisibleCulling() && isWithinRenderDistance(boundingBox)) {
137                         tmp.add(boundingBox);
138                     }
139                 }
140             }
141         }
142
143         Point point = Player.getPoint();
144         final ArrayList<AbstractBoundingBox> result = new ArrayList<>(tmp);
145         result.sort(Comparator.comparingDouble((AbstractBoundingBox boundingBox) -> boundingBox.getDistance(point.getX(), point.getY(), point.getZ())).reversed());
146
147         return result;
148     }
149
150     public static void clear() {
151         for(IBoundingBoxProvider<?> provider : providers) {
152             TypeHelper.doIfType(provider, ICachingProvider.class, ICachingProvider::clearCache);
153         }
154     }
155
156     public static long getLastDurationNanos() {
157         return lastDurationNanos.get();
158     }
159
160
161 }