diff --git a/src/main/java/carpet/commands/SpawnCommand.java b/src/main/java/carpet/commands/SpawnCommand.java index 0e8827b5..3fc58929 100644 --- a/src/main/java/carpet/commands/SpawnCommand.java +++ b/src/main/java/carpet/commands/SpawnCommand.java @@ -19,6 +19,8 @@ import net.minecraft.util.math.BlockPos; import net.minecraft.world.dimension.DimensionType; import java.util.Arrays; +import java.util.Objects; +import java.util.stream.Collectors; import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger; import static com.mojang.brigadier.arguments.IntegerArgumentType.integer; @@ -54,7 +56,7 @@ public class SpawnCommand then(literal("stop"). executes( (c) -> stopTracking(c.getSource()))). then(argument("type", word()). - suggests( (c, b) -> suggestMatching(SpawnReporter.mob_groups,b)). + suggests( (c, b) -> suggestMatching(Arrays.stream(EntityCategory.values()).map(EntityCategory::getName),b)). executes( (c) -> recentSpawnsForType(c.getSource(), getString(c, "type"))))). then(literal("test"). executes( (c)-> runTest(c.getSource(), 72000, null)). @@ -77,7 +79,7 @@ public class SpawnCommand then(literal("reset"). executes( (c) -> resetSpawnRates(c.getSource()))). then(argument("type", word()). - suggests( (c, b) -> suggestMatching(SpawnReporter.mob_groups,b)). + suggests( (c, b) -> suggestMatching(Arrays.stream(EntityCategory.values()).map(EntityCategory::getName),b)). then(argument("rounds", integer(0)). suggests( (c, b) -> suggestMatching(new String[]{"1"},b)). executes( (c) -> setSpawnRates( @@ -94,7 +96,7 @@ public class SpawnCommand then(literal("entities"). executes( (c) -> generalMobcaps(c.getSource()) ). then(argument("type", string()). - suggests( (c, b)->suggestMatching(SpawnReporter.mob_groups, b)). + suggests( (c, b)->suggestMatching(Arrays.stream(EntityCategory.values()).map(EntityCategory::getName), b)). executes( (c) -> listEntitiesOfType(c.getSource(), getString(c, "type"))))); dispatcher.register(literalargumentbuilder); @@ -153,12 +155,12 @@ public class SpawnCommand private static int recentSpawnsForType(ServerCommandSource source, String mob_type) { - if (!Arrays.asList(SpawnReporter.mob_groups).contains(mob_type)) + if (!Arrays.asList(Arrays.stream(EntityCategory.values()).map(Enum::toString)).contains(mob_type)) { - Messenger.m(source, "r Wrong mob type: "+mob_type); + Messenger.m(source, "r Wrong mob type: "+mob_type+" should be "+String.join(", ",Arrays.stream(EntityCategory.values()).map(Enum::toString).collect(Collectors.toSet())) ); return 0; } - Messenger.send(source, SpawnReporter.recent_spawns(source.getWorld(), mob_type)); + //Messenger.send(source, SpawnReporter.recent_spawns(source.getWorld(), mob_type)); return 1; } @@ -222,7 +224,7 @@ public class SpawnCommand private static int resetSpawnRates(ServerCommandSource source) { - for (String s: SpawnReporter.spawn_tries.keySet()) + for (EntityCategory s: SpawnReporter.spawn_tries.keySet()) { SpawnReporter.spawn_tries.put(s,1); } @@ -234,7 +236,7 @@ public class SpawnCommand private static int setSpawnRates(ServerCommandSource source, String mobtype, int rounds) { String code = SpawnReporter.get_creature_code_from_string(mobtype); - SpawnReporter.spawn_tries.put(code, rounds); + //SpawnReporter.spawn_tries.put(code, rounds); Messenger.m(source, "gi "+mobtype+" mobs will now spawn "+rounds+" times per tick"); return 1; } @@ -255,7 +257,7 @@ public class SpawnCommand private static int listEntitiesOfType(ServerCommandSource source, String mobtype) { - Messenger.send(source, SpawnReporter.printEntitiesByType(mobtype, source.getWorld())); + Messenger.send(source, SpawnReporter.printEntitiesByType(EntityCategory.valueOf(mobtype.toUpperCase()), source.getWorld())); return 1; } } diff --git a/src/main/java/carpet/helpers/XPcombine.java b/src/main/java/carpet/helpers/XPcombine.java index d1039652..8dac2226 100644 --- a/src/main/java/carpet/helpers/XPcombine.java +++ b/src/main/java/carpet/helpers/XPcombine.java @@ -21,10 +21,11 @@ public class XPcombine } } private static long tone = 0; + private static int lastTickCombine = 0; private static boolean combineItems(ExperienceOrbEntity first, ExperienceOrbEntity other) { if ( - first == other || first.world.isClient + first == other || first.world.isClient || first.getServer().getTicks() == lastTickCombine || !first.isAlive() || !other.isAlive() || first.pickupDelay == 32767 || other.pickupDelay == 32767 || first.age == -32768 || other.age == -32768 @@ -61,9 +62,10 @@ public class XPcombine (first.world.random.nextDouble() * 0.5D), (first.world.random.nextDouble() * 1.0D - 0.5D) ))); - double pitch = Math.pow(2.0D, (tone%13)/12.0D )/2.0; + float pitch = (float)Math.pow(2.0D, (tone%13)/12.0D )/2.0F; tone+=2; if(tone%13 == 0 || tone%13 == 1 || tone%13 == 6) tone --; + lastTickCombine = newOrb.getServer().getTicks(); for (PlayerEntity p : newOrb.world.getPlayers()) { ServerPlayerEntity sp = (ServerPlayerEntity)p; @@ -71,7 +73,9 @@ public class XPcombine { sp.networkHandler.sendPacket(new PlaySoundIdS2CPacket( Registry.SOUND_EVENT.getId(SoundEvents.ENTITY_EXPERIENCE_ORB_PICKUP), - SoundCategory.BLOCKS, newOrb.getPos(), 1.0F, (float)pitch)); + SoundCategory.PLAYERS, newOrb.getPos(), + pitch-newOrb.world.random.nextFloat()/2f, + pitch)); } } return true; diff --git a/src/main/java/carpet/mixins/DebugHudMixin.java b/src/main/java/carpet/mixins/DebugHudMixin.java new file mode 100644 index 00000000..2380640f --- /dev/null +++ b/src/main/java/carpet/mixins/DebugHudMixin.java @@ -0,0 +1,41 @@ +package carpet.mixins; + +import carpet.CarpetSettings; +import com.mojang.bridge.game.GameVersion; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.hud.DebugHud; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(DebugHud.class) +public class DebugHudMixin +{ + @Redirect(method = "getLeftText", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/MinecraftClient;getGameVersion()Ljava/lang/String;" + )) + private String getCarpetClient(MinecraftClient minecraftClient) + { + return "vanilla enough"; + } + + @Redirect(method = "getLeftText", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/ClientBrandRetriever;getClientModName()Ljava/lang/String;" + )) + private String getModName() + { + return "don't even..."; + } + + @Redirect(method = "getLeftText", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/client/MinecraftClient;getVersionType()Ljava/lang/String;" + )) + private String getVersionType(MinecraftClient minecraftClient) + { + return "release"; + } + +} diff --git a/src/main/java/carpet/mixins/MinecraftClientMixin.java b/src/main/java/carpet/mixins/MinecraftClientMixin.java index 806c6d1d..533288b5 100644 --- a/src/main/java/carpet/mixins/MinecraftClientMixin.java +++ b/src/main/java/carpet/mixins/MinecraftClientMixin.java @@ -1,8 +1,10 @@ package carpet.mixins; import carpet.CarpetServer; +import carpet.CarpetSettings; import net.minecraft.client.MinecraftClient; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -18,4 +20,13 @@ public class MinecraftClientMixin //CM start game hook CarpetServer.onGameStarted(); } + + /** + * @author gnembon + */ + @Overwrite + public String getVersionType() + { + return "carpet "+ CarpetSettings.carpetVersion; + } } diff --git a/src/main/java/carpet/mixins/ServerChunkManagerMixin.java b/src/main/java/carpet/mixins/ServerChunkManagerMixin.java index 11d3666f..b8292cba 100644 --- a/src/main/java/carpet/mixins/ServerChunkManagerMixin.java +++ b/src/main/java/carpet/mixins/ServerChunkManagerMixin.java @@ -7,21 +7,32 @@ import net.minecraft.entity.EntityCategory; import net.minecraft.server.world.ServerChunkManager; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.SpawnHelper; +import net.minecraft.world.World; +import net.minecraft.world.chunk.WorldChunk; import net.minecraft.world.dimension.DimensionType; import net.minecraft.world.level.LevelProperties; +import org.apache.commons.lang3.tuple.Pair; 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.ModifyConstant; +import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import java.util.HashMap; +import java.util.HashSet; + @Mixin(ServerChunkManager.class) public abstract class ServerChunkManagerMixin { @Shadow @Final private ServerWorld world; + @Shadow @Final private static int CHUNKS_ELIGIBLE_FOR_SPAWNING; + @Inject( method = "tickChunks", locals = LocalCapture.CAPTURE_FAILHARD, @@ -32,6 +43,7 @@ public abstract class ServerChunkManagerMixin ordinal = 0 )) + //this runs once per world spawning cycle. Allows to grab mob counts and count spawn ticks private void grabMobcaps(CallbackInfo ci, long long_1, long long_2, @@ -48,6 +60,119 @@ public abstract class ServerChunkManagerMixin DimensionType dim = this.world.dimension.getType(); SpawnReporter.mobCounts.put(dim, (Object2IntMap)object2IntMap_1); SpawnReporter.chunkCounts.put(dim, int_2); + + if (SpawnReporter.track_spawns > 0L) + { + //local spawns now need to be tracked globally cause each calll is just for chunk + SpawnReporter.local_spawns = new HashMap<>(); + SpawnReporter.first_chunk_marker = new HashSet<>(); + for (EntityCategory cat : EntityCategory.values()) + { + Pair key = Pair.of(dim, cat); + SpawnReporter.overall_spawn_ticks.put(key, + SpawnReporter.overall_spawn_ticks.get(key)+ + SpawnReporter.spawn_tries.get(cat)); + } + } + } + + @Redirect(method = "tickChunks", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/SpawnHelper;spawnEntitiesInChunk(Lnet/minecraft/entity/EntityCategory;Lnet/minecraft/world/World;Lnet/minecraft/world/chunk/WorldChunk;Lnet/minecraft/util/math/BlockPos;)V" + )) + // inject our repeat of spawns if more spawn ticks per tick are chosen. + private void spawnMultipleTimes(EntityCategory entityCategory_1, World world_1, WorldChunk worldChunk_1, BlockPos blockPos_1) + { + for (int i = 0; i < SpawnReporter.spawn_tries.get(entityCategory_1); i++) + { + SpawnHelper.spawnEntitiesInChunk(entityCategory_1, world_1, worldChunk_1, blockPos_1); + } + } + + @Redirect(method = "tickChunks", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/entity/EntityCategory;getSpawnCap()I" + )) + // allows to change mobcaps and captures each category try per dimension before it fails due to full mobcaps. + private int getNewMobcaps(EntityCategory entityCategory) + { + DimensionType dim = this.world.dimension.getType(); + int newCap = entityCategory.getSpawnCap()*(int)(Math.pow(2.0,(SpawnReporter.mobcap_exponent/4))); + if (SpawnReporter.track_spawns > 0L) + { + int int_2 = SpawnReporter.chunkCounts.get(dim); // eligible chunks for spawning + int int_3 = newCap * int_2 / CHUNKS_ELIGIBLE_FOR_SPAWNING; //current spawning limits + int mobCount = SpawnReporter.mobCounts.get(dim).getInt(entityCategory); + + if (SpawnReporter.track_spawns > 0L && !SpawnReporter.first_chunk_marker.contains(entityCategory)) + { + SpawnReporter.first_chunk_marker.add(entityCategory); + //first chunk with spawn eligibility for that category + Pair key = Pair.of(dim, entityCategory); + + + int spawnTries = SpawnReporter.spawn_tries.get(entityCategory); + + SpawnReporter.spawn_attempts.put(key, + SpawnReporter.spawn_attempts.get(key) + spawnTries); + + SpawnReporter.spawn_cap_count.put(key, + SpawnReporter.spawn_cap_count.get(key) + mobCount); + } + + if (mobCount <= int_3) + { + //place 0 to indicate there were spawn attempts for a category + //if (entityCategory != EntityCategory.CREATURE || world.getServer().getTicks() % 400 == 0) + // this will only be called once every 400 ticks anyways + SpawnReporter.local_spawns.putIfAbsent(entityCategory, 0L); + + //else + //full mobcaps - and key in local_spawns will be missing + } + } + return SpawnReporter.mock_spawns?Integer.MAX_VALUE:newCap; + } + + @Inject(method = "tickChunks", at = @At("RETURN")) + private void onFinishSpawnWorldCycle(CallbackInfo ci) + { + if (SpawnReporter.track_spawns > 0L && SpawnReporter.local_spawns != null) + { + for (EntityCategory cat: EntityCategory.values()) + { + DimensionType dim = world.dimension.getType(); + Pair key = Pair.of(world.dimension.getType(), cat); + int spawnTries = SpawnReporter.spawn_tries.get(cat); + if (!SpawnReporter.local_spawns.containsKey(cat)) + { + // fill mobcaps for that category so spawn got cancelled + SpawnReporter.spawn_ticks_full.put(key, + SpawnReporter.spawn_ticks_full.get(key)+ spawnTries); + } + else if (SpawnReporter.local_spawns.get(cat) > 0) + { + // tick spawned mobs for that type + SpawnReporter.spawn_ticks_succ.put(key, + SpawnReporter.spawn_ticks_succ.get(key)+spawnTries); + SpawnReporter.spawn_ticks_spawns.put(key, + SpawnReporter.spawn_ticks_spawns.get(key)+ + SpawnReporter.local_spawns.get(cat)); + // this will be off comparing to 1.13 as that would succeed if + // ANY tries in that round were successful. + // there will be much more difficult to mix in + // considering spawn tries to remove, as with warp + // there is little need for them anyways. + } + else // spawn no mobs despite trying + { + //tick didn's spawn mobs of that type + SpawnReporter.spawn_ticks_fail.put(key, + SpawnReporter.spawn_ticks_fail.get(key)+spawnTries); + } + } + } + SpawnReporter.local_spawns = null; } } diff --git a/src/main/java/carpet/mixins/ServerChunkManager_spawnMixin.java b/src/main/java/carpet/mixins/ServerChunkManager_spawnMixin.java new file mode 100644 index 00000000..7781dcc8 --- /dev/null +++ b/src/main/java/carpet/mixins/ServerChunkManager_spawnMixin.java @@ -0,0 +1,5 @@ +package carpet.mixins; + +public class ServerChunkManager_spawnMixin +{ +} diff --git a/src/main/java/carpet/mixins/SpawnHelperMixin.java b/src/main/java/carpet/mixins/SpawnHelperMixin.java new file mode 100644 index 00000000..9f0b264e --- /dev/null +++ b/src/main/java/carpet/mixins/SpawnHelperMixin.java @@ -0,0 +1,36 @@ +package carpet.mixins; + +import carpet.CarpetSettings; +import carpet.utils.SpawnReporter; +import net.minecraft.entity.Entity; +import net.minecraft.entity.mob.MobEntity; +import net.minecraft.world.SpawnHelper; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(SpawnHelper.class) +public abstract class SpawnHelperMixin +{ + @Redirect(method = "spawnEntitiesInChunk", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/World;spawnEntity(Lnet/minecraft/entity/Entity;)Z" + )) + private static boolean catchEntitySpawn(World world, Entity entity_1) + { + if (SpawnReporter.track_spawns > 0L && SpawnReporter.local_spawns != null) + { + SpawnReporter.registerSpawn( + world.dimension.getType(), + (MobEntity) entity_1, + entity_1.getType().getCategory(), + entity_1.getBlockPos()); + } + if (!SpawnReporter.mock_spawns) + return world.spawnEntity(entity_1); + return false; + } + + +} diff --git a/src/main/java/carpet/utils/EvictingQueue.java b/src/main/java/carpet/utils/EvictingQueue.java index 253d51c5..f313aa7f 100644 --- a/src/main/java/carpet/utils/EvictingQueue.java +++ b/src/main/java/carpet/utils/EvictingQueue.java @@ -3,11 +3,18 @@ package carpet.utils; import java.util.LinkedHashMap; import java.util.Map; -public class EvictingQueue extends LinkedHashMap +public class EvictingQueue extends LinkedHashMap { - @Override - protected boolean removeEldestEntry(Map.Entry eldest) + public void put(K key) + { + super.put(key, 1); + } + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) { return this.size() > 10; } + + } \ No newline at end of file diff --git a/src/main/java/carpet/utils/SpawnReporter.java b/src/main/java/carpet/utils/SpawnReporter.java index 7e456c87..986ed343 100644 --- a/src/main/java/carpet/utils/SpawnReporter.java +++ b/src/main/java/carpet/utils/SpawnReporter.java @@ -1,19 +1,24 @@ package carpet.utils; +import java.util.HashSet; import java.util.List; import java.util.ArrayList; import java.util.HashMap; +import carpet.CarpetSettings; import carpet.mixins.WeightedPickerEntryMixin; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2LongMap; +import it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap; +import net.minecraft.entity.EntityType; import net.minecraft.entity.SpawnType; import net.minecraft.entity.mob.MobEntity; import net.minecraft.server.world.ServerChunkManager; +import net.minecraft.server.world.ServerWorld; import net.minecraft.structure.OceanMonumentGenerator; -import net.minecraft.util.Pair; import net.minecraft.util.registry.Registry; import net.minecraft.network.chat.BaseComponent; import net.minecraft.world.World; @@ -34,49 +39,41 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.passive.OcelotEntity; import net.minecraft.world.Heightmap; import net.minecraft.world.gen.chunk.ChunkGenerator; +import org.apache.commons.lang3.tuple.Pair; import java.lang.Math; public class SpawnReporter { - public static String [] mob_groups = {"hostile","passive","water","ambient"}; public static boolean mock_spawns = false; public static Long track_spawns = 0L; public static final HashMap> mobCounts = new HashMap<>(); public static final HashMap chunkCounts = new HashMap<>(); - public static final HashMap> spawn_stats = new HashMap>(); + public static final HashMap, Object2LongMap> spawn_stats = new HashMap<>(); public static double mobcap_exponent = 0.0D; - public static final HashMap spawn_attempts = new HashMap(); - public static final HashMap overall_spawn_ticks = new HashMap(); - public static final HashMap spawn_ticks_full = new HashMap(); - public static final HashMap spawn_ticks_fail = new HashMap(); - public static final HashMap spawn_ticks_succ = new HashMap(); - public static final HashMap spawn_ticks_spawns = new HashMap(); - public static final HashMap spawn_cap_count = new HashMap(); - public static class SpawnPos - { - public String mob; - public BlockPos pos; - public SpawnPos(String mob, BlockPos pos) - { - this.mob = mob; - this.pos = pos; - } - } - public static final HashMap> spawned_mobs = new HashMap<>(); - public static final HashMap spawn_tries = new HashMap<>(); + public static final HashMap, Long> spawn_attempts = new HashMap<>(); + public static final HashMap, Long> overall_spawn_ticks = new HashMap<>(); + public static final HashMap, Long> spawn_ticks_full = new HashMap<>(); + public static final HashMap, Long> spawn_ticks_fail = new HashMap<>(); + public static final HashMap, Long> spawn_ticks_succ = new HashMap<>(); + public static final HashMap, Long> spawn_ticks_spawns = new HashMap<>(); + public static final HashMap, Long> spawn_cap_count = new HashMap<>(); + public static final HashMap, EvictingQueue>> spawned_mobs = new HashMap<>(); + public static final HashMap spawn_tries = new HashMap<>(); public static BlockPos lower_spawning_limit = null; public static BlockPos upper_spawning_limit = null; + // in case game gets each thread for each world - these need to belong to workd. + public static HashMap local_spawns = null; // per world + public static HashSet first_chunk_marker = null; static { reset_spawn_stats(true); } - public static void registerSpawn(LivingEntity el, String type, String mob, BlockPos pos) { registerSpawn(el, type, mob, pos, 1L);} - public static void registerSpawn(LivingEntity el, String type, String mob, BlockPos pos, long value) + public static void registerSpawn(DimensionType dim, MobEntity mob, EntityCategory cat, BlockPos pos) { if (lower_spawning_limit != null) { @@ -88,10 +85,11 @@ public class SpawnReporter return; } } - - long count = spawn_stats.get(type).getOrDefault(mob, 0L); - spawn_stats.get(type).put(mob, count + value); - spawned_mobs.get(type).put(new SpawnPos(mob, new BlockPos(el)), 1); + Pair key = Pair.of(mob.dimension, cat); + long count = spawn_stats.get(key).getOrDefault(mob.getType(), 0L); + spawn_stats.get(key).put(mob.getType(), count + 1); + spawned_mobs.get(key).put(Pair.of(mob.getType(), pos)); + local_spawns.put(cat, local_spawns.get(cat)+1); } @@ -112,17 +110,16 @@ public class SpawnReporter List shortCodes = new ArrayList<>(); for (EntityCategory enumcreaturetype : EntityCategory.values()) { - String type_code = String.format("%s", enumcreaturetype); int cur = dimCounts.getOrDefault(enumcreaturetype, -1); int max = chunkcount * enumcreaturetype.getSpawnCap() / (int)Math.pow(17.0D, 2.0D); // from ServerChunkManager.CHUNKS_ELIGIBLE_FOR_SPAWNING String color = Messenger.heatmap_color(cur, max); String mobColor = Messenger.creatureTypeColor(enumcreaturetype); if (multiline) { - int rounds = spawn_tries.get(type_code); - lst.add(Messenger.c(String.format("w %s: ", type_code), + int rounds = spawn_tries.get(enumcreaturetype); + lst.add(Messenger.c(String.format("w %s: ", enumcreaturetype.getName()), (cur < 0) ? "g -" : (color + " " + cur), "g / ", mobColor + " " + max, - (rounds == 1) ? "w " : String.format("fi (%d rounds/tick)", spawn_tries.get(type_code)) + (rounds == 1) ? "w " : String.format("fi (%d rounds/tick)", spawn_tries.get(enumcreaturetype)) )); } else @@ -149,28 +146,20 @@ public class SpawnReporter return lst; } - public static List recent_spawns(World world, String creature_type_code) + public static List recent_spawns(World world, EntityCategory creature_type) { - - EntityCategory creature_type = get_creature_type_from_code(creature_type_code); List lst = new ArrayList<>(); if ((track_spawns == 0L)) { lst.add(Messenger.s("Spawn tracking not started")); return lst; } - if (creature_type == null) - { - lst.add(Messenger.s(String.format("Incorrect creature type: %s",creature_type_code))); - return lst; - } - - String type_code = get_type_string(creature_type); + String type_code = creature_type.getName(); lst.add(Messenger.s(String.format("Recent %s spawns:",type_code))); - for (SpawnPos entry: spawned_mobs.get(type_code).keySet()) + for (Pair pair : spawned_mobs.get(Pair.of(world.getDimension().getType(),creature_type)).keySet()) { - lst.add( Messenger.c(String.format("w - %s ",entry.mob), Messenger.tp("wb",entry.pos))); + lst.add( Messenger.c(String.format("w - %s ",pair.getLeft()), Messenger.tp("wb",pair.getRight()))); } if (lst.size()==1) @@ -192,10 +181,10 @@ public class SpawnReporter } else { - //return print_general_mobcaps(worldIn); + return new ArrayList<>(); } } - String creature_type = get_type_code_from_wool_code(under); + EntityCategory creature_type = get_type_code_from_wool_code(under); if (creature_type != null) { if (track_spawns > 0L) @@ -222,18 +211,18 @@ public class SpawnReporter } - public static String get_type_code_from_wool_code(DyeColor color) + public static EntityCategory get_type_code_from_wool_code(DyeColor color) { switch (color) { case RED: - return "hostile"; + return EntityCategory.MONSTER; case GREEN: - return "passive"; + return EntityCategory.CREATURE; case BLUE: - return "water"; + return EntityCategory.WATER_CREATURE; case BROWN: - return "ambient"; + return EntityCategory.AMBIENT; } return null; } @@ -270,27 +259,22 @@ public class SpawnReporter return get_type_string(get_creature_type_from_code(str)); } - public static List printEntitiesByType(String creature_type_code, World worldIn) //Class entityType) + public static List printEntitiesByType(EntityCategory type, World worldIn) //Class entityType) { - EntityCategory typ = get_creature_type_from_code(creature_type_code); + CarpetSettings.LOG.error("\n\n\nprinting spawnlist\n\n\n"); List lst = new ArrayList<>(); - if (typ == null) - { - lst.add(Messenger.c(String.format("r Incorrect creature type: %s",creature_type_code))); - return lst; - } - Class cls = typ.getDeclaringClass();// getBaseClass();// getCreatureClass(); - lst.add( Messenger.s(String.format("Loaded entities for %s class:", get_type_string(typ)))); + Class cls = type.getDeclaringClass();// getBaseClass();// getCreatureClass(); + lst.add( Messenger.s(String.format("Loaded entities for %s class:", get_type_string(type)))); lst.add(Messenger.s(" ")); - //for (Entity entity : ((ServerWorld)worldIn).getEntities(...)) - //{ - // if ((!(entity instanceof LivingEntity) || !((LivingEntity)entity).isNoDespawnRequired()) && cls.isAssignableFrom(entity.getClass())) - // { - // lst.add(Messenger.c("w - ", - // Messenger.tp("w", entity.posX, entity.posY, entity.posZ),"w : "+EntityType.getId(entity.getType()))); - // } - //} + for (Entity entity : ((ServerWorld)worldIn).getEntities(null, (e) -> e.getType().getCategory()==type)) + { + if (!(entity instanceof MobEntity) || !((MobEntity)entity).isPersistent()) + { + lst.add(Messenger.c("w - ", + Messenger.tp("w", entity.x, entity.y, entity.z),"w : "+EntityType.getId(entity.getType()))); + } + } if (lst.size()==1) { lst.add(Messenger.s(" - Empty.")); @@ -312,35 +296,35 @@ public class SpawnReporter } public static void reset_spawn_stats(boolean full) { + spawn_stats.clear(); spawned_mobs.clear(); for (EntityCategory enumcreaturetype : EntityCategory.values()) { - String type_code = String.format("%s", enumcreaturetype); if (full) { - spawn_tries.put(type_code, 1); + spawn_tries.put(enumcreaturetype, 1); } - for (String suffix: new String[] {""," (N)"," (E)"}) + for (DimensionType dim : DimensionType.getAll()) { - String code = type_code+suffix; - overall_spawn_ticks.put(code, 0L); - spawn_attempts.put(code, 0L); - spawn_ticks_full.put(code, 0L); - spawn_ticks_fail.put(code, 0L); - spawn_ticks_succ.put(code, 0L); - spawn_ticks_spawns.put(code, 0L); - spawn_cap_count.put(code, 0L); + Pair key = Pair.of(dim, enumcreaturetype); + overall_spawn_ticks.put(key, 0L); + spawn_attempts.put(key, 0L); + spawn_ticks_full.put(key, 0L); + spawn_ticks_fail.put(key, 0L); + spawn_ticks_succ.put(key, 0L); + spawn_ticks_spawns.put(key, 0L); + spawn_cap_count.put(key, 0L); + spawn_stats.put(key, new Object2LongOpenHashMap<>()); + spawned_mobs.put(key, new EvictingQueue<>()); } - - spawn_stats.put(type_code, new HashMap<>()); - spawned_mobs.put(type_code, new EvictingQueue<>()); } track_spawns = 0L; } public static List tracking_report(World worldIn) { + List report = new ArrayList<>(); if (track_spawns == 0L) { @@ -359,17 +343,17 @@ public class SpawnReporter report.add(Messenger.s(String.format("%sSpawn statistics %s: for %.1f min", simulated, location, (duration/72000.0)*60))); for (EntityCategory enumcreaturetype : EntityCategory.values()) { - String type_code = String.format("%s", enumcreaturetype); + //String type_code = String.format("%s", enumcreaturetype); boolean there_are_mobs_to_list = false; - for (String world_code: new String[] {"", " (N)", " (E)"}) + for (DimensionType dim: DimensionType.getAll()) //String world_code: new String[] {"", " (N)", " (E)"}) { - String code = type_code+world_code; + Pair code = Pair.of(dim, enumcreaturetype); if (spawn_ticks_spawns.get(code) > 0L) { there_are_mobs_to_list = true; double hours = overall_spawn_ticks.get(code)/72000.0; report.add(Messenger.s(String.format(" > %s (%.1f min), %.1f m/t, {%.1f%%F / %.1f%%- / %.1f%%+}; %.2f s/att", - code, + code.getRight()+((code.getLeft()==DimensionType.OVERWORLD)?"":( (code.getLeft()==DimensionType.THE_NETHER)?"(N)":"(E)" )), 60*hours, (1.0D*spawn_cap_count.get(code))/ spawn_attempts.get(code), (100.0D*spawn_ticks_full.get(code))/ spawn_attempts.get(code), @@ -377,16 +361,13 @@ public class SpawnReporter (100.0D*spawn_ticks_succ.get(code))/ spawn_attempts.get(code), (1.0D*spawn_ticks_spawns.get(code))/(spawn_ticks_fail.get(code)+spawn_ticks_succ.get(code)) ))); - } - } - if (there_are_mobs_to_list) - { - for (String creature_name : spawn_stats.get(type_code).keySet()) - { - report.add(Messenger.s(String.format(" - %s: %d spawns, %d per hour", - creature_name, - spawn_stats.get(type_code).get(creature_name), - (72000 * spawn_stats.get(type_code).get(creature_name)/duration )))); + for (EntityType type: spawn_stats.get(code).keySet()) + { + report.add(Messenger.s(String.format(" - %s: %d spawns, %d per hour", + Registry.ENTITY_TYPE.getId(type).toString().replaceFirst("minecraft:",""), + spawn_stats.get(code).getLong(type), + (72000 * spawn_stats.get(code).getLong(type)/duration )))); + } } } } diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json index 1faa4908..661a9146 100644 --- a/src/main/resources/carpet.mixins.json +++ b/src/main/resources/carpet.mixins.json @@ -5,6 +5,7 @@ "mixins": [ "CommandManagerMixin", + "FillCommandMixin", "CloneCommandMixin", "SetBlockCommandMixin", @@ -28,7 +29,10 @@ "ExperienceOrbEntityMixin", "PlayerActionC2SPacketMixin", "ServerPlayerEntityMixin", + "ServerChunkManagerMixin", + "SpawnHelperMixin", + "HopperBlockEntityMixin", "ContainerMixin", "ClientConnectionMixin", @@ -37,6 +41,7 @@ "ExplosionMixin" ], "client": [ + "DebugHudMixin", "MinecraftClientMixin", "IntegratedServerMixin", "InGameHudMixin",