Merge branch '1.21.3' into 1.21.4

# Conflicts:
#	gradle.properties
This commit is contained in:
skippyall
2025-04-24 22:13:32 +02:00
52 changed files with 995 additions and 312 deletions
@@ -0,0 +1,24 @@
package io.github.skippyall.minions.mixins;
import io.github.skippyall.minions.mixinhelpers.EntityViewMixinHelper;
import net.minecraft.entity.Entity;
import net.minecraft.world.EntityView;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import java.util.function.Predicate;
@Mixin(EntityView.class)
public interface EntityViewMixin {
@ModifyArg(method = "getClosestPlayer(DDDDZ)Lnet/minecraft/entity/player/PlayerEntity;", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/EntityView;getClosestPlayer(DDDDLjava/util/function/Predicate;)Lnet/minecraft/entity/player/PlayerEntity;"))
private @Nullable Predicate<Entity> addMinionPredicate(@Nullable Predicate<Entity> targetPredicate) {
Predicate<Entity> predicate = EntityViewMixinHelper.ADDITIONAL_PREDICATE.get();
if(targetPredicate != null) {
return predicate.and(targetPredicate);
} else {
return predicate;
}
}
}
@@ -0,0 +1,20 @@
package io.github.skippyall.minions.mixins;
import com.llamalad7.mixinextras.sugar.Local;
import eu.pb4.graves.grave.Grave;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;
@Mixin(Grave.class)
public class GraveCompatMixin {
@ModifyArg(method = "createBlock", at = @At(value = "INVOKE", target = "Leu/pb4/graves/grave/Grave;<init>(JLcom/mojang/authlib/GameProfile;BLnet/minecraft/util/Arm;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/Identifier;Leu/pb4/graves/grave/GraveType;JJILnet/minecraft/text/Text;Ljava/util/Collection;Ljava/util/Collection;ZI)V"))
private static boolean createGrave(boolean profile, @Local(argsOnly = true) ServerPlayerEntity player) {
if(player instanceof MinionFakePlayer) {
return false;
}
return profile;
}
}
@@ -1,29 +1,36 @@
package io.github.skippyall.minions.mixins;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.mixinhelpers.EntityViewMixinHelper;
import io.github.skippyall.minions.module.MobSpawningModule;
import net.minecraft.entity.Entity;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.predicate.entity.EntityPredicates;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.world.World;
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.Redirect;
@Mixin(MobEntity.class)
public abstract class MobEntityMixin {
@Redirect(method = "checkDespawn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;getClosestPlayer(Lnet/minecraft/entity/Entity;D)Lnet/minecraft/entity/player/PlayerEntity;"))
public PlayerEntity checkMobDespawningMinion(World instance, Entity entity, double maxDistance) {
return instance.getClosestPlayer(entity.getX(), entity.getY(), entity.getZ(), maxDistance, EntityPredicates.EXCEPT_SPECTATOR.and(entity1 -> {
if(entity1 instanceof ServerPlayerEntity player) {
if(player instanceof MinionFakePlayer minion) {
return MobSpawningModule.canMinionDespawnMobs(minion);
}
@WrapOperation(method = "checkDespawn", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/World;getClosestPlayer(Lnet/minecraft/entity/Entity;D)Lnet/minecraft/entity/player/PlayerEntity;"))
public PlayerEntity checkMobDespawningMinion(World instance, Entity entity, double maxDistance, Operation<PlayerEntity> original) {
EntityViewMixinHelper.ADDITIONAL_PREDICATE.set(entity2 -> {
if(entity2 instanceof MinionFakePlayer minion) {
return MobSpawningModule.canMinionDespawnMobs(minion);
} else {
return true;
}
return false;
}));
});
PlayerEntity player = original.call(instance, entity, maxDistance);
EntityViewMixinHelper.ADDITIONAL_PREDICATE.remove();
return player;
}
}
@@ -52,7 +52,7 @@ public class PlayerListMixin {
@WrapOperation(method = "respawnPlayer", at = @At(value = "NEW", target = "(Lnet/minecraft/server/MinecraftServer;Lnet/minecraft/server/world/ServerWorld;Lcom/mojang/authlib/GameProfile;Lnet/minecraft/network/packet/c2s/common/SyncedClientOptions;)Lnet/minecraft/server/network/ServerPlayerEntity;"))
public ServerPlayerEntity makePlayerForRespawn(MinecraftServer minecraftServer, ServerWorld serverLevel, GameProfile gameProfile, SyncedClientOptions clientInformation, Operation<ServerPlayerEntity> original, ServerPlayerEntity serverPlayer, boolean bl) {
if (serverPlayer instanceof MinionFakePlayer minion) {
return MinionFakePlayer.respawnFake(minecraftServer, serverLevel, gameProfile, clientInformation);
return MinionFakePlayer.respawnFake(minecraftServer, serverLevel, gameProfile, clientInformation, minion.getData());
}
return original.call(minecraftServer, serverLevel, gameProfile, clientInformation);
}
@@ -18,7 +18,7 @@ public abstract class ServerPlayerMixin implements ServerPlayerInterface {
@Unique
public EntityPlayerActionPack actionPack;
@Override
public EntityPlayerActionPack getActionPack()
public EntityPlayerActionPack minions$getActionPack()
{
return actionPack;
}
@@ -0,0 +1,14 @@
package io.github.skippyall.minions.mixins.antimobcap;
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;
@Mixin(net.minecraft.world.ChunkPosDistanceLevelPropagator.class)
public class ChunkPosDistanceLevelPropagatorMixin {
@Inject(method = "updateLevel", at = @At("HEAD"))
public void minions$updateLevel(long chunkPos, int distance, boolean decrease, CallbackInfo info) {
}
}
@@ -0,0 +1,85 @@
package io.github.skippyall.minions.mixins.antimobcap;
import io.github.skippyall.minions.minion.fakeplayer.MinionFakePlayer;
import io.github.skippyall.minions.mixinhelper.ChunkTicketManager$DistanceFromNearestPlayerTrackerAccessor;
import io.github.skippyall.minions.mixinhelper.ChunkTicketManagerAccessor;
import io.github.skippyall.minions.module.MobSpawningModule;
import it.unimi.dsi.fastutil.longs.Long2ByteMap;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ChunkTicketManager;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
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(value = ChunkTicketManager.DistanceFromNearestPlayerTracker.class)
public abstract class ChunkTicketManager$DistanceFromNearestPlayerTrackerMixin extends ChunkPosDistanceLevelPropagatorMixin implements ChunkTicketManager$DistanceFromNearestPlayerTrackerAccessor {
@Final
@Shadow
ChunkTicketManager field_17462;
@Shadow
@Final
protected Long2ByteMap distanceFromNearestPlayer;
@Shadow protected abstract boolean isPlayerInChunk(long chunkPos);
@Unique
boolean minions$minionless, minions$target;
@Inject(method = "isPlayerInChunk", at = @At("RETURN"), cancellable = true)
public void minions$filterMinions(long chunkPos, CallbackInfoReturnable<Boolean> cir) {
if (minions$minionless) {
cir.setReturnValue(minions$isRealPlayerInChunk(chunkPos));
}
}
@Override
public boolean minions$isRealPlayerInChunk(long chunkPos) {
ObjectSet<ServerPlayerEntity> players = ((ChunkTicketManagerAccessor)field_17462).getPlayers(chunkPos);
boolean contains = false;
if(players != null) {
contains = players.stream().anyMatch(player -> {
if (player instanceof MinionFakePlayer minion) {
return MobSpawningModule.canMinionSpawnMobs(minion);
}
return true;
});
}
return contains;
}
@Inject(method = "updateLevels", at = @At("HEAD"))
public void minions$sync(CallbackInfo info) {
if (minions$target) {
((ChunkTicketManagerAccessor)field_17462).getMinionless().updateLevels();
}
}
@Override
public void minions$updateLevel(long chunkPos, int distance, boolean decrease, CallbackInfo info) {
if (minions$target && (distance == Integer.MAX_VALUE || minions$isRealPlayerInChunk(chunkPos))) {
((ChunkTicketManagerAccessor)field_17462).getMinionless().updateLevel(chunkPos, distance, decrease);
}
}
@Override
public void minions$markAsMinionless() {
minions$minionless = true;
}
@Override
public void minions$markAsTarget() {
minions$target = true;
}
@Override
public int minions$getTickedChunkCount() {
return distanceFromNearestPlayer.size();
}
}
@@ -0,0 +1,49 @@
package io.github.skippyall.minions.mixins.antimobcap;
import com.llamalad7.mixinextras.sugar.Local;
import io.github.skippyall.minions.mixinhelper.ChunkTicketManager$DistanceFromNearestPlayerTrackerAccessor;
import io.github.skippyall.minions.mixinhelper.ChunkTicketManagerAccessor;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ChunkTicketManager;
import net.minecraft.util.math.ChunkSectionPos;
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 java.util.concurrent.Executor;
@Mixin(ChunkTicketManager.class)
public class ChunkTicketManagerMixin implements ChunkTicketManagerAccessor {
@Shadow @Final private Long2ObjectMap<ObjectSet<ServerPlayerEntity>> playersByChunkPos;
@Shadow @Final private ChunkTicketManager.DistanceFromNearestPlayerTracker distanceFromNearestPlayerTracker;
ChunkTicketManager.DistanceFromNearestPlayerTracker minionless;
@Inject(method = "<init>", at = @At("RETURN"))
public void createMinionlessClone(Executor workerExecutor, Executor mainThreadExecutor, CallbackInfo ci) {
ChunkTicketManager manager = ((ChunkTicketManager)(Object)this);
minionless = manager.new DistanceFromNearestPlayerTracker(8);
((ChunkTicketManager$DistanceFromNearestPlayerTrackerAccessor)minionless).minions$markAsMinionless();
((ChunkTicketManager$DistanceFromNearestPlayerTrackerAccessor)distanceFromNearestPlayerTracker).minions$markAsTarget();
}
public ObjectSet<ServerPlayerEntity> getPlayers(long chunkpos) {
return playersByChunkPos.get(chunkpos);
}
@Override
public ChunkTicketManager.DistanceFromNearestPlayerTracker getMinionless() {
return minionless;
}
@Inject(method = "handleChunkLeave", at = @At(value = "INVOKE", target = "Lit/unimi/dsi/fastutil/objects/ObjectSet;remove(Ljava/lang/Object;)Z", shift = At.Shift.AFTER, remap = false))
public void minion$updateMinionlessIfNoMinionInChunk(ChunkSectionPos pos, ServerPlayerEntity player, CallbackInfo ci, @Local long chunk) {
if (!((ChunkTicketManager$DistanceFromNearestPlayerTrackerAccessor)minionless).minions$isRealPlayerInChunk(chunk)) {
minionless.updateLevel(chunk, Integer.MAX_VALUE, false);
}
}
}
@@ -0,0 +1,12 @@
package io.github.skippyall.minions.mixins.antimobcap;
import net.minecraft.server.world.ChunkTicketManager;
import net.minecraft.server.world.ServerChunkManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ServerChunkManager.class)
public interface ServerChunkManagerAccessor {
@Accessor
ChunkTicketManager getTicketManager();
}
@@ -0,0 +1,23 @@
package io.github.skippyall.minions.mixins.antimobcap;
import io.github.skippyall.minions.mixinhelper.ChunkTicketManager$DistanceFromNearestPlayerTrackerAccessor;
import io.github.skippyall.minions.mixinhelper.ChunkTicketManagerAccessor;
import net.minecraft.server.world.ChunkTicketManager;
import net.minecraft.server.world.ServerChunkManager;
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.ModifyArg;
@Mixin(ServerChunkManager.class)
public class ServerChunkManagerMixin {
@Shadow
@Final
private ChunkTicketManager ticketManager;
@ModifyArg(method = "tickChunks(Lnet/minecraft/util/profiler/Profiler;JLjava/util/List;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/SpawnHelper;setupSpawn(ILjava/lang/Iterable;Lnet/minecraft/world/SpawnHelper$ChunkSource;Lnet/minecraft/world/SpawnDensityCapper;)Lnet/minecraft/world/SpawnHelper$Info;"))
public int useMinionless(int spawningChunkCount) {
return ((ChunkTicketManager$DistanceFromNearestPlayerTrackerAccessor)((ChunkTicketManagerAccessor)ticketManager).getMinionless()).minions$getTickedChunkCount();
}
}