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