Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 25 additions & 47 deletions common/src/main/java/net/xolt/freecam/Freecam.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package net.xolt.freecam;

import me.shedaniel.autoconfig.AutoConfig;
import net.minecraft.client.CameraType;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.Input;
import net.minecraft.client.player.KeyboardInput;
import net.minecraft.client.renderer.texture.Tickable;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.xolt.freecam.config.ModBindings;
import net.xolt.freecam.config.ModConfig;
import net.xolt.freecam.tripod.TripodRegistry;
import net.xolt.freecam.tripod.TripodSlot;
Expand All @@ -17,20 +18,15 @@
import net.xolt.freecam.variant.api.BuildVariant;
import org.jetbrains.annotations.Nullable;

import static net.xolt.freecam.config.ModBindings.*;

public class Freecam {

public static final Minecraft MC = Minecraft.getInstance();
public static final String MOD_ID = "freecam";
private static final long TOGGLE_KEY_MAX_TICKS = 10;

private static boolean freecamEnabled = false;
private static boolean tripodEnabled = false;
private static boolean playerControlEnabled = false;
private static boolean disableNextTick = false;
private static boolean toggleKeyUsedWhileHeld = false;
private static long toggleKeyHeldTicks = 0;
private static final TripodRegistry tripods = new TripodRegistry();
private static TripodSlot activeTripod = TripodSlot.NONE;
private static FreeCamera freeCamera;
Expand All @@ -56,47 +52,7 @@ public static void preTick(Minecraft mc) {
}

public static void postTick(Minecraft mc) {
if (KEY_TOGGLE.isDown()) {
// Count held ticks, so we can toggle on release
toggleKeyHeldTicks++;
KEY_TOGGLE.reset();

// Handle <toggle_key>+<hotbar_key> combos
for (KeyMapping combo : mc.options.keyHotbarSlots) {
while (combo.consumeClick()) {
toggleTripod(TripodSlot.ofKeyCode(combo.getDefaultKey().getValue()));
toggleKeyUsedWhileHeld = true;
}
}
}
// Check if toggle was pressed, and is now released
else if (KEY_TOGGLE.consumeClick() || toggleKeyHeldTicks > 0) {
// Only toggle if the key wasn't used (or held too long)
if (!toggleKeyUsedWhileHeld && toggleKeyHeldTicks < TOGGLE_KEY_MAX_TICKS) {
toggle();
}
// Reset state
KEY_TOGGLE.reset();
toggleKeyHeldTicks = 0;
toggleKeyUsedWhileHeld = false;
}

// Handle <reset_key>+<hotbar_key> combos
if (KEY_TRIPOD_RESET.isDown()) {
for (KeyMapping key : mc.options.keyHotbarSlots) {
while (key.consumeClick()) {
resetCamera(TripodSlot.ofKeyCode(key.getDefaultKey().getValue()));
}
}
}

while (KEY_PLAYER_CONTROL.consumeClick()) {
switchControls();
}

while (KEY_CONFIG_GUI.consumeClick()) {
mc.setScreen(AutoConfig.getConfigScreen(ModConfig.class, mc.screen).get());
}
ModBindings.forEach(Tickable::tick);
}

public static void onDisconnect() {
Expand All @@ -106,6 +62,28 @@ public static void onDisconnect() {
tripods.clear();
}

public static boolean activateTripodHandler() {
boolean activated = false;
for (KeyMapping combo : MC.options.keyHotbarSlots) {
while (combo.consumeClick()) {
toggleTripod(TripodSlot.ofKeyCode(combo.getDefaultKey().getValue()));
activated = true;
}
}
return activated;
}

public static boolean resetTripodHandler() {
boolean reset = false;
for (KeyMapping key : MC.options.keyHotbarSlots) {
while (key.consumeClick()) {
resetCamera(TripodSlot.ofKeyCode(key.getDefaultKey().getValue()));
reset = true;
}
}
return reset;
}

public static void toggle() {
if (tripodEnabled) {
toggleTripod(activeTripod);
Expand Down
90 changes: 31 additions & 59 deletions common/src/main/java/net/xolt/freecam/config/ModBindings.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.mojang.blaze3d.platform.InputConstants;
import net.minecraft.client.KeyMapping;
import me.shedaniel.autoconfig.AutoConfig;
import net.xolt.freecam.Freecam;
import net.xolt.freecam.config.keys.FreecamKeyMapping;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
Expand All @@ -12,89 +13,60 @@
import java.util.Spliterator;
import java.util.function.Consumer;

import static net.xolt.freecam.Freecam.MC;
import static net.xolt.freecam.config.keys.FreecamKeyMappingBuilder.builder;
import static org.lwjgl.glfw.GLFW.GLFW_KEY_F4;
import static org.lwjgl.glfw.GLFW.GLFW_KEY_UNKNOWN;

public enum ModBindings {

KEY_TOGGLE("toggle", GLFW_KEY_F4),
KEY_PLAYER_CONTROL("playerControl"),
KEY_TRIPOD_RESET("tripodReset"),
KEY_CONFIG_GUI("configGui");

private final Supplier<KeyMapping> lazyMapping;

ModBindings(String translationKey) {
this(translationKey, InputConstants.Type.KEYSYM, GLFW_KEY_UNKNOWN);
}

ModBindings(String translationKey, int code) {
this(translationKey, InputConstants.Type.KEYSYM, code);
}

ModBindings(String translationKey, InputConstants.Type type) {
this(translationKey, type, GLFW_KEY_UNKNOWN);
}

ModBindings(String translationKey, InputConstants.Type type, int code) {
this.lazyMapping = Suppliers.memoize(() ->
new KeyMapping("key.freecam." + translationKey, type, code, "category.freecam.freecam"));
}

/**
* @return the result of calling {@link KeyMapping#isDown()} on the represented {@link KeyMapping}.
* @see KeyMapping#isDown()
*/
public boolean isDown() {
return get().isDown();
}

/**
* @return the result of calling {@link KeyMapping#consumeClick()} on the represented {@link KeyMapping}.
* @see KeyMapping#consumeClick()
*/
public boolean consumeClick() {
return get().consumeClick();
}

/**
* Reset whether the key was pressed.
* <p>
* Note: Cannot use {@link KeyMapping#release()} because it doesn't work as expected.
*/
@SuppressWarnings("StatementWithEmptyBody")
public void reset() {
final KeyMapping key = get();
while (key.consumeClick()) {}
KEY_TOGGLE(() -> builder("toggle")
.action(Freecam::toggle)
.holdAction(Freecam::activateTripodHandler)
.defaultKey(GLFW_KEY_F4)
.build()),
KEY_PLAYER_CONTROL(() -> builder("playerControl")
.action(Freecam::switchControls)
.build()),
KEY_TRIPOD_RESET(() -> builder("tripodReset")
.holdAction(Freecam::resetTripodHandler)
.build()),
KEY_CONFIG_GUI(() -> builder("configGui")
.action(() -> MC.setScreen(AutoConfig.getConfigScreen(ModConfig.class, MC.screen).get()))
.build());

private final Supplier<FreecamKeyMapping> lazyMapping;

ModBindings(Supplier<FreecamKeyMapping> mappingSupplier) {
lazyMapping = Suppliers.memoize(mappingSupplier);
}

/**
* Lazily get the actual {@link KeyMapping} represented by this enum value.
* Lazily get the actual {@link FreecamKeyMapping} represented by this enum value.
* <p>
* Values are constructed if they haven't been already.
*
* @return the actual {@link KeyMapping}.
* @return the actual {@link FreecamKeyMapping}.
*/
public KeyMapping get() {
public FreecamKeyMapping get() {
return lazyMapping.get();
}

/**
* Calls {@code action} using each {@link KeyMapping} owned by this enum.
* Calls {@code action} using each {@link FreecamKeyMapping} owned by this enum.
* <p>
* Values are constructed if they haven't been already.
* <p>
* Static implementation of {@link Iterable#forEach(Consumer)}.
*/
public static void forEach(@NotNull Consumer<KeyMapping> action) {
public static void forEach(@NotNull Consumer<FreecamKeyMapping> action) {
Objects.requireNonNull(action);
iterator().forEachRemaining(action);
}

/**
* Static implementation of {@link Iterable#iterator()}.
*/
public static @NotNull Iterator<KeyMapping> iterator() {
public static @NotNull Iterator<FreecamKeyMapping> iterator() {
return Arrays.stream(values())
.map(ModBindings::get)
.iterator();
Expand All @@ -103,7 +75,7 @@ public static void forEach(@NotNull Consumer<KeyMapping> action) {
/**
* Static implementation of {@link Iterable#spliterator()}.
*/
public static @NotNull Spliterator<KeyMapping> spliterator() {
public static @NotNull Spliterator<FreecamKeyMapping> spliterator() {
return Arrays.stream(values())
.map(ModBindings::get)
.spliterator();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package net.xolt.freecam.config.keys;

import com.mojang.blaze3d.platform.InputConstants;


class FreecamComboKeyMapping extends FreecamKeyMapping {

private final Runnable action;
private final HoldAction holdAction;
private final long maxHoldTicks;

private boolean usedWhileHeld = false;
private long ticksHeld = 0;

FreecamComboKeyMapping(String translationKey, InputConstants.Type type, int code, Runnable action, HoldAction holdAction, long maxHoldTicks) {
super(translationKey, type, code);
this.action = action;
this.holdAction = holdAction;
this.maxHoldTicks = maxHoldTicks;
}

@Override
public void tick() {
if (isDown()) {
// Count held ticks, so we can run action on release
ticksHeld++;
reset();

// Handle combo actions
if (holdAction.run()) {
usedWhileHeld = true;
}
}
// Check if pressed, but now released
else if (consumeClick() || ticksHeld > 0) {
// Only run action if the key wasn't used (or held too long)
if (!usedWhileHeld && ticksHeld < maxHoldTicks) {
action.run();
}
// Reset state
reset();
ticksHeld = 0;
usedWhileHeld = false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package net.xolt.freecam.config.keys;

import com.mojang.blaze3d.platform.InputConstants;
import net.minecraft.client.KeyMapping;
import net.minecraft.client.renderer.texture.Tickable;

import java.util.function.Consumer;

public class FreecamKeyMapping extends KeyMapping implements Tickable {

private final Consumer<FreecamKeyMapping> onTick;

/**
* @apiNote should only be used if overriding {@link #tick()}
*/
protected FreecamKeyMapping(String translationKey, InputConstants.Type type, int code) {
this(translationKey, type, code, null);
}

FreecamKeyMapping(String translationKey, InputConstants.Type type, int code, Consumer<FreecamKeyMapping> onTick) {
super("key.freecam." + translationKey, type, code, "category.freecam.freecam");
this.onTick = onTick;
}

@Override
public void tick() {
onTick.accept(this);
}

/**
* Reset whether the key was pressed.
* <p>
* @implNote Cannot use {@link KeyMapping#release()} because it doesn't work as expected.
*/
@SuppressWarnings("StatementWithEmptyBody")
public void reset() {
while (consumeClick()) {}
}
}
Loading