7 Commits

Author SHA1 Message Date
skippyall cdd0a594f3 Merge branch '1.21.3' into 1.21.4
# Conflicts:
#	gradle.properties
2025-04-24 22:13:32 +02:00
skippyall a9d0b7fd94 Merge branch 'feature/skin_improvements' into 1.21.3
# Conflicts:
#	src/main/java/io/github/skippyall/minions/module/MoveModule.java
#	src/main/resources/minions.mixins.json
2025-04-24 22:11:34 +02:00
skippyall a2a189a0c1 Merge pull request #2 from Mineattack-Foxgalaxy/feature/mob-cap-fix
Bugfixes (Minion Mobcap)
2025-04-16 20:05:02 +02:00
Erfinderlabyrinth d2d96b3f67 Bugfixes (Minion Mobcap) 2025-04-16 15:29:16 +02:00
skippyall 08e7952e34 Mob Cap fix 2025-04-14 21:45:04 +02:00
skippyall cc69b22aba Turn Up/Down & Grave Compat 2025-04-12 19:08:25 +02:00
skippyall d3b25b595a Too simple 1.21.4 Port 2025-01-30 21:23:34 +01:00
16 changed files with 291 additions and 7 deletions
+18
View File
@@ -6,6 +6,10 @@ plugins {
version = project.mod_version version = project.mod_version
group = project.maven_group group = project.maven_group
loom {
accessWidenerPath = file("src/main/resources/minions.accesswidener")
}
base { base {
archivesName = project.archives_base_name archivesName = project.archives_base_name
} }
@@ -21,6 +25,18 @@ repositories {
// See https://docs.gradle.org/current/userguide/declaring_repositories.html // See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories. // for more information about repositories.
maven { url 'https://maven.nucleoid.xyz' } maven { url 'https://maven.nucleoid.xyz' }
exclusiveContent {
forRepository {
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
}
}
filter {
includeGroup "maven.modrinth"
}
}
} }
dependencies { dependencies {
@@ -34,6 +50,8 @@ dependencies {
modImplementation "eu.pb4:polymer-core:${project.polymer_version}" modImplementation "eu.pb4:polymer-core:${project.polymer_version}"
modImplementation include("eu.pb4:sgui:${project.sgui_version}") modImplementation include("eu.pb4:sgui:${project.sgui_version}")
modImplementation include("xyz.nucleoid:server-translations-api:${project.server_translations_version}") modImplementation include("xyz.nucleoid:server-translations-api:${project.server_translations_version}")
modCompileOnly "maven.modrinth:universal-graves:${project.universal_graves_version}"
} }
processResources { processResources {
+7 -5
View File
@@ -3,9 +3,9 @@ org.gradle.jvmargs=-Xmx1G
# Fabric Properties # Fabric Properties
# check these on https://modmuss50.me/fabric.html # check these on https://modmuss50.me/fabric.html
minecraft_version=1.21.3 minecraft_version=1.21.4
loader_version=0.16.13 loader_version=0.16.13
yarn_mappings=1.21.3+build.2 yarn_mappings=1.21.4+build.8
# Mod Properties # Mod Properties
mod_version = 0.1.2-SNAPSHOT mod_version = 0.1.2-SNAPSHOT
@@ -14,8 +14,10 @@ org.gradle.jvmargs=-Xmx1G
# Dependencies # Dependencies
# check this on https://modmuss50.me/fabric.html # check this on https://modmuss50.me/fabric.html
fabric_version=0.107.0+1.21.3 fabric_version=0.115.1+1.21.4
polymer_version=0.10.0+1.21.2 polymer_version=0.11.5+1.21.4
sgui_version=1.7.1+1.21.2 sgui_version=1.8.2+1.21.4
server_translations_version=2.4.0+1.21.2-rc1 server_translations_version=2.4.0+1.21.2-rc1
universal_graves_version=3.5.0+1.21.2
@@ -8,6 +8,7 @@ import io.github.skippyall.minions.minion.MinionItem;
import io.github.skippyall.minions.minion.MinionPersistentState; import io.github.skippyall.minions.minion.MinionPersistentState;
import io.github.skippyall.minions.module.Modules; import io.github.skippyall.minions.module.Modules;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents;
import net.minecraft.component.DataComponentTypes; import net.minecraft.component.DataComponentTypes;
@@ -21,6 +22,7 @@ import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey; import net.minecraft.registry.RegistryKey;
import net.minecraft.registry.RegistryKeys; import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey; import net.minecraft.registry.tag.TagKey;
import net.minecraft.server.world.ChunkTicketManager;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -51,6 +53,10 @@ public class Minions implements ModInitializer {
}); });
}); });
CommandRegistrationCallback.EVENT.register((commandDispatcher, commandRegistryAccess, registrationEnvironment) -> {
MobCapCommand.registerCommand(commandDispatcher);
});
Modules.register(); Modules.register();
} }
@@ -0,0 +1,24 @@
package io.github.skippyall.minions;
import com.mojang.brigadier.CommandDispatcher;
import io.github.skippyall.minions.mixinhelper.ChunkTicketManager$DistanceFromNearestPlayerTrackerAccessor;
import io.github.skippyall.minions.mixinhelper.ChunkTicketManagerAccessor;
import io.github.skippyall.minions.mixins.antimobcap.ServerChunkManagerAccessor;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.world.ChunkTicketManager;
import net.minecraft.text.Text;
import static net.minecraft.server.command.CommandManager.literal;
public class MobCapCommand {
public static void registerCommand(CommandDispatcher<ServerCommandSource> dispatcher) {
dispatcher.register(literal("mobcapdebug")
.executes(context -> {
ChunkTicketManager ticketManager = ((ServerChunkManagerAccessor)context.getSource().getWorld().getChunkManager()).getTicketManager();
int tickedChunkCount = ((ChunkTicketManager$DistanceFromNearestPlayerTrackerAccessor)((ChunkTicketManagerAccessor)ticketManager).getMinionless()).minions$getTickedChunkCount();
context.getSource().sendFeedback(() -> Text.of(String.valueOf(tickedChunkCount)), false);
return 0;
})
);
}
}
@@ -0,0 +1,9 @@
package io.github.skippyall.minions.mixinhelper;
public interface ChunkTicketManager$DistanceFromNearestPlayerTrackerAccessor {
void minions$markAsMinionless();
void minions$markAsTarget();
int minions$getTickedChunkCount();
boolean minions$isRealPlayerInChunk(long chunkPos);
}
@@ -0,0 +1,11 @@
package io.github.skippyall.minions.mixinhelper;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ChunkTicketManager;
public interface ChunkTicketManagerAccessor {
ObjectSet<ServerPlayerEntity> getPlayers(long chunkpos);
ChunkTicketManager.DistanceFromNearestPlayerTracker getMinionless();
}
@@ -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;
}
}
@@ -10,7 +10,7 @@ import org.spongepowered.asm.mixin.injection.ModifyArg;
@Mixin(PlayerListS2CPacket.Entry.class) @Mixin(PlayerListS2CPacket.Entry.class)
public class PlayerListEntryS2CPacket$EntryMixin { public class PlayerListEntryS2CPacket$EntryMixin {
@ModifyArg(method = "<init>(Lnet/minecraft/server/network/ServerPlayerEntity;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/PlayerListS2CPacket$Entry;<init>(Ljava/util/UUID;Lcom/mojang/authlib/GameProfile;ZILnet/minecraft/world/GameMode;Lnet/minecraft/text/Text;ILnet/minecraft/network/encryption/PublicPlayerSession$Serialized;)V")) @ModifyArg(method = "<init>(Lnet/minecraft/server/network/ServerPlayerEntity;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/PlayerListS2CPacket$Entry;<init>(Ljava/util/UUID;Lcom/mojang/authlib/GameProfile;ZILnet/minecraft/world/GameMode;Lnet/minecraft/text/Text;ZILnet/minecraft/network/encryption/PublicPlayerSession$Serialized;)V"), index = 2)
private static boolean removeMinionFromTabList(boolean original, @Local(argsOnly = true) ServerPlayerEntity player) { private static boolean removeMinionFromTabList(boolean original, @Local(argsOnly = true) ServerPlayerEntity player) {
if(player instanceof MinionFakePlayer) { if(player instanceof MinionFakePlayer) {
return false; return false;
@@ -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();
}
}
+1
View File
@@ -19,6 +19,7 @@
"mixins": [ "mixins": [
"minions.mixins.json" "minions.mixins.json"
], ],
"accessWidener" : "minions.accesswidener",
"depends": { "depends": {
"fabricloader": "*", "fabricloader": "*",
"fabric": "*", "fabric": "*",
+4
View File
@@ -0,0 +1,4 @@
accessWidener v2 named
accessible class net/minecraft/server/world/ChunkTicketManager$DistanceFromNearestPlayerTracker
accessible method net/minecraft/server/world/ChunkTicketManager$DistanceFromNearestPlayerTracker <init> (Lnet/minecraft/server/world/ChunkTicketManager;I)V
+7 -1
View File
@@ -7,6 +7,7 @@
"ChunkTicketManagerFixMixin", "ChunkTicketManagerFixMixin",
"ConnectionMixin", "ConnectionMixin",
"EntityAccessor", "EntityAccessor",
"GraveCompatMixin",
"EntityViewMixin", "EntityViewMixin",
"MinecraftServerMixin", "MinecraftServerMixin",
"MobEntityMixin", "MobEntityMixin",
@@ -15,7 +16,12 @@
"ServerPlayerMixin", "ServerPlayerMixin",
"ServerPlayNetworkHandlerMixin", "ServerPlayNetworkHandlerMixin",
"SleepManagerMixin", "SleepManagerMixin",
"SpawnHelperMixin" "SpawnHelperMixin",
"antimobcap.ChunkPosDistanceLevelPropagatorMixin",
"antimobcap.ChunkTicketManager$DistanceFromNearestPlayerTrackerMixin",
"antimobcap.ChunkTicketManagerMixin",
"antimobcap.ServerChunkManagerAccessor",
"antimobcap.ServerChunkManagerMixin"
], ],
"client": [], "client": [],
"server": [], "server": [],