diff --git a/patchwork-events-entity/build.gradle b/patchwork-events-entity/build.gradle index ee9ee549..057f81d7 100644 --- a/patchwork-events-entity/build.gradle +++ b/patchwork-events-entity/build.gradle @@ -1,5 +1,5 @@ archivesBaseName = "patchwork-events-entity" -version = getSubprojectVersion(project, "0.3.0") +version = getSubprojectVersion(project, "0.4.0") dependencies { compile project(path: ':patchwork-fml', configuration: 'dev') diff --git a/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/player/PlayerPickupXpEvent.java b/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/player/PlayerPickupXpEvent.java new file mode 100644 index 00000000..fe2ae604 --- /dev/null +++ b/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/player/PlayerPickupXpEvent.java @@ -0,0 +1,34 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.event.entity.player; + +import net.minecraft.entity.ExperienceOrbEntity; +import net.minecraft.entity.player.PlayerEntity; + +/** + * Legacy version of PlayerXpEvent.PickupXp. Mods should move to PickupXp, and + * this class is removed in 1.15. + */ +@Deprecated +public class PlayerPickupXpEvent extends PlayerXpEvent.PickupXp { + public PlayerPickupXpEvent(PlayerEntity player, ExperienceOrbEntity orb) { + super(player, orb); + } +} diff --git a/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/player/PlayerXpEvent.java b/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/player/PlayerXpEvent.java new file mode 100644 index 00000000..d53f91f1 --- /dev/null +++ b/patchwork-events-entity/src/main/java/net/minecraftforge/event/entity/player/PlayerXpEvent.java @@ -0,0 +1,95 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.event.entity.player; + +import net.minecraft.entity.ExperienceOrbEntity; +import net.minecraft.entity.player.PlayerEntity; + +public abstract class PlayerXpEvent extends PlayerEvent { + public PlayerXpEvent(PlayerEntity player) { + super(player); + } + + /** + * An event representing a player picking up an XP orb entity. + *
+ * For legacy reasons, the instances of this class should actually be of + * type {@link PlayerPickupXpEvent} + *
+ */ + public static class PickupXp extends CancelablePlayerXpEvent { + private final ExperienceOrbEntity orb; + + public PickupXp(PlayerEntity player, ExperienceOrbEntity orb) { + super(player); + this.orb = orb; + } + + public ExperienceOrbEntity getOrb() { + return orb; + } + } + + public static class XpChange extends CancelablePlayerXpEvent { + private int amount; + + public XpChange(PlayerEntity player, int amount) { + super(player); + this.amount = amount; + } + + public int getAmount() { + return amount; + } + + public void setAmount(int amount) { + this.amount = amount; + } + } + + public static class LevelChange extends CancelablePlayerXpEvent { + private int levels; + + public LevelChange(PlayerEntity player, int levels) { + super(player); + this.levels = levels; + } + + public int getLevels() { + return this.levels; + } + + public void setLevels(int levels) { + this.levels = levels; + } + } + + // Helper, so we don't have to repeat isCancelable all the time + private static class CancelablePlayerXpEvent extends PlayerXpEvent { + private CancelablePlayerXpEvent(PlayerEntity player) { + super(player); + } + + @Override + public boolean isCancelable() { + return true; + } + } +} diff --git a/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinExperienceOrbEntity.java b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinExperienceOrbEntity.java new file mode 100644 index 00000000..01e2bdaa --- /dev/null +++ b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinExperienceOrbEntity.java @@ -0,0 +1,47 @@ +/* + * Minecraft Forge, Patchwork Project + * Copyright (c) 2016-2020, 2019-2020 + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.patchworkmc.mixin.event.entity; + +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.player.PlayerPickupXpEvent; +import org.objectweb.asm.Opcodes; +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.callback.CallbackInfo; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.ExperienceOrbEntity; + +@Mixin(ExperienceOrbEntity.class) +public class MixinExperienceOrbEntity { + // After checking we're on the server and the player is ready to pick up the orb, the first + // thing the target method does is set experiencePickUpDelay, hence hook just before that. + @Inject(method = "onPlayerCollision", cancellable = true, at = @At(value = "FIELD", opcode = Opcodes.H_PUTFIELD, ordinal = 0, + target = "net/minecraft/entity/player/PlayerEntity.experiencePickUpDelay:I")) + private void hookOnPlayerCollisionForPickup(PlayerEntity player, CallbackInfo ci) { + @SuppressWarnings("ConstantConditions") + ExperienceOrbEntity entity = (ExperienceOrbEntity) (Object) this; + + if (MinecraftForge.EVENT_BUS.post(new PlayerPickupXpEvent(player, entity))) { + ci.cancel(); + } + } +} diff --git a/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinPlayerEntity.java b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinPlayerEntity.java index 8ab0389b..1cdbfb47 100644 --- a/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinPlayerEntity.java +++ b/patchwork-events-entity/src/main/java/net/patchworkmc/mixin/event/entity/MixinPlayerEntity.java @@ -19,6 +19,8 @@ package net.patchworkmc.mixin.event.entity; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.entity.player.PlayerXpEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -128,4 +130,28 @@ private void onAttackEntity(Entity target, CallbackInfo callback) { callback.cancel(); } } + + @ModifyVariable(method = "addExperience", at = @At("HEAD"), ordinal = 0) + private int onAddExperience(int points) { + @SuppressWarnings("ConstantConditions") + PlayerEntity player = (PlayerEntity) (Object) this; + + PlayerXpEvent.XpChange event = new PlayerXpEvent.XpChange(player, points); + MinecraftForge.EVENT_BUS.post(event); + + // The only effect of passing in zero is a call to addScore(0), which shouldn't have any effect. + return event.isCanceled() ? 0 : event.getAmount(); + } + + @ModifyVariable(method = "addExperienceLevels", at = @At("HEAD"), ordinal = 0) + private int onAddExperienceLevels(int levels) { + @SuppressWarnings("ConstantConditions") + PlayerEntity player = (PlayerEntity) (Object) this; + + PlayerXpEvent.LevelChange event = new PlayerXpEvent.LevelChange(player, levels); + MinecraftForge.EVENT_BUS.post(event); + + // There are no effects from passing in zero levels, so do that if we've been canceled + return event.isCanceled() ? 0 : event.getLevels(); + } } diff --git a/patchwork-events-entity/src/main/resources/patchwork-events-entity.mixins.json b/patchwork-events-entity/src/main/resources/patchwork-events-entity.mixins.json index 55cb18bf..7b7c0180 100644 --- a/patchwork-events-entity/src/main/resources/patchwork-events-entity.mixins.json +++ b/patchwork-events-entity/src/main/resources/patchwork-events-entity.mixins.json @@ -6,6 +6,7 @@ "MixinEntity", "MixinEntityTrackerEntry", "MixinEntityType", + "MixinExperienceOrbEntity", "MixinLivingEntity", "MixinMobEntity", "MixinMobSpawnerLogic",