/* * This file is part of the Distant Horizons mod (formerly the LOD Mod), * licensed under the GNU LGPL v3 License. * * Copyright (C) 2020-2022 James Seibel * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, version 3. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . */ package com.seibel.lod; import com.seibel.lod.common.wrappers.McObjectConverter; import com.seibel.lod.common.wrappers.world.ClientLevelWrapper; import com.seibel.lod.core.api.internal.ClientApi; import com.seibel.lod.core.config.Config; import com.mojang.blaze3d.platform.InputConstants; import com.seibel.lod.common.wrappers.chunk.ChunkWrapper; import com.seibel.lod.core.logging.DhLoggerBuilder; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientChunkEvents; import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.TitleScreen; import java.util.HashSet; import org.apache.logging.log4j.Logger; import org.lwjgl.glfw.GLFW; /** * This handles all events sent to the client, * and is the starting point for most of the mod. * * @author coolGi * @author Ran * @version 11-23-2021 */ @Environment(EnvType.CLIENT) public class FabricClientProxy { private final ClientApi clientApi = ClientApi.INSTANCE; private static final Logger LOGGER = DhLoggerBuilder.getLogger("FabricClientProxy"); /** * Registers Fabric Events * @author Ran */ public void registerEvents() { LOGGER.info("Registering Fabric Client Events"); /* Register the mod needed event callbacks */ // ClientTickEvent ClientTickEvents.START_CLIENT_TICK.register((client) -> { //LOGGER.info("ClientTickEvent.START_CLIENT_TICK"); ClientApi.INSTANCE.clientTickEvent(); }); // ClientLevelLoadEvent - Done in MixinClientPacketListener // ClientLevelUnloadEvent - Done in MixinClientPacketListener // ClientChunkLoadEvent // TODO: Is using setClientLightReady one still better? //#if PRE_MC_1_18_1 // in 1.18+, we use mixin hook in setClientLightReady(true) ClientChunkEvents.CHUNK_LOAD.register((level, chunk) -> { ClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level); ClientApi.INSTANCE.clientChunkLoadEvent( new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel ); }); //#endif // ClientChunkSaveEvent ClientChunkEvents.CHUNK_UNLOAD.register((level, chunk) -> { ClientLevelWrapper wrappedLevel = ClientLevelWrapper.getWrapper(level); ClientApi.INSTANCE.clientChunkSaveEvent( new ChunkWrapper(chunk, level, wrappedLevel), wrappedLevel ); }); // RendererStartupEvent - Done in MixinGameRenderer // RendererShutdownEvent - Done in MixinGameRenderer // ClientRenderLevelTerrainEvent WorldRenderEvents.AFTER_SETUP.register((renderContext) -> clientApi.renderLods(ClientLevelWrapper.getWrapper(renderContext.world()), McObjectConverter.Convert(renderContext.matrixStack().last().pose()), McObjectConverter.Convert(renderContext.projectionMatrix()), renderContext.tickDelta()) ); // Debug keyboard event // FIXME: Use better hooks so it doesn't trigger even in text boxes ClientTickEvents.END_CLIENT_TICK.register(client -> { if (client.player != null && isValidTime()) onKeyInput(); }); } private boolean isValidTime() { return !(Minecraft.getInstance().screen instanceof TitleScreen); } // public void blockChangeEvent(LevelAccessor world, BlockPos pos) { // if (!isValidTime()) return; // IChunkWrapper chunk = new ChunkWrapper(world.getChunk(pos), world); // DimensionTypeWrapper dimType = DimensionTypeWrapper.getDimensionTypeWrapper(world.dimensionType()); // // // recreate the LOD where the blocks were changed // // TODO: serverApi.blockChangeEvent(chunk, dimType); // } private static final int[] KEY_TO_CHECK_FOR = {GLFW.GLFW_KEY_F6, GLFW.GLFW_KEY_F8}; HashSet previousKeyDown = new HashSet<>(); public void onKeyInput() { if (Config.Client.Advanced.Debugging.enableDebugKeybindings.get()) { HashSet currentKeyDown = new HashSet(); // Note: Minecraft's InputConstants is same as GLFW Key values //TODO: Use mixin to hook directly into the GLFW Keyboard event in minecraft KeyboardHandler // Check all keys we need for (int i = GLFW.GLFW_KEY_A; i <= GLFW.GLFW_KEY_Z; i++) { if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), i)) { currentKeyDown.add(i); } } for (int i : KEY_TO_CHECK_FOR) { if (InputConstants.isKeyDown(Minecraft.getInstance().getWindow().getWindow(), i)) { currentKeyDown.add(i); } } // Diff and trigger events for (int c : currentKeyDown) { if (!previousKeyDown.contains(c)) { ClientApi.INSTANCE.keyPressedEvent(c); } } // Update the set previousKeyDown = currentKeyDown; } } }