From b257e6f984bb6aab2916cb31ea52c410c3b2ffc3 Mon Sep 17 00:00:00 2001 From: gnembon Date: Wed, 22 May 2019 15:21:07 -0300 Subject: [PATCH] other features --- src/main/java/carpet/CarpetSettings.java | 9 ++- .../carpet/fakes/CoralFeatureInterface.java | 12 +++ .../java/carpet/fakes/WorldInterface.java | 11 +++ .../logging/logHelpers/TNTLogHelper.java | 4 +- .../java/carpet/mixins/CarpetBlockMixin.java | 28 +++++++ .../java/carpet/mixins/CoralBlockMixin.java | 81 +++++++++++++++++++ .../java/carpet/mixins/CoralFeatureMixin.java | 25 ++++++ .../java/carpet/mixins/KelpFeatureMixin.java | 24 ++++++ .../LivingEntity_maxCollisionsMixin.java | 64 +++++++++++++++ .../mixins/PistonHandler_pushLimitMixin.java | 18 +++++ .../PoweredRailBlock_powerLimitMixin.java | 18 +++++ .../carpet/mixins/PrimedTntEntityMixin.java | 26 ++++-- .../carpet/mixins/ProjectileEntityMixin.java | 2 +- .../mixins/ServerChunkManagerMixin.java | 2 + .../ServerWorld_onePlayerSleepingMixin.java | 54 +++++++++++++ .../java/carpet/mixins/SpawnHelperMixin.java | 64 ++++++++++++++- .../carpet/mixins/SummonCommandMixin.java | 54 +++++++++++++ .../java/carpet/mixins/World_tickMixin.java | 13 ++- src/main/resources/carpet.mixins.json | 10 ++- 19 files changed, 501 insertions(+), 18 deletions(-) create mode 100644 src/main/java/carpet/fakes/CoralFeatureInterface.java create mode 100644 src/main/java/carpet/fakes/WorldInterface.java create mode 100644 src/main/java/carpet/mixins/CarpetBlockMixin.java create mode 100644 src/main/java/carpet/mixins/CoralBlockMixin.java create mode 100644 src/main/java/carpet/mixins/CoralFeatureMixin.java create mode 100644 src/main/java/carpet/mixins/KelpFeatureMixin.java create mode 100644 src/main/java/carpet/mixins/LivingEntity_maxCollisionsMixin.java create mode 100644 src/main/java/carpet/mixins/PistonHandler_pushLimitMixin.java create mode 100644 src/main/java/carpet/mixins/PoweredRailBlock_powerLimitMixin.java create mode 100644 src/main/java/carpet/mixins/ServerWorld_onePlayerSleepingMixin.java create mode 100644 src/main/java/carpet/mixins/SummonCommandMixin.java diff --git a/src/main/java/carpet/CarpetSettings.java b/src/main/java/carpet/CarpetSettings.java index 001eee83..b7878dda 100644 --- a/src/main/java/carpet/CarpetSettings.java +++ b/src/main/java/carpet/CarpetSettings.java @@ -55,6 +55,7 @@ public class CarpetSettings //those don't have to mimic defaults - defaults will be ' //static store public static int n_pushLimit = 12; + public static int n_maxEntityCollisions = 0; public static boolean b_hopperCounters = false; public static boolean b_shulkerSpawningInEndCities = false; public static boolean b_fastRedstoneDust = false; @@ -64,6 +65,7 @@ public class CarpetSettings public static boolean b_huskSpawningInTemples = false; public static boolean b_stackableShulkerBoxes = false; public static boolean b_fillUpdates = true; + public static boolean b_lagFreeSpawning = false; private static CarpetSettingEntry rule(String s1, String s2, String s3) { return CarpetSettingEntry.create(s1,s2,s3);} @@ -143,16 +145,14 @@ public class CarpetSettings rule("fillLimit", "creative","Customizable fill/clone volume limit") .choices("32768","32768 250000 1000000").setNotStrict(), rule("maxEntityCollisions", "optimizations", "Customizable maximal entity collision limits, 0 for no limits") - .choices("0","0 1 20").setNotStrict(), + .choices("0","0 1 20").setNotStrict().numAccelerate(), //???rule("pistonGhostBlocksFix", "fix", "Fix for piston ghost blocks") // .extraInfo("true(serverOnly) option works with all clients, including vanilla", // "clientAndServer option requires compatible carpet clients and messes up flying machines") // .choices("false","false true clientAndServer"), //???rule("waterFlow", "optimizations", "fixes water flowing issues") // .choices("vanilla","vanilla optimized correct"), - rule("sleepingThreshold", "experimental", "The percentage of required sleeping players to skip the night") - .extraInfo("Use values from 0 to 100, 100 for default (all players needed)") - .choices("100","0 10 50 100").setNotStrict(), + rule("onePlayerSleeping", "survival", "One player is required on the server to cause night to pass"), rule("customMOTD", "creative","Sets a different motd message on client trying to connect to the server") .extraInfo("use '_' to use the startup setting from server.properties") .choices("_","_").setNotStrict().validate((s) -> @@ -196,6 +196,7 @@ public class CarpetSettings rule("placementRotationFix", "fix", "fixes block placement rotation issue when player rotates quickly while placing blocks"), rule("leadFix", "fix", "Fixes leads breaking/becoming invisible in unloaded chunks") .extraInfo("You may still get visibly broken leash links on the client side, but server side the link is still there."), + rule("lagFreeSpawning", "optimizations", "Spawning requires much less CPU and Memory").boolAccelerate() }; for (CarpetSettingEntry rule: RuleList) { diff --git a/src/main/java/carpet/fakes/CoralFeatureInterface.java b/src/main/java/carpet/fakes/CoralFeatureInterface.java new file mode 100644 index 00000000..a5ee25e2 --- /dev/null +++ b/src/main/java/carpet/fakes/CoralFeatureInterface.java @@ -0,0 +1,12 @@ +package carpet.fakes; + +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import java.util.Random; + +public interface CoralFeatureInterface +{ + boolean growSpecific(World worldIn, Random random, BlockPos pos, BlockState blockUnder); +} diff --git a/src/main/java/carpet/fakes/WorldInterface.java b/src/main/java/carpet/fakes/WorldInterface.java new file mode 100644 index 00000000..0ba86651 --- /dev/null +++ b/src/main/java/carpet/fakes/WorldInterface.java @@ -0,0 +1,11 @@ +package carpet.fakes; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; + +import java.util.Map; + +public interface WorldInterface +{ + Map getPrecookedMobs(); +} diff --git a/src/main/java/carpet/logging/logHelpers/TNTLogHelper.java b/src/main/java/carpet/logging/logHelpers/TNTLogHelper.java index d97b8cb3..c9ca2010 100644 --- a/src/main/java/carpet/logging/logHelpers/TNTLogHelper.java +++ b/src/main/java/carpet/logging/logHelpers/TNTLogHelper.java @@ -7,8 +7,9 @@ import net.minecraft.util.math.Vec3d; public class TNTLogHelper { + public boolean initialized; private double primedX, primedY, primedZ; - Vec3d primedAngle; + private Vec3d primedAngle; /** * Runs when the TNT is primed. Expects the position and motion angle of the TNT. */ @@ -18,6 +19,7 @@ public class TNTLogHelper primedY = y; primedZ = z; primedAngle = motion; + initialized = true; } /** * Runs when the TNT explodes. Expects the position of the TNT. diff --git a/src/main/java/carpet/mixins/CarpetBlockMixin.java b/src/main/java/carpet/mixins/CarpetBlockMixin.java new file mode 100644 index 00000000..f1d9f1f8 --- /dev/null +++ b/src/main/java/carpet/mixins/CarpetBlockMixin.java @@ -0,0 +1,28 @@ +package carpet.mixins; + +import carpet.utils.WoolTool; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.CarpetBlock; +import net.minecraft.item.ItemPlacementContext; +import org.spongepowered.asm.mixin.Mixin; + +@Mixin(CarpetBlock.class) +public abstract class CarpetBlockMixin extends Block +{ + + public CarpetBlockMixin(Settings block$Settings_1) + { + super(block$Settings_1); + } + + public BlockState getPlacementState(ItemPlacementContext context) + { + BlockState state = super.getPlacementState(context); + if (context.getPlayer() != null && !context.getWorld().isClient) + { + WoolTool.carpetPlacedAction(((CarpetBlock)(Object)this).getColor(), context.getPlayer(), context.getBlockPos(), context.getWorld()); + } + return state; + } +} diff --git a/src/main/java/carpet/mixins/CoralBlockMixin.java b/src/main/java/carpet/mixins/CoralBlockMixin.java new file mode 100644 index 00000000..af68f352 --- /dev/null +++ b/src/main/java/carpet/mixins/CoralBlockMixin.java @@ -0,0 +1,81 @@ +package carpet.mixins; + +import carpet.CarpetSettings; +import carpet.fakes.CoralFeatureInterface; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.CoralBlock; +import net.minecraft.block.CoralParentBlock; +import net.minecraft.block.Fertilizable; +import net.minecraft.block.MaterialColor; +import net.minecraft.tag.BlockTags; +import net.minecraft.tag.FluidTags; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.CoralClawFeature; +import net.minecraft.world.gen.feature.CoralFeature; +import net.minecraft.world.gen.feature.CoralMushroomFeature; +import net.minecraft.world.gen.feature.CoralTreeFeature; +import net.minecraft.world.gen.feature.DefaultFeatureConfig; +import org.spongepowered.asm.mixin.Interface; +import org.spongepowered.asm.mixin.Mixin; + +import java.util.Random; + +@Mixin(CoralBlock.class) +@Interface(iface = Fertilizable.class, prefix = "fert$") +public abstract class CoralBlockMixin implements Fertilizable +{ + public boolean isFertilizable(BlockView var1, BlockPos var2, BlockState var3, boolean var4) + { + return CarpetSettings.getBool("renewableCoral") && var3.get(CoralParentBlock.WATERLOGGED) && var1.getFluidState(var2.up()).matches(FluidTags.WATER); + } + + public boolean canGrow(World var1, Random var2, BlockPos var3, BlockState var4) + { + return (double)var1.random.nextFloat() < 0.15D; + } + + public void grow(World worldIn, Random random, BlockPos pos, BlockState blockUnder) + { + + CoralFeature coral; + int variant = random.nextInt(3); + if (variant == 0) + coral = new CoralClawFeature(DefaultFeatureConfig::deserialize); + else if (variant == 1) + coral = new CoralTreeFeature(DefaultFeatureConfig::deserialize); + else + coral = new CoralMushroomFeature(DefaultFeatureConfig::deserialize); + + MaterialColor color = blockUnder.getTopMaterialColor(worldIn, pos); + BlockState proper_block = blockUnder; + for (Block block: BlockTags.CORAL_BLOCKS.values()) + { + proper_block = block.getDefaultState(); + if (proper_block.getTopMaterialColor(worldIn,pos) == color) + { + break; + } + } + worldIn.setBlockState(pos, Blocks.WATER.getDefaultState(), 4); + + if (!((CoralFeatureInterface)coral).growSpecific(worldIn, random, pos, proper_block)) + { + worldIn.setBlockState(pos, blockUnder, 3); + } + else + { + if (worldIn.random.nextInt(10)==0) + { + BlockPos randomPos = pos.add(worldIn.random.nextInt(16)-8,worldIn.random.nextInt(8),worldIn.random.nextInt(16)-8 ); + if (BlockTags.CORAL_BLOCKS.contains(worldIn.getBlockState(randomPos).getBlock())) + { + worldIn.setBlockState(randomPos, Blocks.WET_SPONGE.getDefaultState(), 3); + } + } + } + } +} diff --git a/src/main/java/carpet/mixins/CoralFeatureMixin.java b/src/main/java/carpet/mixins/CoralFeatureMixin.java new file mode 100644 index 00000000..115aff1d --- /dev/null +++ b/src/main/java/carpet/mixins/CoralFeatureMixin.java @@ -0,0 +1,25 @@ +package carpet.mixins; + +import carpet.fakes.CoralFeatureInterface; +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.IWorld; +import net.minecraft.world.World; +import net.minecraft.world.gen.feature.CoralFeature; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import java.util.Random; + +@Mixin(CoralFeature.class) +public abstract class CoralFeatureMixin implements CoralFeatureInterface +{ + + @Shadow protected abstract boolean spawnCoral(IWorld var1, Random var2, BlockPos var3, BlockState var4); + + @Override + public boolean growSpecific(World worldIn, Random random, BlockPos pos, BlockState blockUnder) + { + return spawnCoral(worldIn, random, pos, blockUnder); + } +} diff --git a/src/main/java/carpet/mixins/KelpFeatureMixin.java b/src/main/java/carpet/mixins/KelpFeatureMixin.java new file mode 100644 index 00000000..5e317feb --- /dev/null +++ b/src/main/java/carpet/mixins/KelpFeatureMixin.java @@ -0,0 +1,24 @@ +package carpet.mixins; + +import carpet.CarpetSettings; +import net.minecraft.world.gen.feature.KelpFeature; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.Random; + +@Mixin(KelpFeature.class) +public class KelpFeatureMixin +{ + @Redirect(method = "method_13460", at = @At(value = "INVOKE", target = "Ljava/util/Random;nextInt(I)I")) + private int getRandom(Random random, int bound) + { + if (bound==10) + return random.nextInt(bound); + int limit = CarpetSettings.getInt("kelpGenerationGrowLimit"); + if (limit == 0) + return random.nextInt(bound); + return 25-limit+random.nextInt(Math.min(23,limit+1)); + } +} diff --git a/src/main/java/carpet/mixins/LivingEntity_maxCollisionsMixin.java b/src/main/java/carpet/mixins/LivingEntity_maxCollisionsMixin.java new file mode 100644 index 00000000..38f8831c --- /dev/null +++ b/src/main/java/carpet/mixins/LivingEntity_maxCollisionsMixin.java @@ -0,0 +1,64 @@ +package carpet.mixins; + +import carpet.CarpetSettings; +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.predicate.entity.EntityPredicates; +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.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; + +@Mixin(LivingEntity.class) +public abstract class LivingEntity_maxCollisionsMixin extends Entity +{ + + public LivingEntity_maxCollisionsMixin(EntityType entityType_1, World world_1) + { + super(entityType_1, world_1); + } + + @Shadow protected abstract void pushAway(Entity entity_1); + + @Inject(method = "tickPushing", cancellable = true, at = @At("HEAD")) + private void tickPushingReplacement(CallbackInfo ci) + { + List list_1 = this.world.getEntities((Entity)this, this.getBoundingBox(), EntityPredicates.canBePushedBy(this)); + if (!list_1.isEmpty()) { + int int_1 = this.world.getGameRules().getInteger("maxEntityCramming"); + int int_2; + if (int_1 > 0 && list_1.size() > int_1 - 1 && this.random.nextInt(4) == 0) { + int_2 = 0; + + for(int int_3 = 0; int_3 < list_1.size(); ++int_3) { + if (!((Entity)list_1.get(int_3)).hasVehicle()) { + ++int_2; + } + } + + if (int_2 > int_1 - 1) { + this.damage(DamageSource.CRAMMING, 6.0F); + } + } + + int limit = list_1.size(); + if (CarpetSettings.n_maxEntityCollisions > 0) + limit = Math.min(limit, CarpetSettings.n_maxEntityCollisions); + + for(int_2 = 0; int_2 < limit; ++int_2) { + Entity entity_1 = (Entity)list_1.get(int_2); + this.pushAway(entity_1); + } + } + ci.cancel(); + } + + +} diff --git a/src/main/java/carpet/mixins/PistonHandler_pushLimitMixin.java b/src/main/java/carpet/mixins/PistonHandler_pushLimitMixin.java new file mode 100644 index 00000000..04a9497f --- /dev/null +++ b/src/main/java/carpet/mixins/PistonHandler_pushLimitMixin.java @@ -0,0 +1,18 @@ +package carpet.mixins; + +import carpet.CarpetSettings; +import net.minecraft.block.piston.PistonHandler; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +@Mixin(PistonHandler.class) +public class PistonHandler_pushLimitMixin +{ + @ModifyConstant(method = "tryMove", constant = @Constant(intValue = 12), expect = 3) + private int pushLimit(int original) + { + return CarpetSettings.n_pushLimit; + } +} diff --git a/src/main/java/carpet/mixins/PoweredRailBlock_powerLimitMixin.java b/src/main/java/carpet/mixins/PoweredRailBlock_powerLimitMixin.java new file mode 100644 index 00000000..660ea173 --- /dev/null +++ b/src/main/java/carpet/mixins/PoweredRailBlock_powerLimitMixin.java @@ -0,0 +1,18 @@ +package carpet.mixins; + +import carpet.CarpetSettings; +import net.minecraft.block.PoweredRailBlock; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +@Mixin(PoweredRailBlock.class) +public class PoweredRailBlock_powerLimitMixin +{ + @ModifyConstant(method = "isPoweredByOtherRails(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;ZI)Z", + constant = @Constant(intValue = 8)) + private int powerLimit(int original) + { + return CarpetSettings.railPowerLimitAdjusted; + } +} diff --git a/src/main/java/carpet/mixins/PrimedTntEntityMixin.java b/src/main/java/carpet/mixins/PrimedTntEntityMixin.java index 196588ed..648f31ce 100644 --- a/src/main/java/carpet/mixins/PrimedTntEntityMixin.java +++ b/src/main/java/carpet/mixins/PrimedTntEntityMixin.java @@ -5,6 +5,7 @@ import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.PrimedTntEntity; +import net.minecraft.nbt.CompoundTag; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import org.spongepowered.asm.mixin.Mixin; @@ -24,6 +25,25 @@ public abstract class PrimedTntEntityMixin extends Entity super(entityType_1, world_1); } + @Inject(method = "(Lnet/minecraft/entity/EntityType;Lnet/minecraft/world/World;)V", at = @At("RETURN")) + private void initTNTLoggerPrime(EntityType entityType_1, World world_1, CallbackInfo ci) + { + if (LoggerRegistry.__tnt && !world_1.isClient) + { + logHelper = new TNTLogHelper(); + } + } + + @Inject(method = "tick", at = @At("HEAD")) + private void initTracker(CallbackInfo ci) + { + if (LoggerRegistry.__tnt && logHelper != null && !logHelper.initialized) + { + logHelper.onPrimed(x, y, z, getVelocity()); + } + } + + @Inject(method = "(Lnet/minecraft/world/World;DDDLnet/minecraft/entity/LivingEntity;)V", at = @At(value = "RETURN")) private void initTNTLogger(World world_1, double double_1, double double_2, double double_3, @@ -31,12 +51,6 @@ public abstract class PrimedTntEntityMixin extends Entity { if(CarpetSettings.getBool("tntPrimerMomentumRemoved")) this.setVelocity(new Vec3d(0.0, 0.20000000298023224D, 0.0)); - if (LoggerRegistry.__tnt) - { - logHelper = new TNTLogHelper(); - - logHelper.onPrimed(double_1, double_2, double_3, getVelocity()); - } } @Inject(method = "explode", at = @At(value = "HEAD")) diff --git a/src/main/java/carpet/mixins/ProjectileEntityMixin.java b/src/main/java/carpet/mixins/ProjectileEntityMixin.java index 5822da46..c96ad156 100644 --- a/src/main/java/carpet/mixins/ProjectileEntityMixin.java +++ b/src/main/java/carpet/mixins/ProjectileEntityMixin.java @@ -25,7 +25,7 @@ public abstract class ProjectileEntityMixin extends Entity logHelper = new TrajectoryLogHelper("projectiles"); } - @Inject(method = "tick", at = @At("RETURN")) + @Inject(method = "tick", at = @At("HEAD")) private void tickCheck(CallbackInfo ci) { if (LoggerRegistry.__projectiles && logHelper != null) diff --git a/src/main/java/carpet/mixins/ServerChunkManagerMixin.java b/src/main/java/carpet/mixins/ServerChunkManagerMixin.java index e96eed92..f922edd0 100644 --- a/src/main/java/carpet/mixins/ServerChunkManagerMixin.java +++ b/src/main/java/carpet/mixins/ServerChunkManagerMixin.java @@ -1,5 +1,6 @@ package carpet.mixins; +import carpet.fakes.WorldInterface; import carpet.utils.SpawnReporter; import it.unimi.dsi.fastutil.objects.Object2IntMap; import net.minecraft.entity.EntityCategory; @@ -56,6 +57,7 @@ public abstract class ServerChunkManagerMixin Object2IntMap object2IntMap_1) { DimensionType dim = this.world.dimension.getType(); + ((WorldInterface)world).getPrecookedMobs().clear(); SpawnReporter.mobCounts.put(dim, (Object2IntMap)object2IntMap_1); SpawnReporter.chunkCounts.put(dim, int_2); diff --git a/src/main/java/carpet/mixins/ServerWorld_onePlayerSleepingMixin.java b/src/main/java/carpet/mixins/ServerWorld_onePlayerSleepingMixin.java new file mode 100644 index 00000000..6406b15f --- /dev/null +++ b/src/main/java/carpet/mixins/ServerWorld_onePlayerSleepingMixin.java @@ -0,0 +1,54 @@ +package carpet.mixins; + +import carpet.CarpetSettings; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +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.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Stream; + +@Mixin(ServerWorld.class) +public class ServerWorld_onePlayerSleepingMixin +{ + @Shadow @Final private List players; + + @Shadow private boolean allPlayersSleeping; + + @Inject(method = "updatePlayersSleeping", cancellable = true, at = @At("HEAD")) + private void updateOnePlayerSleeping(CallbackInfo ci) + { + if(CarpetSettings.getBool("onePlayerSleeping")) + { + allPlayersSleeping = false; + for (ServerPlayerEntity p : players) + if (!p.isSpectator() && p.isSleeping()) + { + allPlayersSleeping = true; + ci.cancel(); + return; + } + ci.cancel(); + } + } + + @Redirect(method = "tick", at = @At( + value = "INVOKE", + target = "Ljava/util/stream/Stream;noneMatch(Ljava/util/function/Predicate;)Z" + )) + private boolean noneMatchSleep(Stream stream, Predicate predicate) + { + if (CarpetSettings.getBool("onePlayerSleeping")) + return stream.anyMatch((p) -> !p.isSpectator() && p.isSleepingLongEnough()); + return stream.noneMatch(predicate); + } + +} diff --git a/src/main/java/carpet/mixins/SpawnHelperMixin.java b/src/main/java/carpet/mixins/SpawnHelperMixin.java index 9f0b264e..d703866d 100644 --- a/src/main/java/carpet/mixins/SpawnHelperMixin.java +++ b/src/main/java/carpet/mixins/SpawnHelperMixin.java @@ -1,24 +1,82 @@ package carpet.mixins; import carpet.CarpetSettings; +import carpet.fakes.WorldInterface; import carpet.utils.SpawnReporter; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; import net.minecraft.entity.mob.MobEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.BoundingBox; +import net.minecraft.util.shape.VoxelShapes; 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; +import java.util.Map; + @Mixin(SpawnHelper.class) -public abstract class SpawnHelperMixin +public class SpawnHelperMixin { + // in World: private static Map precookedMobs= new HashMap<>(); + + @Redirect(method = "spawnEntitiesInChunk", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/world/World;doesNotCollide(Lnet/minecraft/util/math/BoundingBox;)Z" + )) + private static boolean doesNotCollide(World world, BoundingBox bb) + { + //.doesNotCollide is VERY expensive. On the other side - most worlds are not made of trapdoors in + // various configurations, but solid and 'passable' blocks, like air, water grass, etc. + // checking if in the BB of the entity are only passable blocks is very cheap and covers most cases + // in case something more complex happens - we default to full block collision check + if (CarpetSettings.b_lagFreeSpawning) + { + BlockPos.Mutable blockpos = new BlockPos.Mutable(); + for (int x = (int)bb.minX, maxx = (int)Math.ceil(bb.maxX); x < maxx; x++) + for (int z = (int)bb.minZ, maxz = (int)Math.ceil(bb.maxZ); z < maxz; z++) + for (int y = (int)bb.minY, maxy = (int)Math.ceil(bb.maxY); y < maxy; y++) + { + blockpos.set(x, y, z); + if (world.getBlockState(blockpos).getCollisionShape(world, blockpos) != VoxelShapes.empty()) + return world.doesNotCollide(bb); + } + return true; + } + return world.doesNotCollide(bb); + } + + @Redirect(method = "spawnEntitiesInChunk", at = @At( + value = "INVOKE", + target = "Lnet/minecraft/entity/EntityType;create(Lnet/minecraft/world/World;)Lnet/minecraft/entity/Entity;" + )) + private static Entity create(EntityType entityType, World world_1) + { + if (CarpetSettings.b_lagFreeSpawning) + { + Map precookedMobs = ((WorldInterface)world_1).getPrecookedMobs(); + if (precookedMobs.containsKey(entityType)) + //this mob has been 's but not used yet + return precookedMobs.get(entityType); + Entity e = entityType.create(world_1); + precookedMobs.put(entityType, e); + return e; + } + return entityType.create(world_1); + } + @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) + private static boolean spawnEntity(World world, Entity entity_1) { + if (CarpetSettings.b_lagFreeSpawning) + // we used the mob - next time we will create a new one when needed + ((WorldInterface) world).getPrecookedMobs().remove(entity_1.getType()); + if (SpawnReporter.track_spawns > 0L && SpawnReporter.local_spawns != null) { SpawnReporter.registerSpawn( @@ -31,6 +89,4 @@ public abstract class SpawnHelperMixin return world.spawnEntity(entity_1); return false; } - - } diff --git a/src/main/java/carpet/mixins/SummonCommandMixin.java b/src/main/java/carpet/mixins/SummonCommandMixin.java new file mode 100644 index 00000000..6de6530e --- /dev/null +++ b/src/main/java/carpet/mixins/SummonCommandMixin.java @@ -0,0 +1,54 @@ +package carpet.mixins; + +import carpet.CarpetSettings; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LightningEntity; +import net.minecraft.entity.mob.SkeletonHorseEntity; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.TranslatableComponent; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.command.SummonCommand; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.LocalDifficulty; +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; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@Mixin(SummonCommand.class) +public class SummonCommandMixin +{ + @Inject(method = "execute", locals = LocalCapture.CAPTURE_FAILHARD, cancellable = true, at = @At( + value = "INVOKE", + target = "Lnet/minecraft/server/world/ServerWorld;addLightning(Lnet/minecraft/entity/LightningEntity;)V", + shift = At.Shift.BEFORE + )) + private static void addRiders(ServerCommandSource source, Identifier identifier_1, Vec3d vec3d_1, CompoundTag compoundTag_1, boolean arg4, CallbackInfoReturnable cir, CompoundTag compoundTag_2, LightningEntity lightningEntity_1) + { + // [CM] SummonNaturalLightning - if statement around + if (CarpetSettings.getBool("summonNaturalLightning") && !source.getWorld().isClient) + { + ServerWorld world = source.getWorld(); + BlockPos at = new BlockPos(vec3d_1); + LocalDifficulty localDifficulty_1 = source.getWorld().getLocalDifficulty(at); + boolean boolean_2 = world.getGameRules().getBoolean("doMobSpawning") && world.random.nextDouble() < (double)localDifficulty_1.getLocalDifficulty() * 0.01D; + if (boolean_2) { + SkeletonHorseEntity skeletonHorseEntity_1 = (SkeletonHorseEntity) EntityType.SKELETON_HORSE.create(world); + skeletonHorseEntity_1.setTrapped(true); + skeletonHorseEntity_1.setBreedingAge(0); + skeletonHorseEntity_1.setPosition(vec3d_1.x, vec3d_1.y, vec3d_1.z); + world.spawnEntity(skeletonHorseEntity_1); + } + world.addLightning(lightningEntity_1); + source.sendFeedback(new TranslatableComponent("commands.summon.success", new Object[]{lightningEntity_1.getDisplayName()}), true); + cir.setReturnValue(1); + cir.cancel(); + + } + } + +} diff --git a/src/main/java/carpet/mixins/World_tickMixin.java b/src/main/java/carpet/mixins/World_tickMixin.java index c299c293..e2360922 100644 --- a/src/main/java/carpet/mixins/World_tickMixin.java +++ b/src/main/java/carpet/mixins/World_tickMixin.java @@ -1,9 +1,11 @@ package carpet.mixins; +import carpet.fakes.WorldInterface; import carpet.helpers.TickSpeed; import carpet.utils.CarpetProfiler; import net.minecraft.block.entity.BlockEntity; import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.profiler.Profiler; import net.minecraft.world.World; @@ -14,15 +16,24 @@ 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.Iterator; +import java.util.Map; import java.util.function.Consumer; @Mixin(World.class) -public abstract class World_tickMixin +public abstract class World_tickMixin implements WorldInterface { CarpetProfiler.ProfilerToken currentSection; CarpetProfiler.ProfilerToken entitySection; + Map precookedMobs = new HashMap<>(); + + public Map getPrecookedMobs() + { + return precookedMobs; + } + @Inject(method = "tickBlockEntities", at = @At("HEAD")) private void startBlockEntities(CallbackInfo ci) { currentSection = CarpetProfiler.start_section((World) (Object) this, "Tile Entities", CarpetProfiler.TYPE.GENERAL); diff --git a/src/main/resources/carpet.mixins.json b/src/main/resources/carpet.mixins.json index cee3a83d..b84f0517 100644 --- a/src/main/resources/carpet.mixins.json +++ b/src/main/resources/carpet.mixins.json @@ -5,7 +5,6 @@ "mixins": [ "CommandManagerMixin", - "FillCommandMixin", "CloneCommandMixin", "SetBlockCommandMixin", @@ -32,6 +31,15 @@ "PlayerActionC2SPacketMixin", "ServerPlayerEntityMixin", "PlayerManagerMixin", + "CarpetBlockMixin", + "SummonCommandMixin", + "PistonHandler_pushLimitMixin", + "PoweredRailBlock_powerLimitMixin", + "LivingEntity_maxCollisionsMixin", + "ServerWorld_onePlayerSleepingMixin", + "KelpFeatureMixin", + "CoralBlockMixin", + "CoralFeatureMixin", "ServerChunkManagerMixin", "SpawnHelperMixin",