]> git.lizzy.rs Git - LightOverlay.git/blob - src/main/java/me/shedaniel/lightoverlay/LightOverlayClient.java
1.15
[LightOverlay.git] / src / main / java / me / shedaniel / lightoverlay / LightOverlayClient.java
1 package me.shedaniel.lightoverlay;
2
3 import com.mojang.blaze3d.systems.RenderSystem;
4 import net.minecraft.block.Block;
5 import net.minecraft.block.BlockState;
6 import net.minecraft.client.Minecraft;
7 import net.minecraft.client.entity.player.ClientPlayerEntity;
8 import net.minecraft.client.renderer.ActiveRenderInfo;
9 import net.minecraft.client.renderer.BufferBuilder;
10 import net.minecraft.client.renderer.Tessellator;
11 import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
12 import net.minecraft.client.settings.KeyBinding;
13 import net.minecraft.client.util.InputMappings;
14 import net.minecraft.entity.Entity;
15 import net.minecraft.entity.EntityClassification;
16 import net.minecraft.entity.EntityType;
17 import net.minecraft.entity.player.PlayerEntity;
18 import net.minecraft.tags.BlockTags;
19 import net.minecraft.util.Direction;
20 import net.minecraft.util.ResourceLocation;
21 import net.minecraft.util.math.BlockPos;
22 import net.minecraft.util.math.shapes.ISelectionContext;
23 import net.minecraft.util.math.shapes.VoxelShape;
24 import net.minecraft.util.text.TranslationTextComponent;
25 import net.minecraft.world.LightType;
26 import net.minecraft.world.World;
27 import net.minecraft.world.biome.Biome;
28 import net.minecraftforge.api.distmarker.Dist;
29 import net.minecraftforge.client.event.InputEvent;
30 import net.minecraftforge.client.event.RenderWorldLastEvent;
31 import net.minecraftforge.client.settings.KeyConflictContext;
32 import net.minecraftforge.client.settings.KeyModifier;
33 import net.minecraftforge.common.MinecraftForge;
34 import net.minecraftforge.eventbus.api.SubscribeEvent;
35 import net.minecraftforge.fml.DistExecutor;
36 import net.minecraftforge.fml.client.registry.ClientRegistry;
37
38 import java.io.File;
39 import java.io.FileInputStream;
40 import java.io.FileOutputStream;
41 import java.io.IOException;
42 import java.text.DecimalFormat;
43 import java.util.Properties;
44
45 public class LightOverlayClient {
46     
47     static final DecimalFormat FORMAT = new DecimalFormat("#.#");
48     private static final String KEYBIND_CATEGORY = "key.lightoverlay-forge.category";
49     private static final ResourceLocation ENABLE_OVERLAY_KEYBIND = new ResourceLocation("lightoverlay-forge", "enable_overlay");
50     private static final ResourceLocation INCREASE_REACH_KEYBIND = new ResourceLocation("lightoverlay-forge", "increase_reach");
51     private static final ResourceLocation DECREASE_REACH_KEYBIND = new ResourceLocation("lightoverlay-forge", "decrease_reach");
52     private static final ResourceLocation INCREASE_LINE_WIDTH_KEYBIND = new ResourceLocation("lightoverlay-forge", "increase_line_width");
53     private static final ResourceLocation DECREASE_LINE_WIDTH_KEYBIND = new ResourceLocation("lightoverlay-forge", "decrease_line_width");
54     static int reach = 7;
55     static EntityType<Entity> testingEntityType;
56     static float lineWidth = 1.0F;
57     static int yellowColor = 0xFFFF00, redColor = 0xFF0000;
58     static File configFile = new File(new File(Minecraft.getInstance().gameDir, "config"), "lightoverlay.properties");
59     private static KeyBinding enableOverlay, increaseReach, decreaseReach, increaseLineWidth, decreaseLineWidth;
60     private static boolean enabled = false;
61     
62     public static void register() {
63         // Load Config
64         loadConfig(configFile);
65         
66         // Setup
67         testingEntityType = EntityType.Builder.create(EntityClassification.MONSTER).size(0f, 0f).disableSerialization().build(null);
68         enableOverlay = registerKeybind(ENABLE_OVERLAY_KEYBIND, InputMappings.Type.KEYSYM, 296, KEYBIND_CATEGORY);
69         increaseReach = registerKeybind(INCREASE_REACH_KEYBIND, InputMappings.Type.KEYSYM, -1, KEYBIND_CATEGORY);
70         decreaseReach = registerKeybind(DECREASE_REACH_KEYBIND, InputMappings.Type.KEYSYM, -1, KEYBIND_CATEGORY);
71         increaseLineWidth = registerKeybind(INCREASE_LINE_WIDTH_KEYBIND, InputMappings.Type.KEYSYM, -1, KEYBIND_CATEGORY);
72         decreaseLineWidth = registerKeybind(DECREASE_LINE_WIDTH_KEYBIND, InputMappings.Type.KEYSYM, -1, KEYBIND_CATEGORY);
73         MinecraftForge.EVENT_BUS.register(LightOverlayClient.class);
74         
75         try {
76             DistExecutor.runWhenOn(Dist.CLIENT, () -> () -> LightOverlayCloth.register());
77         } catch (Exception e) {
78             e.printStackTrace();
79         }
80     }
81     
82     public static CrossType getCrossType(BlockPos pos, World world, PlayerEntity playerEntity) {
83         BlockState blockBelowState = world.getBlockState(pos.down());
84         BlockState blockUpperState = world.getBlockState(pos);
85         VoxelShape upperCollisionShape = blockUpperState.getCollisionShape(world, pos, ISelectionContext.forEntity(playerEntity));
86         if (!blockUpperState.getFluidState().isEmpty())
87             return CrossType.NONE;
88         /* WorldEntitySpawner.func_222266_a */
89         // Check if the outline is full
90         if (Block.doesSideFillSquare(upperCollisionShape, Direction.UP))
91             return CrossType.NONE;
92         // Check if there is power
93         if (blockUpperState.canProvidePower())
94             return CrossType.NONE;
95         // Check if the collision has a bump
96         if (upperCollisionShape.getEnd(Direction.Axis.Y) > 0)
97             return CrossType.NONE;
98         if (blockUpperState.getBlock().isIn(BlockTags.RAILS))
99             return CrossType.NONE;
100         // Check block state allow spawning (excludes bedrock and barriers automatically)
101         if (!blockBelowState.canEntitySpawn(world, pos.down(), testingEntityType))
102             return CrossType.NONE;
103         if (world.func_226658_a_(LightType.BLOCK, pos) >= 8)
104             return CrossType.NONE;
105         if (world.func_226658_a_(LightType.SKY, pos) >= 8)
106             return CrossType.YELLOW;
107         return CrossType.RED;
108     }
109     
110     public static void renderCross(World world, BlockPos pos, int color, PlayerEntity entity) {
111         ActiveRenderInfo info = Minecraft.getInstance().gameRenderer.getActiveRenderInfo();
112         RenderSystem.lineWidth(lineWidth);
113         RenderSystem.depthMask(false);
114         Tessellator tessellator = Tessellator.getInstance();
115         BufferBuilder buffer = tessellator.getBuffer();
116         double d0 = info.getProjectedView().x;
117         double d1 = info.getProjectedView().y - .005D;
118         VoxelShape upperOutlineShape = world.getBlockState(pos).getShape(world, pos, ISelectionContext.forEntity(entity));
119         if (!upperOutlineShape.isEmpty())
120             d1 -= upperOutlineShape.getEnd(Direction.Axis.Y);
121         double d2 = info.getProjectedView().z;
122         buffer.begin(1, DefaultVertexFormats.POSITION_COLOR);
123         int red = (color >> 16) & 255;
124         int green = (color >> 8) & 255;
125         int blue = color & 255;
126         buffer.func_225582_a_(pos.getX() + .01 - d0, pos.getY() - d1, pos.getZ() + .01 - d2).func_225586_a_(red, green, blue, 255).endVertex();
127         buffer.func_225582_a_(pos.getX() - .01 + 1 - d0, pos.getY() - d1, pos.getZ() - .01 + 1 - d2).func_225586_a_(red, green, blue, 255).endVertex();
128         buffer.func_225582_a_(pos.getX() - .01 + 1 - d0, pos.getY() - d1, pos.getZ() + .01 - d2).func_225586_a_(red, green, blue, 255).endVertex();
129         buffer.func_225582_a_(pos.getX() + .01 - d0, pos.getY() - d1, pos.getZ() - .01 + 1 - d2).func_225586_a_(red, green, blue, 255).endVertex();
130         tessellator.draw();
131         RenderSystem.depthMask(true);
132     }
133     
134     @SubscribeEvent(receiveCanceled = true)
135     public static void handleInput(InputEvent.KeyInputEvent event) {
136         if (enableOverlay.isPressed())
137             enabled = !enabled;
138         if (increaseReach.isPressed()) {
139             if (reach < 50)
140                 reach++;
141             try {
142                 saveConfig(configFile);
143             } catch (IOException e) {
144                 e.printStackTrace();
145             }
146             Minecraft.getInstance().player.sendStatusMessage(new TranslationTextComponent("text.lightoverlay-forge.current_reach", reach), false);
147         }
148         if (decreaseReach.isPressed()) {
149             if (reach > 1)
150                 reach--;
151             try {
152                 saveConfig(configFile);
153             } catch (IOException e) {
154                 e.printStackTrace();
155             }
156             Minecraft.getInstance().player.sendStatusMessage(new TranslationTextComponent("text.lightoverlay-forge.current_reach", reach), false);
157         }
158         if (increaseLineWidth.isPressed()) {
159             if (lineWidth < 7)
160                 lineWidth += 0.1f;
161             try {
162                 saveConfig(configFile);
163             } catch (IOException e) {
164                 e.printStackTrace();
165             }
166             Minecraft.getInstance().player.sendStatusMessage(new TranslationTextComponent("text.lightoverlay-forge.current_line_width", FORMAT.format(lineWidth)), false);
167         }
168         if (decreaseLineWidth.isPressed()) {
169             if (lineWidth > 1)
170                 lineWidth -= 0.1F;
171             try {
172                 saveConfig(configFile);
173             } catch (IOException e) {
174                 e.printStackTrace();
175             }
176             Minecraft.getInstance().player.sendStatusMessage(new TranslationTextComponent("text.lightoverlay-forge.current_line_width", FORMAT.format(lineWidth)), false);
177         }
178     }
179     
180     @SubscribeEvent
181     public static void renderWorldLast(RenderWorldLastEvent event) {
182         if (LightOverlayClient.enabled) {
183             RenderSystem.pushMatrix();
184             RenderSystem.loadIdentity();
185             RenderSystem.multMatrix(event.getMatrixStack().func_227866_c_().func_227870_a_());
186             Minecraft client = Minecraft.getInstance();
187             ClientPlayerEntity playerEntity = client.player;
188             World world = client.world;
189             RenderSystem.disableTexture();
190             RenderSystem.disableBlend();
191             BlockPos playerPos = playerEntity.getPosition();
192             BlockPos.getAllInBox(playerPos.add(-reach, -reach, -reach), playerPos.add(reach, reach, reach)).forEach(pos -> {
193                 Biome biome = world.func_226691_t_(pos);
194                 if (biome.getSpawningChance() > 0 && !biome.getSpawns(EntityClassification.MONSTER).isEmpty()) {
195                     CrossType type = LightOverlayClient.getCrossType(pos, world, playerEntity);
196                     if (type != CrossType.NONE) {
197                         VoxelShape shape = world.getBlockState(pos).getCollisionShape(world, pos);
198                         int color = type == CrossType.RED ? redColor : yellowColor;
199                         LightOverlayClient.renderCross(world, pos, color, playerEntity);
200                     }
201                 }
202             });
203             RenderSystem.popMatrix();
204         }
205     }
206     
207     private static KeyBinding registerKeybind(ResourceLocation resourceLocation, InputMappings.Type type, int keyCode, String category) {
208         KeyBinding keyBinding = new KeyBinding("key." + resourceLocation.getNamespace() + "." + resourceLocation.getPath(), KeyConflictContext.IN_GAME, KeyModifier.NONE, type, keyCode, category);
209         ClientRegistry.registerKeyBinding(keyBinding);
210         return keyBinding;
211     }
212     
213     static void loadConfig(File file) {
214         try {
215             redColor = 0xFF0000;
216             yellowColor = 0xFFFF00;
217             if (!file.exists() || !file.canRead())
218                 saveConfig(file);
219             FileInputStream fis = new FileInputStream(file);
220             Properties properties = new Properties();
221             properties.load(fis);
222             fis.close();
223             reach = Integer.parseInt((String) properties.computeIfAbsent("reach", a -> "7"));
224             lineWidth = Float.valueOf((String) properties.computeIfAbsent("lineWidth", a -> "1"));
225             {
226                 int r, g, b;
227                 r = Integer.parseInt((String) properties.computeIfAbsent("yellowColorRed", a -> "255"));
228                 g = Integer.parseInt((String) properties.computeIfAbsent("yellowColorGreen", a -> "255"));
229                 b = Integer.parseInt((String) properties.computeIfAbsent("yellowColorBlue", a -> "0"));
230                 yellowColor = (r << 16) + (g << 8) + b;
231             }
232             {
233                 int r, g, b;
234                 r = Integer.parseInt((String) properties.computeIfAbsent("redColorRed", a -> "255"));
235                 g = Integer.parseInt((String) properties.computeIfAbsent("redColorGreen", a -> "0"));
236                 b = Integer.parseInt((String) properties.computeIfAbsent("redColorBlue", a -> "0"));
237                 redColor = (r << 16) + (g << 8) + b;
238             }
239             saveConfig(file);
240         } catch (Exception e) {
241             e.printStackTrace();
242             reach = 7;
243             lineWidth = 1.0F;
244             redColor = 0xFF0000;
245             yellowColor = 0xFFFF00;
246             try {
247                 saveConfig(file);
248             } catch (IOException ex) {
249                 ex.printStackTrace();
250             }
251         }
252     }
253     
254     static void saveConfig(File file) throws IOException {
255         FileOutputStream fos = new FileOutputStream(file, false);
256         fos.write("# Light Overlay Config".getBytes());
257         fos.write("\n".getBytes());
258         fos.write(("reach=" + reach).getBytes());
259         fos.write("\n".getBytes());
260         fos.write(("lineWidth=" + FORMAT.format(lineWidth)).getBytes());
261         fos.write("\n".getBytes());
262         fos.write(("yellowColorRed=" + ((yellowColor >> 16) & 255)).getBytes());
263         fos.write("\n".getBytes());
264         fos.write(("yellowColorGreen=" + ((yellowColor >> 8) & 255)).getBytes());
265         fos.write("\n".getBytes());
266         fos.write(("yellowColorBlue=" + (yellowColor & 255)).getBytes());
267         fos.write("\n".getBytes());
268         fos.write(("redColorRed=" + ((redColor >> 16) & 255)).getBytes());
269         fos.write("\n".getBytes());
270         fos.write(("redColorGreen=" + ((redColor >> 8) & 255)).getBytes());
271         fos.write("\n".getBytes());
272         fos.write(("redColorBlue=" + (redColor & 255)).getBytes());
273         fos.close();
274     }
275     
276     private static enum CrossType {
277         YELLOW,
278         RED,
279         NONE
280     }
281     
282 }