Add the 'Freecam' feature
This commit is contained in:
parent
f3f3b21848
commit
f64139b600
16 changed files with 442 additions and 20 deletions
|
@ -54,8 +54,10 @@ dependencies {
|
|||
|
||||
runtimeOnly("org.joml:joml:1.10.2")
|
||||
runtimeOnly("org.anarres:jcpp:1.4.14")
|
||||
|
||||
modRuntimeOnly(files("vendor/mods/iris-mc1.18.1-1.2.0-pre.jar"))
|
||||
modRuntimeOnly(files("vendor/mods/sodium-fabric-mc1.18.1-0.4.0-alpha6+build.14.jar"))
|
||||
modRuntimeOnly(files("vendor/mods/lazydfu-0.1.2.jar"))
|
||||
}
|
||||
|
||||
loom {
|
||||
|
|
|
@ -2,6 +2,7 @@ package codes.som.hibiscus.mixins;
|
|||
|
||||
import codes.som.hibiscus.HibiscusMod;
|
||||
import codes.som.hibiscus.events.MovePlayerEvent;
|
||||
import codes.som.hibiscus.events.PlayerPreTickEvent;
|
||||
import codes.som.hibiscus.events.PlayerTickEvent;
|
||||
import codes.som.hibiscus.events.SendChatEvent;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
|
@ -16,6 +17,11 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||
|
||||
@Mixin(ClientPlayerEntity.class)
|
||||
public abstract class MixinClientPlayerEntity {
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void onPreTick(CallbackInfo ci) {
|
||||
HibiscusMod.bus().fire(PlayerPreTickEvent.INSTANCE);
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At("RETURN"))
|
||||
private void onPostTick(CallbackInfo ci) {
|
||||
HibiscusMod.bus().fire(PlayerTickEvent.INSTANCE);
|
||||
|
|
|
@ -8,4 +8,7 @@ import org.spongepowered.asm.mixin.gen.Accessor;
|
|||
public interface MixinExtPlayerInteractEntityC2SPacket {
|
||||
@Accessor("type")
|
||||
PlayerInteractEntityC2SPacket.InteractTypeHandler getTypeHandler();
|
||||
|
||||
@Accessor("entityId")
|
||||
int getEntityId();
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
package codes.som.hibiscus.mixins;
|
||||
|
||||
import codes.som.hibiscus.HibiscusMod;
|
||||
import codes.som.hibiscus.events.RenderWorldEvent;
|
||||
import codes.som.hibiscus.events.Render3DEvent;
|
||||
import codes.som.hibiscus.events.RenderHandEvent;
|
||||
import codes.som.hibiscus.util.graphics.MinecraftRenderPipelineProgress;
|
||||
import codes.som.hibiscus.util.graphics.WorldToScreenProjection;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.gui.hud.InGameHud;
|
||||
import net.minecraft.client.render.Camera;
|
||||
import net.minecraft.client.render.GameRenderer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
|
@ -14,6 +17,7 @@ import org.spongepowered.asm.mixin.Mixin;
|
|||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(GameRenderer.class)
|
||||
|
@ -40,7 +44,32 @@ public abstract class MixinGameRenderer {
|
|||
|
||||
matrices.push();
|
||||
RenderSystem.applyModelViewMatrix();
|
||||
HibiscusMod.bus().fire(new RenderWorldEvent(tickDelta, this.camera, matrices));
|
||||
HibiscusMod.bus().fire(new Render3DEvent(tickDelta, this.camera, matrices));
|
||||
matrices.pop();
|
||||
}
|
||||
|
||||
@Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/hud/InGameHud;render(Lnet/minecraft/client/util/math/MatrixStack;F)V"))
|
||||
private void callRenderOverlay(InGameHud inGameHud, MatrixStack matrices, float tickDelta) {
|
||||
MinecraftRenderPipelineProgress.INSTANCE.setDrawingUI(true);
|
||||
inGameHud.render(matrices, tickDelta);
|
||||
MinecraftRenderPipelineProgress.INSTANCE.setDrawingUI(false);
|
||||
}
|
||||
|
||||
@Inject(method = "updateTargetedEntity", at = @At("HEAD"))
|
||||
public void onPreUpdateTargetedEntity(float tickDelta, CallbackInfo ci) {
|
||||
MinecraftRenderPipelineProgress.INSTANCE.setProcessingInput(true);
|
||||
}
|
||||
|
||||
@Inject(method = "updateTargetedEntity", at = @At("RETURN"))
|
||||
public void onPostUpdateTargetedEntity(float tickDelta, CallbackInfo ci) {
|
||||
MinecraftRenderPipelineProgress.INSTANCE.setProcessingInput(false);
|
||||
}
|
||||
|
||||
@Inject(method = "renderHand", at = @At("HEAD"), cancellable = true)
|
||||
private void onRenderHand(MatrixStack matrices, Camera camera, float tickDelta, CallbackInfo ci) {
|
||||
var event = new RenderHandEvent(tickDelta);
|
||||
HibiscusMod.bus().fire(event);
|
||||
if (event.isCancelled())
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
package codes.som.hibiscus.mixins;
|
||||
|
||||
import codes.som.hibiscus.HibiscusMod;
|
||||
import codes.som.hibiscus.events.GetRenderViewEntityEvent;
|
||||
import codes.som.hibiscus.events.PostRenderAllEvent;
|
||||
import codes.som.hibiscus.gui.ImGuiRenderer;
|
||||
import codes.som.hibiscus.util.graphics.MinecraftRenderPipelineProgress;
|
||||
import net.minecraft.client.MinecraftClient;
|
||||
import net.minecraft.client.RunArgs;
|
||||
import net.minecraft.client.render.RenderTickCounter;
|
||||
import net.minecraft.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(MinecraftClient.class)
|
||||
public abstract class MixinMinecraftClient {
|
||||
|
@ -42,4 +46,25 @@ public abstract class MixinMinecraftClient {
|
|||
HibiscusMod.bus().fire(new PostRenderAllEvent(delta));
|
||||
ImGuiRenderer.INSTANCE.finishFrame(delta);
|
||||
}
|
||||
|
||||
@Inject(method = "getCameraEntity", at = @At("RETURN"), cancellable = true)
|
||||
private void onGetCameraEntity(CallbackInfoReturnable<Entity> cir) {
|
||||
Entity view = cir.getReturnValue();
|
||||
|
||||
if (view != null) {
|
||||
var event = new GetRenderViewEntityEvent(view);
|
||||
HibiscusMod.bus().fire(event);
|
||||
cir.setReturnValue(event.getViewEntity());
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "handleInputEvents", at = @At("HEAD"))
|
||||
private void onPreHandleInputEvents(CallbackInfo ci) {
|
||||
MinecraftRenderPipelineProgress.INSTANCE.setProcessingInput(true);
|
||||
}
|
||||
|
||||
@Inject(method = "handleInputEvents", at = @At("RETURN"))
|
||||
private void onPostHandleInputEvents(CallbackInfo ci) {
|
||||
MinecraftRenderPipelineProgress.INSTANCE.setProcessingInput(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
package codes.som.hibiscus.mixins;
|
||||
|
||||
import codes.som.hibiscus.HibiscusMod;
|
||||
import codes.som.hibiscus.events.*;
|
||||
import codes.som.hibiscus.util.graphics.MinecraftRenderPipelineProgress;
|
||||
import net.minecraft.client.network.ClientPlayerEntity;
|
||||
import net.minecraft.client.render.Camera;
|
||||
import net.minecraft.client.render.GameRenderer;
|
||||
import net.minecraft.client.render.LightmapTextureManager;
|
||||
import net.minecraft.client.render.WorldRenderer;
|
||||
import net.minecraft.client.util.math.MatrixStack;
|
||||
import net.minecraft.util.math.Matrix4f;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(WorldRenderer.class)
|
||||
public abstract class MixinWorldRenderer {
|
||||
@Inject(method = "render", at = @At("HEAD"))
|
||||
private void onPreRenderWorld(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) {
|
||||
HibiscusMod.bus().fire(new PreRenderWorldEvent(tickDelta, camera, matrices));
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At("HEAD"))
|
||||
private void onPostRenderWorld(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) {
|
||||
HibiscusMod.bus().fire(new PostRenderWorldEvent(tickDelta, camera, matrices));
|
||||
}
|
||||
|
||||
@Redirect(method = "render", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerEntity;isSpectator()Z"))
|
||||
public boolean cancelCulling(ClientPlayerEntity instance) {
|
||||
var event = new WorldCullingEvent();
|
||||
HibiscusMod.bus().fire(event);
|
||||
return instance.isSpectator() || event.isCancelled();
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V", args = "ldc=entities"))
|
||||
private void startRenderEntities(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) {
|
||||
MinecraftRenderPipelineProgress.INSTANCE.setRenderingEntities(true);
|
||||
HibiscusMod.bus().fire(new PreRenderEntitiesEvent(tickDelta));
|
||||
}
|
||||
|
||||
@Inject(method = "render", at = @At(value = "INVOKE_STRING", target = "Lnet/minecraft/util/profiler/Profiler;swap(Ljava/lang/String;)V", args = "ldc=blockentities"))
|
||||
private void startRenderBlockEntities(MatrixStack matrices, float tickDelta, long limitTime, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, LightmapTextureManager lightmapTextureManager, Matrix4f matrix4f, CallbackInfo ci) {
|
||||
MinecraftRenderPipelineProgress.INSTANCE.setRenderingEntities(false);
|
||||
HibiscusMod.bus().fire(new PostRenderEntitiesEvent(tickDelta));
|
||||
}
|
||||
}
|
|
@ -6,13 +6,16 @@ import codes.som.hibiscus.api.keybinds.KeybindRegistry
|
|||
import codes.som.hibiscus.commands.CommandRegistry
|
||||
import codes.som.hibiscus.events.KeyEvent
|
||||
import codes.som.hibiscus.features.FeaturesRegistry
|
||||
import codes.som.hibiscus.features.combat.Criticals
|
||||
import codes.som.hibiscus.features.exploits.AntiGhost
|
||||
import codes.som.hibiscus.features.player.NoFallDamage
|
||||
import codes.som.hibiscus.gui.ImGuiScreen
|
||||
import codes.som.hibiscus.util.command.ChatCommandListener
|
||||
import codes.som.hibiscus.util.input.KeybindDispatcher
|
||||
import codes.som.hibiscus.util.netmoving.NetworkMovingDispatcher
|
||||
import net.fabricmc.api.ModInitializer
|
||||
import org.lwjgl.glfw.GLFW
|
||||
import org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT_SHIFT
|
||||
import org.lwjgl.glfw.GLFW.*
|
||||
|
||||
@Suppress("UNUSED")
|
||||
object HibiscusMod : ModInitializer {
|
||||
|
@ -45,6 +48,7 @@ object HibiscusMod : ModInitializer {
|
|||
bus.register(ChatCommandListener())
|
||||
bus.register(KeybindDispatcher())
|
||||
|
||||
defaultConfig()
|
||||
// TODO: Load files
|
||||
}
|
||||
|
||||
|
@ -55,4 +59,15 @@ object HibiscusMod : ModInitializer {
|
|||
system.reset()
|
||||
}
|
||||
}
|
||||
|
||||
fun defaultConfig() {
|
||||
keybinds.register(GLFW_KEY_R, "fly")
|
||||
keybinds.register(GLFW_KEY_O, "nofall")
|
||||
keybinds.register(GLFW_KEY_G, "speed")
|
||||
keybinds.register(GLFW_KEY_B, "freecam")
|
||||
|
||||
features.getFeature<AntiGhost>().enabled = true
|
||||
features.getFeature<NoFallDamage>().enabled = true
|
||||
features.getFeature<Criticals>().enabled = true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ abstract class Feature(val name: String, val category: FeatureCategory) {
|
|||
}
|
||||
}
|
||||
|
||||
var hiddenInOverlay = false
|
||||
|
||||
open fun onEnable() {}
|
||||
open fun onDisable() {}
|
||||
|
||||
|
|
|
@ -6,4 +6,5 @@ enum class FeatureCategory(val humanName: String) {
|
|||
PLAYER("Player"),
|
||||
MOVEMENT("Movement"),
|
||||
OVERLAY("Overlay"),
|
||||
VISUAL("Visual"),
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import codes.som.hibiscus.api.event.Cancellable
|
|||
import codes.som.hibiscus.api.event.Event
|
||||
import net.minecraft.entity.MovementType
|
||||
|
||||
object PlayerPreTickEvent : Event
|
||||
object PlayerTickEvent : Event
|
||||
class SendChatEvent(val message: String) : Cancellable(), Event
|
||||
data class MovePlayerEvent(var x: Double, var y: Double, var z: Double, val movementType: MovementType) : Event
|
||||
|
|
|
@ -1,8 +1,21 @@
|
|||
package codes.som.hibiscus.events
|
||||
|
||||
import codes.som.hibiscus.api.event.Cancellable
|
||||
import codes.som.hibiscus.api.event.Event
|
||||
import net.minecraft.client.render.Camera
|
||||
import net.minecraft.client.util.math.MatrixStack
|
||||
import net.minecraft.entity.Entity
|
||||
|
||||
class PostRenderAllEvent(val delta: Float) : Event
|
||||
class RenderWorldEvent(val delta: Float, val camera: Camera, val matrices: MatrixStack) : Event
|
||||
class Render3DEvent(val delta: Float, val camera: Camera, val matrices: MatrixStack) : Event
|
||||
|
||||
class WorldCullingEvent : Cancellable(), Event
|
||||
|
||||
class GetRenderViewEntityEvent(var viewEntity: Entity) : Event
|
||||
|
||||
class PreRenderWorldEvent(val delta: Float, val camera: Camera, val matrices: MatrixStack) : Event
|
||||
class PreRenderEntitiesEvent(val delta: Float) : Event
|
||||
class PostRenderEntitiesEvent(val delta: Float) : Event
|
||||
class PostRenderWorldEvent(val delta: Float, val camera: Camera, val matrices: MatrixStack) : Event
|
||||
|
||||
class RenderHandEvent(val delta: Float) : Cancellable(), Event
|
||||
|
|
|
@ -8,6 +8,7 @@ import codes.som.hibiscus.features.movement.Flight
|
|||
import codes.som.hibiscus.features.movement.Speed
|
||||
import codes.som.hibiscus.features.overlay.Overlay
|
||||
import codes.som.hibiscus.features.player.NoFallDamage
|
||||
import codes.som.hibiscus.features.visual.Freecam
|
||||
import codes.som.hibiscus.util.Resettable
|
||||
|
||||
fun allFeatureClasses(): Array<() -> Feature> = arrayOf(
|
||||
|
@ -18,6 +19,7 @@ fun allFeatureClasses(): Array<() -> Feature> = arrayOf(
|
|||
::Criticals,
|
||||
::Ghost,
|
||||
::AntiGhost,
|
||||
::Freecam,
|
||||
)
|
||||
|
||||
class FeaturesRegistry : Resettable {
|
||||
|
|
|
@ -7,13 +7,12 @@ import codes.som.hibiscus.events.PostRenderAllEvent
|
|||
import codes.som.hibiscus.mc
|
||||
import imgui.ImGui
|
||||
import imgui.flag.ImGuiCol
|
||||
import imgui.flag.ImGuiStyleVar
|
||||
import imgui.flag.ImGuiWindowFlags
|
||||
|
||||
class Overlay : Feature("Overlay", FeatureCategory.OVERLAY) {
|
||||
init {
|
||||
val enabledFeatures by values.bool("Enabled Features", true)
|
||||
|
||||
|
||||
on { _: PostRenderAllEvent ->
|
||||
if (mc.world == null || mc.options.debugEnabled)
|
||||
return@on
|
||||
|
@ -24,10 +23,10 @@ class Overlay : Feature("Overlay", FeatureCategory.OVERLAY) {
|
|||
|
||||
ImGui.pushStyleColor(ImGuiCol.WindowBg, 0, 0, 0, 0)
|
||||
ImGui.begin(
|
||||
"Overlay##Overlay",
|
||||
"Overlay##Overlay",
|
||||
ImGuiWindowFlags.NoMove + ImGuiWindowFlags.NoInputs + ImGuiWindowFlags.NoDecoration
|
||||
)
|
||||
|
||||
|
||||
if (enabledFeatures)
|
||||
drawEnabledFeatures()
|
||||
|
||||
|
@ -37,35 +36,35 @@ class Overlay : Feature("Overlay", FeatureCategory.OVERLAY) {
|
|||
|
||||
enabled = true
|
||||
}
|
||||
|
||||
|
||||
private fun drawEnabledFeatures() {
|
||||
val enabledFeatures =
|
||||
val displayedFeatures =
|
||||
HibiscusMod.features.getAllFeatures()
|
||||
.filter { it.category != FeatureCategory.OVERLAY }
|
||||
.filter { !it.hiddenInOverlay }
|
||||
.filter { it.enabled }.toList()
|
||||
|
||||
if (enabledFeatures.isEmpty())
|
||||
if (displayedFeatures.isEmpty())
|
||||
return
|
||||
|
||||
|
||||
val padX = 8f
|
||||
val padY = 8f
|
||||
|
||||
|
||||
val pos = ImGui.getCursorScreenPos()
|
||||
ImGui.setCursorScreenPos(pos.x + padX, pos.y + padY)
|
||||
|
||||
|
||||
ImGui.beginGroup()
|
||||
|
||||
|
||||
ImGui.pushStyleColor(ImGuiCol.Text, 244, 161, 255, 255)
|
||||
for (feature in enabledFeatures)
|
||||
for (feature in displayedFeatures)
|
||||
ImGui.text(feature.name)
|
||||
ImGui.popStyleColor()
|
||||
|
||||
|
||||
ImGui.endGroup()
|
||||
val min = ImGui.getItemRectMin()
|
||||
val max = ImGui.getItemRectMax()
|
||||
ImGui.getBackgroundDrawList().addRectFilled(
|
||||
min.x - padX, min.y - padY, max.x + padX,
|
||||
max.y + padY,
|
||||
max.y + padY,
|
||||
0xAA0A0A0AL.toInt(),
|
||||
0F
|
||||
)
|
||||
|
|
267
src/main/kotlin/codes/som/hibiscus/features/visual/Freecam.kt
Normal file
267
src/main/kotlin/codes/som/hibiscus/features/visual/Freecam.kt
Normal file
|
@ -0,0 +1,267 @@
|
|||
package codes.som.hibiscus.features.visual
|
||||
|
||||
import codes.som.hibiscus.HibiscusMod
|
||||
import codes.som.hibiscus.api.feature.Feature
|
||||
import codes.som.hibiscus.api.feature.FeatureCategory
|
||||
import codes.som.hibiscus.events.*
|
||||
import codes.som.hibiscus.mc
|
||||
import codes.som.hibiscus.mixins.MixinExtPlayerInteractEntityC2SPacket
|
||||
import codes.som.hibiscus.player
|
||||
import codes.som.hibiscus.util.ext.requireExtension
|
||||
import codes.som.hibiscus.util.graphics.MinecraftRenderPipelineProgress
|
||||
import codes.som.hibiscus.world
|
||||
import net.minecraft.client.input.Input
|
||||
import net.minecraft.client.network.ClientPlayerEntity
|
||||
import net.minecraft.client.option.Perspective
|
||||
import net.minecraft.entity.Entity
|
||||
import net.minecraft.entity.EntityType
|
||||
import net.minecraft.entity.MovementType
|
||||
import net.minecraft.nbt.NbtCompound
|
||||
import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket
|
||||
import net.minecraft.util.math.MathHelper
|
||||
import net.minecraft.util.math.Vec3d
|
||||
import net.minecraft.world.World
|
||||
import org.lwjgl.glfw.GLFW.GLFW_KEY_TAB
|
||||
import org.lwjgl.glfw.GLFW.GLFW_PRESS
|
||||
|
||||
class Freecam : Feature("Freecam", FeatureCategory.VISUAL) {
|
||||
private var camEntity: Entity? = null
|
||||
private var playerInput: Input? = null
|
||||
private var isControllingPlayer: Boolean = false
|
||||
|
||||
private var origYaw = 0F
|
||||
private var origPitch = 0F
|
||||
|
||||
private val toggleKey by values.key("Toggle Key", GLFW_KEY_TAB)
|
||||
|
||||
init {
|
||||
var isPlayerTicking = false
|
||||
on { _: PlayerPreTickEvent -> isPlayerTicking = true }
|
||||
on { _: PlayerTickEvent -> isPlayerTicking = false }
|
||||
|
||||
on { event: WorldCullingEvent -> event.cancel() }
|
||||
|
||||
on { event: GetRenderViewEntityEvent ->
|
||||
val view = camEntity ?: return@on
|
||||
|
||||
if (isPlayerTicking)
|
||||
return@on
|
||||
|
||||
if (MinecraftRenderPipelineProgress.isRenderingEntities || MinecraftRenderPipelineProgress.isDrawingUI)
|
||||
return@on
|
||||
|
||||
if (isControllingPlayer && MinecraftRenderPipelineProgress.isProcessingInput)
|
||||
return@on
|
||||
|
||||
event.viewEntity = view
|
||||
}
|
||||
|
||||
on { _: PlayerPreTickEvent ->
|
||||
val view = camEntity ?: return@on
|
||||
|
||||
if (isControllingPlayer) {
|
||||
origYaw = player.yaw
|
||||
origPitch = player.pitch
|
||||
}
|
||||
|
||||
player.yaw = origYaw
|
||||
player.pitch = origPitch
|
||||
|
||||
with(view) {
|
||||
prevHorizontalSpeed = horizontalSpeed
|
||||
prevX = x
|
||||
prevY = y
|
||||
prevZ = z
|
||||
prevPitch = pitch
|
||||
prevYaw = yaw
|
||||
}
|
||||
|
||||
if (!isControllingPlayer) {
|
||||
val yaw = MathHelper.RADIANS_PER_DEGREE * view.yaw
|
||||
val lookVec = Vec3d(-MathHelper.sin(yaw).toDouble(), 0.0, MathHelper.cos(yaw).toDouble())
|
||||
var movement = Vec3d.ZERO
|
||||
if (mc.options.forwardKey.isPressed)
|
||||
movement = movement.add(0.0, 0.0, 1.0)
|
||||
if (mc.options.backKey.isPressed)
|
||||
movement = movement.add(0.0, 0.0, -1.0)
|
||||
if (mc.options.rightKey.isPressed)
|
||||
movement = movement.add(1.0, 0.0, 0.0)
|
||||
if (mc.options.leftKey.isPressed)
|
||||
movement = movement.add(-1.0, 0.0, 0.0)
|
||||
if (mc.options.jumpKey.isPressed)
|
||||
movement = movement.add(0.0, 1.0, 0.0)
|
||||
if (mc.options.sneakKey.isPressed)
|
||||
movement = movement.add(0.0, -1.0, 0.0)
|
||||
|
||||
// one day i will learn the matrix math for this
|
||||
movement = lookVec
|
||||
.multiply(movement.z)
|
||||
.add(lookVec.rotateY(-MathHelper.HALF_PI).multiply(movement.x))
|
||||
.add(0.0, movement.y, 0.0)
|
||||
|
||||
view.move(MovementType.SELF, movement) // Update entity positional state properly by calling move()
|
||||
}
|
||||
}
|
||||
|
||||
on { event: KeyEvent ->
|
||||
if (event.action == GLFW_PRESS && event.key == toggleKey) {
|
||||
isControllingPlayer = !isControllingPlayer
|
||||
updatePlayerControl()
|
||||
}
|
||||
}
|
||||
|
||||
var yawPreRender = 0F
|
||||
var pitchPreRender = 0F
|
||||
var prevPitchPreRender = 0F
|
||||
on { _: PreRenderWorldEvent ->
|
||||
yawPreRender = player.yaw
|
||||
pitchPreRender = player.pitch
|
||||
prevPitchPreRender = player.prevPitch
|
||||
|
||||
camEntity?.let { view ->
|
||||
player.yaw = view.yaw
|
||||
player.pitch = view.pitch
|
||||
player.prevPitch = view.prevPitch
|
||||
}
|
||||
}
|
||||
|
||||
var lastMouseX = 0.0
|
||||
var lastMouseY = 0.0
|
||||
var mouseDeltaX = 0.0
|
||||
var mouseDeltaY = 0.0
|
||||
HibiscusMod.bus.register { _: PostRenderWorldEvent ->
|
||||
mouseDeltaX = mc.mouse.x - lastMouseX
|
||||
mouseDeltaY = mc.mouse.y - lastMouseY
|
||||
lastMouseX = mc.mouse.x
|
||||
lastMouseY = mc.mouse.y
|
||||
}
|
||||
|
||||
// TODO: On post render world, update the camEntity's view angles based on mouse delta
|
||||
on { _: PostRenderWorldEvent ->
|
||||
val view = camEntity ?: return@on
|
||||
|
||||
if (isControllingPlayer)
|
||||
return@on
|
||||
|
||||
if (mc.isWindowFocused && mc.currentScreen == null) {
|
||||
val mouseSensAdj = mc.options.mouseSensitivity * 0.6 + 0.2
|
||||
val mouseSensAngleCoeff = mouseSensAdj * mouseSensAdj * mouseSensAdj * 8.0
|
||||
val invertYCoeff = if (mc.options.invertYMouse) -1 else 1
|
||||
view.changeLookDirection(
|
||||
mouseDeltaX * mouseSensAngleCoeff,
|
||||
mouseDeltaY * mouseSensAngleCoeff * invertYCoeff
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: Push / pop origYaw so that the player matches their server-side look angles
|
||||
var perspectivePreRender: Perspective? = null
|
||||
on { event: PreRenderEntitiesEvent ->
|
||||
player.yaw = yawPreRender
|
||||
player.pitch = pitchPreRender
|
||||
player.prevPitch = prevPitchPreRender
|
||||
|
||||
if (!isControllingPlayer) {
|
||||
player.yaw = origYaw
|
||||
player.pitch = origPitch
|
||||
}
|
||||
|
||||
perspectivePreRender = mc.options.perspective
|
||||
mc.options.perspective = Perspective.THIRD_PERSON_BACK
|
||||
mc.gameRenderer.camera.update(mc.world, mc.player, true, false, event.delta)
|
||||
}
|
||||
|
||||
on { event: PostRenderEntitiesEvent ->
|
||||
mc.options.perspective = perspectivePreRender!!
|
||||
|
||||
player.yaw = yawPreRender
|
||||
player.pitch = pitchPreRender
|
||||
player.prevPitch = prevPitchPreRender
|
||||
|
||||
mc.gameRenderer.camera.update(
|
||||
mc.world,
|
||||
mc.getCameraEntity() ?: mc.player,
|
||||
!mc.options.perspective.isFirstPerson,
|
||||
mc.options.perspective.isFrontView,
|
||||
event.delta
|
||||
)
|
||||
}
|
||||
|
||||
on { event: SendPacketEvent ->
|
||||
val (packet) = event
|
||||
if (packet is PlayerInteractEntityC2SPacket) {
|
||||
requireExtension<MixinExtPlayerInteractEntityC2SPacket>(packet)
|
||||
if (packet.typeHandler.type == PlayerInteractEntityC2SPacket.InteractType.ATTACK && packet.entityId == player.id) {
|
||||
event.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
on { event: RenderHandEvent ->
|
||||
if (!isControllingPlayer)
|
||||
event.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePlayerControl() {
|
||||
if (isControllingPlayer) {
|
||||
if (playerInput != null)
|
||||
player.input = playerInput
|
||||
} else {
|
||||
playerInput = player.input
|
||||
player.input = Input()
|
||||
player.input.sneaking = playerInput!!.sneaking
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCamera() {
|
||||
isControllingPlayer = false
|
||||
camEntity = FreecamControllerEntity(player, world)
|
||||
|
||||
updatePlayerControl()
|
||||
origYaw = player.yaw
|
||||
origPitch = player.pitch
|
||||
}
|
||||
|
||||
override fun onEnable() {
|
||||
if (mc.world == null)
|
||||
return
|
||||
|
||||
setupCamera()
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
if (mc.world == null)
|
||||
return
|
||||
|
||||
isControllingPlayer = true
|
||||
updatePlayerControl()
|
||||
|
||||
camEntity = null
|
||||
playerInput = null
|
||||
}
|
||||
|
||||
class FreecamControllerEntity(localPlayer: ClientPlayerEntity, world: World) : Entity(EntityType.PLAYER, world) {
|
||||
init {
|
||||
updatePositionAndAngles(
|
||||
localPlayer.x, localPlayer.y, localPlayer.z,
|
||||
localPlayer.yaw, localPlayer.pitch
|
||||
)
|
||||
setRotation(localPlayer.yaw, localPlayer.pitch)
|
||||
noClip = true
|
||||
setNoGravity(true)
|
||||
}
|
||||
|
||||
override fun initDataTracker() {
|
||||
}
|
||||
|
||||
override fun readCustomDataFromNbt(nbt: NbtCompound?) {
|
||||
}
|
||||
|
||||
override fun writeCustomDataToNbt(nbt: NbtCompound?) {
|
||||
}
|
||||
|
||||
override fun createSpawnPacket() = null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package codes.som.hibiscus.util.graphics
|
||||
|
||||
object MinecraftRenderPipelineProgress {
|
||||
var isRenderingEntities: Boolean = false
|
||||
var isDrawingUI: Boolean = false
|
||||
var isProcessingInput: Boolean = false
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
"MixinExtUpdatePlayerAbilitiesC2SPacket",
|
||||
"MixinGameRenderer",
|
||||
"MixinKeyboard",
|
||||
"MixinMinecraftClient"
|
||||
"MixinMinecraftClient",
|
||||
"MixinWorldRenderer"
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue