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
3 changes: 0 additions & 3 deletions common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ loom {

dependencies {
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"

modApi "dev.architectury:architectury:${rootProject.architectury_version}"

modApi "me.shedaniel.cloth:cloth-config:${rootProject.cloth_version}"
}

Expand Down
90 changes: 50 additions & 40 deletions common/src/main/java/net/xolt/freecam/Freecam.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
package net.xolt.freecam;

import dev.architectury.event.events.client.ClientTickEvent;
import dev.architectury.registry.client.keymappings.KeyMappingRegistry;
import me.shedaniel.autoconfig.AutoConfig;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.input.Input;
import net.minecraft.client.input.KeyboardInput;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.option.Perspective;
import net.minecraft.client.util.InputUtil;
import net.minecraft.text.Text;
import net.minecraft.util.math.ChunkPos;
import net.xolt.freecam.config.ModConfig;
Expand All @@ -17,22 +14,14 @@
import org.lwjgl.glfw.GLFW;

import java.util.HashMap;
import java.util.stream.Stream;

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

public class Freecam {

public static final MinecraftClient MC = MinecraftClient.getInstance();
public static final String MOD_ID = "freecam";

public static final KeyBinding KEY_TOGGLE = new KeyBinding(
"key.freecam.toggle", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_F4, "category.freecam.freecam");
public static final KeyBinding KEY_PLAYER_CONTROL = new KeyBinding(
"key.freecam.playerControl", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_UNKNOWN, "category.freecam.freecam");
public static final KeyBinding KEY_TRIPOD_RESET = new KeyBinding(
"key.freecam.tripodReset", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_UNKNOWN, "category.freecam.freecam");
public static final KeyBinding KEY_CONFIG_GUI = new KeyBinding(
"key.freecam.configGui", InputUtil.Type.KEYSYM, GLFW.GLFW_KEY_UNKNOWN, "category.freecam.freecam");

private static boolean freecamEnabled = false;
private static boolean tripodEnabled = false;
private static boolean playerControlEnabled = false;
Expand All @@ -44,40 +33,61 @@ public class Freecam {
private static HashMap<Integer, FreecamPosition> end_tripods = new HashMap<>();
private static Perspective rememberedF5 = null;

public static void init() {
ModConfig.init();
Stream.of(KEY_TOGGLE, KEY_PLAYER_CONTROL, KEY_TRIPOD_RESET, KEY_CONFIG_GUI).forEach(KeyMappingRegistry::register);

ClientTickEvent.CLIENT_POST.register(client -> {
if (KEY_TRIPOD_RESET.isPressed()) {
for (KeyBinding hotbarKey : MC.options.hotbarKeys) {
while (hotbarKey.wasPressed()) {
resetCamera(hotbarKey.getDefaultKey().getCode());
while (KEY_TRIPOD_RESET.wasPressed()) {}
}
}
public static void preTick(MinecraftClient mc) {
if (isEnabled()) {
// Disable if the previous tick asked us to
if (disableNextTick()) {
toggle();
disableNextTick = false;
}

if (KEY_TOGGLE.isPressed()) {
for (KeyBinding hotbarKey : MC.options.hotbarKeys) {
while (hotbarKey.wasPressed()) {
toggleTripod(hotbarKey.getDefaultKey().getCode());
while (KEY_TOGGLE.wasPressed()) {}
}
}
} else if (KEY_TOGGLE.wasPressed()) {
toggle();
while (KEY_TOGGLE.wasPressed()) {}
// Prevent player from being controlled when freecam is enabled
if (mc.player != null && mc.player.input instanceof KeyboardInput && !isPlayerControlEnabled()) {
Input input = new Input();
input.sneaking = mc.player.input.sneaking; // Makes player continue to sneak after freecam is enabled.
mc.player.input = input;
}

while (KEY_PLAYER_CONTROL.wasPressed()) {
switchControls();
mc.gameRenderer.setRenderHand(ModConfig.INSTANCE.visual.showHand);
}
}

public static void postTick(MinecraftClient mc) {
if (KEY_TRIPOD_RESET.isPressed()) {
for (KeyBinding hotbarKey : mc.options.hotbarKeys) {
while (hotbarKey.wasPressed()) {
resetCamera(hotbarKey.getDefaultKey().getCode());
while (KEY_TRIPOD_RESET.wasPressed()) {}
}
}
}

while (KEY_CONFIG_GUI.wasPressed()) {
MC.setScreen(AutoConfig.getConfigScreen(ModConfig.class, MC.currentScreen).get());
if (KEY_TOGGLE.isPressed()) {
for (KeyBinding hotbarKey : mc.options.hotbarKeys) {
while (hotbarKey.wasPressed()) {
toggleTripod(hotbarKey.getDefaultKey().getCode());
while (KEY_TOGGLE.wasPressed()) {}
}
}
});
} else if (KEY_TOGGLE.wasPressed()) {
toggle();
while (KEY_TOGGLE.wasPressed()) {}
}

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

while (KEY_CONFIG_GUI.wasPressed()) {
mc.setScreen(AutoConfig.getConfigScreen(ModConfig.class, mc.currentScreen).get());
}
}

public static void onDisconnect() {
if (isEnabled()) {
toggle();
}
clearTripods();
}

public static void toggle() {
Expand Down
100 changes: 100 additions & 0 deletions common/src/main/java/net/xolt/freecam/config/ModBindings.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package net.xolt.freecam.config;

import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.util.InputUtil;
import org.jetbrains.annotations.NotNull;

import java.util.Arrays;
import java.util.Iterator;
import java.util.Objects;
import java.util.Spliterator;
import java.util.function.Consumer;

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<KeyBinding> lazyBinding;

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

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

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

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

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

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

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

/**
* Calls {@code action} using each {@link KeyBinding} 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<KeyBinding> action) {
Objects.requireNonNull(action);
iterator().forEachRemaining(action);
}

/**
* Static implementation of {@link Iterable#iterator()}.
*/
public static @NotNull Iterator<KeyBinding> iterator() {
return Arrays.stream(values())
.map(ModBindings::get)
.iterator();
}

/**
* Static implementation of {@link Iterable#spliterator()}.
*/
public static @NotNull Spliterator<KeyBinding> spliterator() {
return Arrays.stream(values())
.map(ModBindings::get)
.spliterator();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ public class ClientConnectionMixin {
// Disables freecam if the player disconnects.
@Inject(method = "handleDisconnection", at = @At("HEAD"))
private void onHandleDisconnection(CallbackInfo ci) {
if (Freecam.isEnabled()) {
Freecam.toggle();
}
Freecam.clearTripods();
Freecam.onDisconnect();
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package net.xolt.freecam.mixins;

import net.minecraft.client.MinecraftClient;
import net.minecraft.client.input.Input;
import net.minecraft.client.input.KeyboardInput;
import net.xolt.freecam.Freecam;
import net.xolt.freecam.config.ModConfig;
import org.spongepowered.asm.mixin.Mixin;
Expand All @@ -11,29 +9,12 @@
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import static net.xolt.freecam.Freecam.MC;
import static net.xolt.freecam.config.ModBindings.KEY_TOGGLE;
import static net.xolt.freecam.config.ModBindings.KEY_TRIPOD_RESET;

@Mixin(MinecraftClient.class)
public class MinecraftClientMixin {

// Prevents player from being controlled when freecam is enabled.
@Inject(method = "tick", at = @At("HEAD"))
private void onTick(CallbackInfo ci) {
if (Freecam.isEnabled()) {
if (MC.player != null && MC.player.input instanceof KeyboardInput && !Freecam.isPlayerControlEnabled()) {
Input input = new Input();
input.sneaking = MC.player.input.sneaking; // Makes player continue to sneak after freecam is enabled.
MC.player.input = input;
}
MC.gameRenderer.setRenderHand(ModConfig.INSTANCE.visual.showHand);

if (Freecam.disableNextTick()) {
Freecam.toggle();
Freecam.setDisableNextTick(false);
}
}
}

// Prevents attacks when allowInteract is disabled.
@Inject(method = "doAttack", at = @At("HEAD"), cancellable = true)
private void onDoAttack(CallbackInfoReturnable<Boolean> cir) {
Expand Down Expand Up @@ -61,7 +42,7 @@ private void onHandleBlockBreaking(CallbackInfo ci) {
// Prevents hotbar keys from changing selected slot when freecam key is held
@Inject(method = "handleInputEvents", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/KeyBinding;wasPressed()Z", ordinal = 2), cancellable = true)
private void onHandleInputEvents(CallbackInfo ci) {
if (Freecam.KEY_TOGGLE.isPressed() || Freecam.KEY_TRIPOD_RESET.isPressed()) {
if (KEY_TOGGLE.isPressed() || KEY_TRIPOD_RESET.isPressed()) {
ci.cancel();
}
}
Expand Down
3 changes: 0 additions & 3 deletions fabric/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ dependencies {
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"

modApi "dev.architectury:architectury-fabric:${rootProject.architectury_version}"
include "dev.architectury:architectury-fabric:${rootProject.architectury_version}"

modImplementation ("com.terraformersmc:modmenu:${rootProject.modmenu_version}") {
exclude module: "fabric-api"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
package net.xolt.freecam.fabric;

import net.fabricmc.api.ClientModInitializer;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.keybinding.v1.KeyBindingHelper;
import net.xolt.freecam.Freecam;
import net.xolt.freecam.config.ModBindings;
import net.xolt.freecam.config.ModConfig;

public class FreecamFabric implements ClientModInitializer {
@Override
public void onInitializeClient() {
Freecam.init();
ModConfig.init();
ModBindings.forEach(KeyBindingHelper::registerKeyBinding);
ClientTickEvents.START_CLIENT_TICK.register(Freecam::preTick);
ClientTickEvents.END_CLIENT_TICK.register(Freecam::postTick);
}
}
3 changes: 0 additions & 3 deletions forge/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ configurations {
dependencies {
forge "net.minecraftforge:forge:${rootProject.forge_version}"

modApi "dev.architectury:architectury-forge:${rootProject.architectury_version}"
include "dev.architectury:architectury-forge:${rootProject.architectury_version}"

modApi "me.shedaniel.cloth:cloth-config-forge:${rootProject.cloth_version}"
include "me.shedaniel.cloth:cloth-config-forge:${rootProject.cloth_version}"

Expand Down
39 changes: 31 additions & 8 deletions forge/src/main/java/net/xolt.freecam/forge/FreecamForge.java
Original file line number Diff line number Diff line change
@@ -1,26 +1,49 @@
package net.xolt.freecam.forge;

import dev.architectury.platform.forge.EventBuses;
import me.shedaniel.autoconfig.AutoConfig;
import net.minecraft.client.MinecraftClient;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.ConfigScreenHandler;
import net.minecraftforge.client.event.RegisterKeyMappingsEvent;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.eventbus.api.EventPriority;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.xolt.freecam.Freecam;
import net.xolt.freecam.config.ModBindings;
import net.xolt.freecam.config.ModConfig;

@Mod(Freecam.MOD_ID)
@Mod.EventBusSubscriber(bus = Bus.MOD, value = Dist.CLIENT)
public class FreecamForge {
public FreecamForge() {
// Register our event bus with Architectury
EventBuses.registerModEventBus(Freecam.MOD_ID, FMLJavaModLoadingContext.get().getModEventBus());

@SubscribeEvent
public static void clientSetup(FMLClientSetupEvent event) {
ModConfig.init();

// Register our config screen with Forge
ModLoadingContext.get().registerExtensionPoint(ConfigScreenHandler.ConfigScreenFactory.class, () -> new ConfigScreenHandler.ConfigScreenFactory((client, parent) ->
AutoConfig.getConfigScreen(ModConfig.class, parent).get()
AutoConfig.getConfigScreen(ModConfig.class, parent).get()
));
}

@SubscribeEvent
public static void registerKeymappings(RegisterKeyMappingsEvent event) {
ModBindings.forEach(event::register);
}

// Call our init
Freecam.init();
@Mod.EventBusSubscriber(bus = Bus.FORGE, value = Dist.CLIENT)
public static class GlobalEventHandler {
@SubscribeEvent(priority = EventPriority.HIGH)
public static void onTick(TickEvent.ClientTickEvent event) {
final MinecraftClient client = MinecraftClient.getInstance();
switch (event.phase) {
case START -> Freecam.preTick(client);
case END -> Freecam.postTick(client);
}
}
}
}
Loading