Skip to content

Commit

Permalink
More spectator fixes
Browse files Browse the repository at this point in the history
Fixed jitter when attempting to pick up items from slots
Possibly fixed spectators being able to body-block players
Removed spectators from being considered as Creative mode players
Fixed spectators having an item stuck in their cursor if someone else changes their game mode while they were dragging items, it'll get put in their inventory or thrown on the ground if no room is available.
Fixed AE2 containers largely ignoring many checks (including `canTakeStack`) by just no-opping their inventory code for spectators
Fixed spectators being able to spectate spectators
  • Loading branch information
Roadhog360 committed Jan 6, 2025
1 parent a5af4fb commit d4eb326
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 17 deletions.
1 change: 1 addition & 0 deletions dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ dependencies {
compileOnly "codechicken:CodeChickenLib:1.7.10-1.1.3.140:dev"
compileOnly "codechicken:CodeChickenCore:1.7.10-1.0.7.47:dev"
compileOnly 'com.github.GTNewHorizons:ironchest:6.0.87'
compileOnly 'curse.maven:applied-energistics-2-223794:2296430'

compileOnly("com.github.GTNewHorizons:TinkersConstruct:1.12.6-GTNH:dev") {
transitive = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ public List<String> getMixins(Set<String> loadedCoreMods) {
mixins.add("spectator.MixinNetHandlerPlayServer");
mixins.add("spectator.MixinInventoryPlayer");
mixins.add("spectator.MixinContainerChest");
mixins.add("spectator.MixinSlot");
if (side == MixinEnvironment.Side.CLIENT) {
mixins.add("spectator.client.MixinEntityRenderer");
mixins.add("spectator.client.MixinEntityPlayer");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,13 @@ public String getMixinConfig() {
public List<String> getMixins(Set<String> loadedMods) {
List<String> mixins = new ArrayList<>();

if(ConfigMixins.enableSpectatorMode && loadedMods.contains("IronChest")) {
mixins.add("spectator.MixinContainerIronChest");
if (ConfigMixins.enableSpectatorMode) {
if (loadedMods.contains("IronChest")) {
mixins.add("spectator.MixinContainerIronChest");
}
if (loadedMods.contains("appliedenergistics2")) {
mixins.add("spectator.MixinPacketInventoryAction");
}
}

return mixins;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.ContainerBeacon;
import net.minecraft.inventory.ContainerChest;
import net.minecraft.inventory.IInventory;
import net.minecraft.inventory.InventoryBasic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
Expand All @@ -20,7 +20,7 @@ public abstract class MixinContainerChest extends Container {
@WrapOperation(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/inventory/IInventory;openInventory()V"))
private void ignoreOpenInventoryInSpectator(IInventory chestInv, Operation<Void> original,
@Local(ordinal = 0, argsOnly = true) IInventory playerInv) {
if (!(playerInv instanceof InventoryPlayer) || !SpectatorMode.isSpectator(((InventoryPlayer) playerInv).player)) {
if (!(playerInv instanceof InventoryPlayer inv) || !SpectatorMode.isSpectator(inv.player)) {
original.call(chestInv);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,60 +1,72 @@
package ganymedes01.etfuturum.mixins.early.spectator;

import ganymedes01.etfuturum.spectator.SpectatorMode;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.item.EntityXPOrb;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.AxisAlignedBB;
import net.minecraft.world.World;
import net.minecraft.world.WorldSettings;
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(EntityPlayer.class)
public abstract class MixinEntityPlayer extends EntityLivingBase {

@Shadow
public InventoryPlayer inventory;
@Shadow public InventoryPlayer inventory;

@Shadow public abstract EntityItem dropPlayerItemWithRandomChoice(ItemStack itemStackIn, boolean p_71019_2_);

public MixinEntityPlayer(World p_i1595_1_) {
super(p_i1595_1_);
}

@Override
public boolean canBePushed() {
return !SpectatorMode.isSpectator((EntityPlayer) (Object) this);
return !SpectatorMode.isSpectator((EntityPlayer) (Object) this) && super.canBePushed();
}

@Override
public boolean canBeCollidedWith() {
return !SpectatorMode.isSpectator((EntityPlayer) (Object) this);
return !SpectatorMode.isSpectator((EntityPlayer) (Object) this) && !super.canBeCollidedWith();
}

@Override
protected void collideWithNearbyEntities() {
if (!SpectatorMode.isSpectator((EntityPlayer) (Object) this))
if (!SpectatorMode.isSpectator((EntityPlayer) (Object) this)) {
super.collideWithNearbyEntities();
}
}

@Override
public boolean isOnLadder() {
if (SpectatorMode.isSpectator((EntityPlayer) (Object) this))
if (SpectatorMode.isSpectator((EntityPlayer) (Object) this)) {
return false;
}
return super.isOnLadder();
}

@Override
public boolean handleWaterMovement() {
if (SpectatorMode.isSpectator((EntityPlayer) (Object) this))
if (SpectatorMode.isSpectator((EntityPlayer) (Object) this)) {
return false;
}
return super.handleWaterMovement();
}

@Override
public ItemStack getEquipmentInSlot(int p_71124_1_) {
return SpectatorMode.isSpectator((EntityPlayer) (Object) this) ? null : p_71124_1_ == 0 ? this.inventory.getCurrentItem() : this.inventory.armorInventory[p_71124_1_ - 1];
@Inject(method = "getEquipmentInSlot", at = @At(value = "HEAD"), cancellable = true)
public void getNullEquipmentIfSpectator(int p_71124_1_, CallbackInfoReturnable<ItemStack> cir) {
if(SpectatorMode.isSpectator((EntityPlayer) (Object) this)) {
cir.setReturnValue(null);
}
}

@Inject(method = "isCurrentToolAdventureModeExempt", at = @At(value = "HEAD"), cancellable = true)
Expand All @@ -63,4 +75,24 @@ public void isSpectating(int p_82246_1_, int p_82246_2_, int p_82246_3_, Callbac
cir.setReturnValue(false);
}
}

@Inject(method = "setGameType", at = @At("HEAD"))
private void dropCarriedItem(WorldSettings.GameType gameType, CallbackInfo ci) {
if(gameType == SpectatorMode.SPECTATOR_GAMETYPE) {
ItemStack stack = inventory.getItemStack(); // Item in cursor
// Tries to add ItemStack to inventory, else drops it on the ground.
// This is to prevent spectators from having a cursor item.
if(stack != null) {
if(!inventory.addItemStackToInventory(stack)) {
dropPlayerItemWithRandomChoice(stack, true);
}
}
}
}

@Override
public boolean canAttackWithItem()
{
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public void configureSpecCaps(PlayerCapabilities caps, CallbackInfo ci) {
if (etfuturum$isSpectator()) {
ci.cancel();
caps.allowFlying = true;
caps.isCreativeMode = true;
caps.isCreativeMode = false;
caps.disableDamage = true;
caps.allowEdit = false;
caps.isFlying = true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package ganymedes01.etfuturum.mixins.early.spectator;

import ganymedes01.etfuturum.spectator.SpectatorMode;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
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.CallbackInfoReturnable;

@Mixin(Slot.class)
public class MixinSlot {
@Inject(method = "canTakeStack", at = @At(value = "HEAD"), cancellable = true)
private void cancelTake(EntityPlayer p_82869_1_, CallbackInfoReturnable<Boolean> cir) {
if(SpectatorMode.isSpectator(p_82869_1_)) {
cir.setReturnValue(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public class MixinEntityPlayer {
@Inject(method = "isInvisibleToPlayer", at = @At("HEAD"), cancellable = true)
public void isInvisibleToPlayer(EntityPlayer player, CallbackInfoReturnable<Boolean> cir) {
if (SpectatorMode.isSpectator(player)) {
cir.setReturnValue(false);
cir.setReturnValue(false); //TODO: Make it so spectators can see each other
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package ganymedes01.etfuturum.mixins.late.spectator;

import appeng.container.AEBaseContainer;
import appeng.core.sync.packets.PacketInventoryAction;
import appeng.helpers.InventoryAction;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import ganymedes01.etfuturum.spectator.SpectatorMode;
import net.minecraft.entity.player.EntityPlayerMP;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

@Mixin(PacketInventoryAction.class)
public class MixinPacketInventoryAction {
@WrapOperation(method = "serverPacketData", remap = false, at = @At(value = "INVOKE",
target = "Lappeng/container/AEBaseContainer;doAction(Lnet/minecraft/entity/player/EntityPlayerMP;Lappeng/helpers/InventoryAction;IJ)V"))
private void cancelInventoryActions(AEBaseContainer instance, EntityPlayerMP player, InventoryAction action, int slot, long id, Operation<Void> original) {
if(!SpectatorMode.isSpectator(player)) {
original.call(instance, player, action, slot, id);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ public void onPlayerTick(TickEvent.PlayerTickEvent event) {

Entity entityToSpectate = SPECTATING_ENTITIES.get(event.player);
if (entityToSpectate != null) {
if (entityToSpectate.isDead || event.player.isSneaking()) {
if ((entityToSpectate instanceof EntityPlayer spectatingPlayer && isSpectator(spectatingPlayer))
|| entityToSpectate.isDead || event.player.isSneaking()) {
SPECTATING_ENTITIES.remove(event.player);
return;
}
Expand Down

0 comments on commit d4eb326

Please sign in to comment.