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
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
package com.lambda.mixin.entity;

import com.lambda.event.EventFlow;
import com.lambda.event.events.AttackEvent;
import com.lambda.event.events.InteractionEvent;
import com.lambda.event.events.PlayerEvent;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.client.network.ClientPlayerInteractionManager;
Expand All @@ -29,6 +28,7 @@
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.EntityHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import org.spongepowered.asm.mixin.Final;
Expand All @@ -44,53 +44,55 @@ public class ClientPlayInteractionManagerMixin {

@Shadow
public float currentBreakingProgress;
@Final
@Shadow
private MinecraftClient client;

@Inject(method = "interactBlock", at = @At("HEAD"))
@Inject(method = "interactBlock", at = @At("HEAD"), cancellable = true)
public void interactBlockHead(final ClientPlayerEntity player, final Hand hand, final BlockHitResult hitResult, final CallbackInfoReturnable<ActionResult> cir) {
if (client.world == null) return;
EventFlow.post(new InteractionEvent.Block(client.world, hitResult));
if (EventFlow.post(new PlayerEvent.Interact.Block(hand, hitResult)).isCanceled()) {
cir.setReturnValue(ActionResult.FAIL);
}
}

@Inject(method = "clickSlot", at = @At("HEAD"), cancellable = true)
public void clickSlotHead(int syncId, int slotId, int button, SlotActionType actionType, PlayerEntity player, CallbackInfo ci) {
if (syncId != player.currentScreenHandler.syncId) return;
var click = new InteractionEvent.SlotClick(syncId, slotId, button, actionType, player.currentScreenHandler);
if (EventFlow.post(click).isCanceled()) ci.cancel();
@Inject(method = "interactEntityAtLocation", at = @At("HEAD"), cancellable = true)
public void interactEntityAtLocation(PlayerEntity player, Entity entity, EntityHitResult hitResult, Hand hand, CallbackInfoReturnable<ActionResult> cir) {
if (EventFlow.post(new PlayerEvent.Interact.Entity(hand, entity, hitResult)).isCanceled()) {
cir.setReturnValue(ActionResult.FAIL);
}
}

@Inject(method = "attackEntity", at = @At("HEAD"), cancellable = true)
void onAttackPre(PlayerEntity player, Entity target, CallbackInfo ci) {
if (EventFlow.post(new AttackEvent.Pre(target)).isCanceled()) ci.cancel();
@Inject(method = "interactItem", at = @At("HEAD"), cancellable = true)
public void interactItemHead(PlayerEntity player, Hand hand, CallbackInfoReturnable<ActionResult> cir) {
if (EventFlow.post(new PlayerEvent.Interact.Item(hand)).isCanceled()) {
cir.setReturnValue(ActionResult.FAIL);
}
}

@Inject(method = "attackEntity", at = @At("TAIL"))
void onAttackPost(PlayerEntity player, Entity target, CallbackInfo ci) {
EventFlow.post(new AttackEvent.Post(target));
@Inject(method = "attackBlock", at = @At("HEAD"))
public void onAttackBlock(BlockPos pos, Direction side, CallbackInfoReturnable<Boolean> cir) {
if (EventFlow.post(new PlayerEvent.Attack.Block(pos, side)).isCanceled()) cir.cancel();
}

@Inject(method = "attackBlock", at = @At("HEAD"), cancellable = true)
public void onAttackBlock(BlockPos pos, Direction side, CallbackInfoReturnable<Boolean> cir) {
if (EventFlow.post(new InteractionEvent.BlockAttack.Pre(pos, side)).isCanceled()) cir.cancel();
@Inject(method = "attackEntity", at = @At("HEAD"), cancellable = true)
void onAttackPre(PlayerEntity player, Entity target, CallbackInfo ci) {
if (EventFlow.post(new PlayerEvent.Attack.Entity(target)).isCanceled()) ci.cancel();
}

@Inject(method = "attackBlock", at = @At("TAIL"))
public void onAttackBlockPost(BlockPos pos, Direction side, CallbackInfoReturnable<Boolean> cir) {
EventFlow.post(new InteractionEvent.BlockAttack.Post(pos, side));
@Inject(method = "clickSlot", at = @At("HEAD"), cancellable = true)
public void clickSlotHead(int syncId, int slotId, int button, SlotActionType actionType, PlayerEntity player, CallbackInfo ci) {
if (syncId != player.currentScreenHandler.syncId) return;
var click = new PlayerEvent.SlotClick(syncId, slotId, button, actionType, player.currentScreenHandler);
if (EventFlow.post(click).isCanceled()) ci.cancel();
}

@Inject(method = "updateBlockBreakingProgress", at = @At("HEAD"), cancellable = true)
private void updateBlockBreakingProgressPre(BlockPos pos, Direction side, CallbackInfoReturnable<Boolean> cir) {
var event = EventFlow.post(new InteractionEvent.BreakingProgress.Pre(pos, side, currentBreakingProgress));
if (event.isCanceled()) cir.cancel();
var event = EventFlow.post(new PlayerEvent.Breaking.Update(pos, side, currentBreakingProgress));
if (event.isCanceled()) cir.setReturnValue(false);

currentBreakingProgress = event.getProgress();
}

@Inject(method = "updateBlockBreakingProgress", at = @At("TAIL"))
private void updateBlockBreakingProgressPost(BlockPos pos, Direction side, CallbackInfoReturnable<Boolean> cir) {
EventFlow.post(new InteractionEvent.BreakingProgress.Post(pos, side, currentBreakingProgress));
@Inject(method = "cancelBlockBreaking", at = @At("HEAD"), cancellable = true)
private void cancelBlockBreakingPre(CallbackInfo ci) {
if (EventFlow.post(new PlayerEvent.Breaking.Cancel(currentBreakingProgress)).isCanceled()) ci.cancel();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import com.lambda.Lambda;
import com.lambda.event.EventFlow;
import com.lambda.event.events.EntityEvent;
import com.lambda.event.events.PlayerEvent;
import com.lambda.event.events.MovementEvent;
import com.lambda.event.events.TickEvent;
import com.lambda.interaction.PlayerPacketManager;
Expand Down Expand Up @@ -50,9 +50,6 @@ public abstract class ClientPlayerEntityMixin extends EntityMixin {
@Shadow
protected abstract void autoJump(float dx, float dz);

@Shadow
public abstract boolean isUsingItem();

@Inject(method = "move", at = @At("HEAD"), cancellable = true)
void onMove(MovementType movementType, Vec3d movement, CallbackInfo ci) {
ClientPlayerEntity self = (ClientPlayerEntity) (Object) this;
Expand All @@ -63,9 +60,9 @@ void onMove(MovementType movementType, Vec3d movement, CallbackInfo ci) {
float prevX = (float) self.getX();
float prevZ = (float) self.getZ();

EventFlow.post(new MovementEvent.Pre());
EventFlow.post(new MovementEvent.Player.Pre(movementType, movement));
super.move(movementType, self.getVelocity());
EventFlow.post(new MovementEvent.Post());
EventFlow.post(new MovementEvent.Player.Post(movementType, movement));

float currX = (float) self.getX();
float currZ = (float) self.getZ();
Expand Down Expand Up @@ -125,6 +122,6 @@ float fixHeldItemPitch(ClientPlayerEntity instance) {

@Inject(method = "swingHand", at = @At("HEAD"), cancellable = true)
void onSwingHandPre(Hand hand, CallbackInfo ci) {
if (EventFlow.post(new EntityEvent.SwingHand(hand)).isCanceled()) ci.cancel();
if (EventFlow.post(new PlayerEvent.SwingHand(hand)).isCanceled()) ci.cancel();
}
}
4 changes: 2 additions & 2 deletions common/src/main/java/com/lambda/mixin/entity/EntityMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import com.lambda.Lambda;
import com.lambda.event.EventFlow;
import com.lambda.event.events.EntityEvent;
import com.lambda.event.events.PlayerEvent;
import com.lambda.event.events.WorldEvent;
import com.lambda.interaction.RotationManager;
import com.lambda.util.math.Vec2d;
Expand Down Expand Up @@ -87,7 +87,7 @@ float fixDirectionPitch2(Entity entity) {

@Inject(method = "changeLookDirection", at = @At("HEAD"), cancellable = true)
private void changeLookDirection(double cursorDeltaX, double cursorDeltaY, CallbackInfo ci) {
if (EventFlow.post(new EntityEvent.ChangeLookDirection(cursorDeltaX, cursorDeltaY)).isCanceled()) ci.cancel();
if (EventFlow.post(new PlayerEvent.ChangeLookDirection(cursorDeltaX, cursorDeltaY)).isCanceled()) ci.cancel();
}

@Inject(method = "onTrackedDataSet(Lnet/minecraft/entity/data/TrackedData;)V", at = @At("TAIL"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,12 @@ void onJump(CallbackInfo ci) {

@Inject(method = "travel", at = @At("HEAD"), cancellable = true)
void onTravelPre(Vec3d movementInput, CallbackInfo ci) {
LivingEntity self = (LivingEntity) (Object) this;
if (self != Lambda.getMc().player) return;

if (EventFlow.post(new MovementEvent.Travel.Pre()).isCanceled()) ci.cancel();
if (EventFlow.post(new MovementEvent.Entity.Pre((LivingEntity) (Object) this, movementInput)).isCanceled()) ci.cancel();
}

@Inject(method = "travel", at = @At("TAIL"))
void onTravelPost(Vec3d movementInput, CallbackInfo ci) {
LivingEntity self = (LivingEntity) (Object) this;
if (self != Lambda.getMc().player) return;

EventFlow.post(new MovementEvent.Travel.Post());
EventFlow.post(new MovementEvent.Entity.Post((LivingEntity) (Object) this, movementInput));
}

@Redirect(method = "travel", at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;getPitch()F"))
Expand Down
18 changes: 14 additions & 4 deletions common/src/main/java/com/lambda/mixin/input/KeyboardMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
package com.lambda.mixin.input;

import com.lambda.event.EventFlow;
import com.lambda.event.events.KeyPressEvent;
import com.lambda.event.events.KeyboardEvent;
import net.minecraft.client.Keyboard;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
Expand All @@ -28,9 +28,19 @@
@Mixin(Keyboard.class)
public class KeyboardMixin {
@Inject(method = "onKey", at = @At("HEAD"))
void onKey(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) {
private void onKey(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) {
if (key <= 0) return;
if (action != 1) return;
EventFlow.post(new KeyPressEvent(key, scancode, action, modifiers));
if (action != 1) return; // TODO: Post events on both press and release ?

EventFlow.post(new KeyboardEvent.Press(key, scancode, action, modifiers));
}

@Inject(method = "onChar", at = @At("HEAD"))
private void onChar(long window, int codePoint, int modifiers, CallbackInfo ci) {
char[] chars = Character.toChars(codePoint);

for (char c : chars) {
EventFlow.post(new KeyboardEvent.Char(c));
}
}
}
66 changes: 66 additions & 0 deletions common/src/main/java/com/lambda/mixin/input/MouseMixin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2024 Lambda
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.lambda.mixin.input;

import com.lambda.event.EventFlow;
import com.lambda.event.events.MouseEvent;
import com.lambda.util.math.Vec2d;
import net.minecraft.client.Mouse;
import com.lambda.util.Mouse.Button;
import com.lambda.util.Mouse.Action;
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;

@Mixin(Mouse.class)
public class MouseMixin {
@Shadow private double x;

@Shadow private double y;

@Inject(method = "onMouseButton(JIII)V", at = @At("HEAD"), cancellable = true)
private void onMouseButton(long window, int button, int action, int mods, CallbackInfo ci) {
Vec2d position = new Vec2d(x, y);

if (EventFlow.post(new MouseEvent.Click(button, action, mods, position)).isCanceled()) {
ci.cancel();
}
}

@Inject(method = "onMouseScroll(JDD)V", at = @At("HEAD"), cancellable = true)
private void onMouseScroll(long window, double horizontal, double vertical, CallbackInfo ci) {
Vec2d delta = new Vec2d(horizontal, vertical);

if (EventFlow.post(new MouseEvent.Scroll(delta)).isCanceled()) {
ci.cancel();
}
}

@Inject(method = "onCursorPos(JDD)V", at = @At("HEAD"), cancellable = true)
private void onCursorPos(long window, double x, double y, CallbackInfo ci) {
if (x + y == this.x + this.y) return;

Vec2d position = new Vec2d(x, y);

if (EventFlow.post(new MouseEvent.Move(position)).isCanceled()) {
ci.cancel();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private void onChunkLoad(
Consumer<ChunkData.BlockEntityVisitor> consumer,
CallbackInfoReturnable<WorldChunk> info
) {
EventFlow.post(new WorldEvent.ChunkEvent.Load(this.world, info.getReturnValue()));
EventFlow.post(new WorldEvent.ChunkEvent.Load(info.getReturnValue()));
}

@Inject(method = "loadChunkFromPacket", at = @At(value = "NEW", target = "net/minecraft/world/chunk/WorldChunk", shift = At.Shift.BEFORE), locals = LocalCapture.CAPTURE_FAILHARD)
Expand All @@ -68,13 +68,13 @@ private void onChunkUnload(
ChunkPos chunkPos
) {
if (chunk != null) {
EventFlow.post(new WorldEvent.ChunkEvent.Unload(this.world, chunk));
EventFlow.post(new WorldEvent.ChunkEvent.Unload(chunk));
}
}

@Inject(method = "unload", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientChunkManager$ClientChunkMap;compareAndSet(ILnet/minecraft/world/chunk/WorldChunk;Lnet/minecraft/world/chunk/WorldChunk;)Lnet/minecraft/world/chunk/WorldChunk;"), locals = LocalCapture.CAPTURE_FAILHARD)
private void onChunkUnload(ChunkPos pos, CallbackInfo ci, int i, WorldChunk chunk) {
EventFlow.post(new WorldEvent.ChunkEvent.Unload(this.world, chunk));
EventFlow.post(new WorldEvent.ChunkEvent.Unload(chunk));
}

// @Inject(
Expand Down
1 change: 0 additions & 1 deletion common/src/main/kotlin/com/lambda/event/Subscriber.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ class Subscriber : ConcurrentHashMap<KClass<out Event>, ConcurrentSkipListSet<Li
val defaultListenerSet: ConcurrentSkipListSet<Listener<out Event>>
get() = ConcurrentSkipListSet(Listener.comparator.reversed())


/** Allows a [Listener] to start receiving a specific type of [Event] */
inline fun <reified T : Event> subscribe(listener: Listener<T>) =
getOrPut(T::class) { defaultListenerSet }.add(listener)
Expand Down
28 changes: 0 additions & 28 deletions common/src/main/kotlin/com/lambda/event/events/AttackEvent.kt

This file was deleted.

26 changes: 21 additions & 5 deletions common/src/main/kotlin/com/lambda/event/events/ClientEvent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,26 @@ import com.lambda.event.callback.Cancellable
import com.lambda.event.callback.ICancellable
import net.minecraft.client.sound.SoundInstance

sealed class ClientEvent {
/**
* Triggered upon client initialization
*/
class Startup : Event

abstract class ClientEvent : Event {
class Shutdown : ClientEvent()
class Startup : ClientEvent()
class Timer(var speed: Double) : ClientEvent()
class Sound(val sound: SoundInstance) : ClientEvent(), ICancellable by Cancellable()
/**
* Triggered upon client shutdown
*/
class Shutdown : Event

/**
* Triggered upon game logic tick
*
* @property speed The speed of the timer.
*/
data class Timer(var speed: Double) : Event

/**
* Triggered before playing a sound
*/
data class Sound(val sound: SoundInstance) : ICancellable by Cancellable()
}
Loading