Skip to content
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# User-specific stuff
.idea/
.vscode/

*.iml
*.ipr
Expand Down
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ This mod works in multiplayer, but may be considered cheating on some servers, s
|----------------|-------------------------------------------------------------------------------------------------------------------------|--------------|
| Toggle Freecam | Enables/disables Freecam | `F4` |
| Config GUI | Opens the settings screen. | `Unbound` |
| Goto GUI | Opens a "goto" screen, which allows jumping Freecam to any player within range. | `G` |
| Control Player | Transfers control back to your player, but retains your current perspective (Can only be used while Freecam is active.) | `Unbound` |
| Reset Tripod | Resets a tripod\* camera when pressed in combination with any of the hotbar keys | `Unbound` |

Expand Down Expand Up @@ -53,10 +54,11 @@ This mod works in multiplayer, but may be considered cheating on some servers, s

## Notification Options

| Name | Description | Default Value |
|-----------------------|---------------------------------------------------------|---------------|
| Freecam Notifications | Notifies you when entering/exiting freecam. | `true` |
| Tripod Notifications | Notifies you when entering/exiting tripod cameras.<br/> | `true` |
| Name | Description | Default Value |
|-----------------------|-----------------------------------------------------------|---------------|
| Freecam Notifications | Notifies you when entering/exiting freecam. | `true` |
| Tripod Notifications | Notifies you when entering/exiting tripod cameras. | `true` |
| Goto Notifications | Notifies you when using "Goto" to teleport the camera. | `true` |

## Requirements

Expand Down
110 changes: 47 additions & 63 deletions common/src/main/java/net/xolt/freecam/Freecam.java
Original file line number Diff line number Diff line change
@@ -1,21 +1,17 @@
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.network.chat.Component;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.xolt.freecam.config.ModConfig;
import net.xolt.freecam.gui.go.GotoScreen;
import net.xolt.freecam.tripod.TripodRegistry;
import net.xolt.freecam.tripod.TripodSlot;
import net.xolt.freecam.util.FreeCamera;
import net.xolt.freecam.util.FreecamPosition;
import net.xolt.freecam.variant.api.BuildVariant;
import org.jetbrains.annotations.Nullable;

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

Expand Down Expand Up @@ -50,7 +46,7 @@ public static void preTick(Minecraft mc) {
mc.player.input = input;
}

mc.gameRenderer.setRenderHand(ModConfig.INSTANCE.visual.showHand);
mc.gameRenderer.setRenderHand(ModConfig.get().visual.showHand);
}
disableNextTick = false;
}
Expand Down Expand Up @@ -94,8 +90,12 @@ else if (KEY_TOGGLE.consumeClick() || toggleKeyHeldTicks > 0) {
switchControls();
}

while (KEY_GOTO_GUI.consumeClick()) {
mc.setScreen(new GotoScreen());
}

while (KEY_CONFIG_GUI.consumeClick()) {
mc.setScreen(AutoConfig.getConfigScreen(ModConfig.class, mc.screen).get());
mc.setScreen(ModConfig.getScreen(mc.screen));
}
}

Expand Down Expand Up @@ -123,6 +123,29 @@ public static void toggle() {
}
}

public static void gotoPosition(FreecamPosition position) {
boolean wasEnabled = isEnabled();
if (!wasEnabled) {
// FIXME this will move the camera to the default position and show a notification,
// even though we'll move the camera and show our own notification immediately after.
toggle();
}

freeCamera.applyPosition(position);

if (ModConfig.get().notification.notifyGoto) {
Component notification;
if (!wasEnabled) {
notification = Component.translatable("msg.freecam.gotoPosition.enable", position.getName());
} else if (tripodEnabled) {
notification = Component.translatable("msg.freecam.gotoPosition.moveTripod", activeTripod, position.getName());
} else {
notification = Component.translatable("msg.freecam.gotoPosition.move", position.getName());
}
MC.player.displayClientMessage(notification, true);
}
}

private static void toggleTripod(TripodSlot tripod) {
if (tripod == TripodSlot.NONE) {
return;
Expand Down Expand Up @@ -165,40 +188,30 @@ public static void switchControls() {
private static void onEnableTripod(TripodSlot tripod) {
onEnable();

FreecamPosition position = tripods.get(tripod);
boolean chunkLoaded = false;
if (position != null) {
ChunkPos chunkPos = position.getChunkPos();
chunkLoaded = MC.level.getChunkSource().hasChunk(chunkPos.x, chunkPos.z);
}

if (!chunkLoaded) {
FreecamPosition position = FreecamPosition.of(tripod);
while (!position.isInRange()) {
resetCamera(tripod);
position = null;
position = FreecamPosition.of(tripod);
}

freeCamera = new FreeCamera(-420 - tripod.ordinal());
if (position == null) {
moveToPlayer();
} else {
moveToPosition(position);
}
freeCamera.applyPosition(position);

freeCamera.spawn();
MC.setCameraEntity(freeCamera);
activeTripod = tripod;

if (ModConfig.INSTANCE.notification.notifyTripod) {
if (ModConfig.get().notification.notifyTripod) {
MC.player.displayClientMessage(Component.translatable("msg.freecam.openTripod", tripod), true);
}
}

private static void onDisableTripod() {
tripods.put(activeTripod, new FreecamPosition(freeCamera));
tripods.put(activeTripod, FreecamPosition.of(freeCamera));
onDisable();

if (MC.player != null) {
if (ModConfig.INSTANCE.notification.notifyTripod) {
if (ModConfig.get().notification.notifyTripod) {
MC.player.displayClientMessage(Component.translatable("msg.freecam.closeTripod", activeTripod), true);
}
}
Expand All @@ -208,11 +221,11 @@ private static void onDisableTripod() {
private static void onEnableFreecam() {
onEnable();
freeCamera = new FreeCamera(-420);
moveToPlayer();
freeCamera.applyPosition(FreecamPosition.defaultPosition());
freeCamera.spawn();
MC.setCameraEntity(freeCamera);

if (ModConfig.INSTANCE.notification.notifyFreecam) {
if (ModConfig.get().notification.notifyFreecam) {
MC.player.displayClientMessage(Component.translatable("msg.freecam.enable"), true);
}
}
Expand All @@ -221,15 +234,15 @@ private static void onDisableFreecam() {
onDisable();

if (MC.player != null) {
if (ModConfig.INSTANCE.notification.notifyFreecam) {
if (ModConfig.get().notification.notifyFreecam) {
MC.player.displayClientMessage(Component.translatable("msg.freecam.disable"), true);
}
}
}

private static void onEnable() {
MC.smartCull = false;
MC.gameRenderer.setRenderHand(ModConfig.INSTANCE.visual.showHand);
MC.gameRenderer.setRenderHand(ModConfig.get().visual.showHand);

rememberedF5 = MC.options.getCameraType();
if (MC.gameRenderer.getMainCamera().isDetached()) {
Expand Down Expand Up @@ -259,49 +272,16 @@ private static void onDisabled() {

private static void resetCamera(TripodSlot tripod) {
if (tripodEnabled && activeTripod != TripodSlot.NONE && activeTripod == tripod && freeCamera != null) {
moveToPlayer();
freeCamera.applyPosition(FreecamPosition.defaultPosition());
} else {
tripods.put(tripod, null);
}

if (ModConfig.INSTANCE.notification.notifyTripod) {
if (ModConfig.get().notification.notifyTripod) {
MC.player.displayClientMessage(Component.translatable("msg.freecam.tripodReset", tripod), true);
}
}

public static void moveToEntity(@Nullable Entity entity) {
if (freeCamera == null) {
return;
}
if (entity == null) {
moveToPlayer();
return;
}
freeCamera.copyPosition(entity);
}

public static void moveToPosition(@Nullable FreecamPosition position) {
if (freeCamera == null) {
return;
}
if (position == null) {
moveToPlayer();
return;
}
freeCamera.applyPosition(position);
}

public static void moveToPlayer() {
if (freeCamera == null) {
return;
}
freeCamera.copyPosition(MC.player);
freeCamera.applyPerspective(
ModConfig.INSTANCE.visual.perspective,
ModConfig.INSTANCE.collision.alwaysCheck || !(ModConfig.INSTANCE.collision.ignoreAll && BuildVariant.getInstance().cheatsPermitted())
);
}

public static FreeCamera getFreeCamera() {
return freeCamera;
}
Expand All @@ -317,4 +297,8 @@ public static boolean isEnabled() {
public static boolean isPlayerControlEnabled() {
return playerControlEnabled;
}

public static FreecamPosition getTripod(TripodSlot tripod) {
return tripods.get(tripod);
}
}
12 changes: 10 additions & 2 deletions common/src/main/java/net/xolt/freecam/config/ModBindings.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@
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;
import static org.lwjgl.glfw.GLFW.*;

public enum ModBindings {

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

private final Supplier<KeyMapping> lazyMapping;
Expand Down Expand Up @@ -57,6 +57,14 @@ public boolean consumeClick() {
return get().consumeClick();
}

/**
* @return the result of calling {@link KeyMapping#matches(int, int)} on the represented {@link KeyMapping}.
* @see KeyMapping#matches(int, int)
*/
public boolean matches(int keyCode, int scanCode) {
return get().matches(keyCode, scanCode);
}

/**
* Reset whether the key was pressed.
* <p>
Expand Down
Loading