diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/network/protocol/game/SWorldBorderPacketMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/network/protocol/game/SWorldBorderPacketMixin.java index 21fa4d0b..2c880be8 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/network/protocol/game/SWorldBorderPacketMixin.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/network/protocol/game/SWorldBorderPacketMixin.java @@ -21,7 +21,8 @@ public class SWorldBorderPacketMixin { @Inject(method = "(Lnet/minecraft/world/level/border/WorldBorder;)V", at = @At("RETURN")) private void arclight$nether(WorldBorder border, CallbackInfo ci) { - this.newCenterX = border.getCenterX() * (((WorldBorderBridge) border).bridge$getWorld().dimensionType().coordinateScale()); - this.newCenterZ = border.getCenterZ() * (((WorldBorderBridge) border).bridge$getWorld().dimensionType().coordinateScale()); + var level = ((WorldBorderBridge) border).bridge$getWorld(); + this.newCenterX = border.getCenterX() * (level != null ? level.dimensionType().coordinateScale() : 1.0); + this.newCenterZ = border.getCenterZ() * (level != null ? level.dimensionType().coordinateScale() : 1.0); } } diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/entity/item/FallingBlockEntityMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/entity/item/FallingBlockEntityMixin.java index d6f1560c..4bd92cc2 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/entity/item/FallingBlockEntityMixin.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/entity/item/FallingBlockEntityMixin.java @@ -1,5 +1,6 @@ package io.izzel.arclight.common.mixin.core.world.entity.item; +import io.izzel.arclight.common.bridge.core.world.WorldBridge; import io.izzel.arclight.common.mixin.core.world.entity.EntityMixin; import net.minecraft.core.BlockPos; import net.minecraft.world.damagesource.DamageSource; @@ -8,6 +9,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import org.bukkit.craftbukkit.v.event.CraftEventFactory; +import org.bukkit.event.entity.CreatureSpawnEvent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; @@ -19,7 +21,10 @@ import org.spongepowered.asm.mixin.injection.callback.LocalCapture; @Mixin(FallingBlockEntity.class) public abstract class FallingBlockEntityMixin extends EntityMixin { + // @formatter:off @Shadow private BlockState blockState; + @Shadow public static FallingBlockEntity fall(Level p_201972_, BlockPos p_201973_, BlockState p_201974_) { return null; } + // @formatter:on @Inject(method = "tick", cancellable = true, locals = LocalCapture.CAPTURE_FAILHARD, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;I)Z")) private void arclight$entityChangeBlock(CallbackInfo ci, Block block, BlockPos pos) { @@ -44,4 +49,9 @@ public abstract class FallingBlockEntityMixin extends EntityMixin { cir.setReturnValue(entity); } } + + private static FallingBlockEntity fall(Level level, BlockPos pos, BlockState state, CreatureSpawnEvent.SpawnReason spawnReason) { + ((WorldBridge) level).bridge$pushAddEntityReason(spawnReason); + return fall(level, pos, state); + } } diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/entity/monster/ZombieMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/entity/monster/ZombieMixin.java index 591c98fb..3b33442a 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/entity/monster/ZombieMixin.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/entity/monster/ZombieMixin.java @@ -5,7 +5,9 @@ import io.izzel.arclight.common.bridge.core.entity.MobEntityBridge; import io.izzel.arclight.common.bridge.core.world.WorldBridge; import io.izzel.arclight.common.mixin.core.world.entity.PathfinderMobMixin; import io.izzel.arclight.mixin.Eject; +import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.DifficultyInstance; import net.minecraft.world.damagesource.DamageSource; @@ -15,6 +17,7 @@ import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.MobSpawnType; import net.minecraft.world.entity.SpawnGroupData; +import net.minecraft.world.entity.monster.ZombieVillager; import net.minecraft.world.entity.npc.Villager; import net.minecraft.world.level.ServerLevelAccessor; import net.minecraftforge.event.entity.living.ZombieEvent; @@ -80,4 +83,23 @@ public abstract class ZombieMixin extends PathfinderMobMixin { private void arclight$mount(ServerLevelAccessor worldIn, DifficultyInstance difficultyIn, MobSpawnType reason, SpawnGroupData spawnDataIn, CompoundTag dataTag, CallbackInfoReturnable cir) { ((WorldBridge) worldIn.getLevel()).bridge$pushAddEntityReason(CreatureSpawnEvent.SpawnReason.MOUNT); } + + private static ZombieVillager zombifyVillager(ServerLevel level, Villager villager, BlockPos blockPosition, boolean silent, CreatureSpawnEvent.SpawnReason spawnReason) { + ((WorldBridge) villager.level).bridge$pushAddEntityReason(spawnReason); + ((MobEntityBridge) villager).bridge$pushTransformReason(EntityTransformEvent.TransformReason.INFECTION); + ZombieVillager zombieVillager = villager.convertTo(EntityType.ZOMBIE_VILLAGER, false); + if (zombieVillager != null) { + zombieVillager.finalizeSpawn(level, level.getCurrentDifficultyAt(zombieVillager.blockPosition()), MobSpawnType.CONVERSION, new net.minecraft.world.entity.monster.Zombie.ZombieGroupData(false, true), null); + zombieVillager.setVillagerData(villager.getVillagerData()); + zombieVillager.setGossips(villager.getGossips().store(NbtOps.INSTANCE).getValue()); + zombieVillager.setTradeOffers(villager.getOffers().createTag()); + zombieVillager.setVillagerXp(villager.getVillagerXp()); + net.minecraftforge.event.ForgeEventFactory.onLivingConvert(villager, zombieVillager); + if (!silent) { + level.levelEvent(null, 1026, blockPosition, 0); + } + } + return zombieVillager; + } } + diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/entity/player/ServerPlayerMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/entity/player/ServerPlayerMixin.java index 99284e91..bc93149e 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/entity/player/ServerPlayerMixin.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/entity/player/ServerPlayerMixin.java @@ -80,12 +80,12 @@ import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.common.util.ITeleporter; import net.minecraftforge.event.ForgeEventFactory; import net.minecraftforge.server.ServerLifecycleHooks; -import org.slf4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.WeatherType; import org.bukkit.craftbukkit.v.CraftServer; import org.bukkit.craftbukkit.v.CraftWorld; +import org.bukkit.craftbukkit.v.CraftWorldBorder; import org.bukkit.craftbukkit.v.block.CraftBlock; import org.bukkit.craftbukkit.v.entity.CraftPlayer; import org.bukkit.craftbukkit.v.event.CraftEventFactory; @@ -102,6 +102,7 @@ import org.bukkit.event.player.PlayerLocaleChangeEvent; import org.bukkit.event.player.PlayerPortalEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.MainHand; +import org.slf4j.Logger; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; @@ -304,6 +305,9 @@ public abstract class ServerPlayerMixin extends PlayerMixin implements ServerPla CraftEventFactory.callPlayerLevelChangeEvent(this.getBukkitEntity(), this.oldLevel, this.experienceLevel); this.oldLevel = this.experienceLevel; } + if (this.getBukkitEntity().hasClientWorldBorder()) { + ((CraftWorldBorder) this.getBukkitEntity().getWorldBorder()).getHandle().tick(); + } } /** diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/food/FoodDataMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/food/FoodDataMixin.java index 0aa4f98d..ae13e84b 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/food/FoodDataMixin.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/world/food/FoodDataMixin.java @@ -49,8 +49,9 @@ public abstract class FoodDataMixin implements FoodStatsBridge { this.entityhuman = playerEntity; } - @Redirect(method = "eat(Lnet/minecraft/world/item/Item;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/entity/LivingEntity;)V", at = @At(value = "INVOKE", remap = false, target = "Lnet/minecraft/world/food/FoodData;eat(IF)V")) - public void arclight$foodLevelChange(FoodData foodStats, int foodLevelIn, float foodSaturationModifier, Item maybeFood, ItemStack stack, @Nullable LivingEntity entity) { + @Redirect(method = "eat(Lnet/minecraft/world/item/Item;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/entity/LivingEntity;)V", remap = false, + at = @At(value = "INVOKE", remap = true, target = "Lnet/minecraft/world/food/FoodData;eat(IF)V")) + private void arclight$foodLevelChange(FoodData foodStats, int foodLevelIn, float foodSaturationModifier, Item maybeFood, ItemStack stack, @Nullable LivingEntity entity) { var player = this.entityhuman != null ? this.entityhuman : (entity instanceof Player p ? p : null); if (player == null) { foodStats.eat(foodLevelIn, foodSaturationModifier); diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/optimization/general/ResourceKeyMixin_Optimize.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/optimization/general/ResourceKeyMixin_Optimize.java new file mode 100644 index 00000000..0d373ac6 --- /dev/null +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/optimization/general/ResourceKeyMixin_Optimize.java @@ -0,0 +1,24 @@ +package io.izzel.arclight.common.mixin.optimization.general; + +import net.minecraft.resources.ResourceKey; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Mixin(ResourceKey.class) +public class ResourceKeyMixin_Optimize { + + @Redirect(method = "", at = @At(value = "INVOKE", remap = false, target = "Ljava/util/Collections;synchronizedMap(Ljava/util/Map;)Ljava/util/Map;")) + private static Map arclight$useHashMap(Map m) { + return new ConcurrentHashMap<>(); + } + + @Redirect(method = "create(Lnet/minecraft/resources/ResourceLocation;Lnet/minecraft/resources/ResourceLocation;)Lnet/minecraft/resources/ResourceKey;", + at = @At(value = "INVOKE", remap = false, target = "Ljava/lang/String;intern()Ljava/lang/String;")) + private static String arclight$dropIntern(String instance) { + return instance; + } +} diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/optimization/general/UtilMixin_Optimize.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/optimization/general/UtilMixin_Optimize.java deleted file mode 100644 index 9b5ed054..00000000 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/optimization/general/UtilMixin_Optimize.java +++ /dev/null @@ -1,28 +0,0 @@ -package io.izzel.arclight.common.mixin.optimization.general; - -import net.minecraft.Util; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; - -import java.util.List; -import java.util.concurrent.CompletableFuture; - -@Mixin(Util.class) -public class UtilMixin_Optimize { - - /** - * @author IzzelAliz - * @reason original method allocates tons of garbage - */ - @Overwrite - public static CompletableFuture> sequence(List> futures) { - if (futures.isEmpty()) { - return CompletableFuture.completedFuture(List.of()); - } else if (futures.size() == 1) { - return futures.get(0).thenApply(List::of); - } else { - return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])) - .thenApply(it -> futures.stream().map(CompletableFuture::join).toList()); - } - } -} diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mod/ArclightMixinPlugin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mod/ArclightMixinPlugin.java index 59776e2b..cafb0bff 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mod/ArclightMixinPlugin.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mod/ArclightMixinPlugin.java @@ -89,6 +89,20 @@ public class ArclightMixinPlugin implements IMixinConfigPlugin { new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "reload", "(Lnet/minecraft/server/MinecraftServer;)V", null, null) ) )) + .put("net.minecraft.world.entity.monster.Zombie", + Map.entry( + List.of(), + List.of( + new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "zombifyVillager", "(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/npc/Villager;Lnet/minecraft/core/BlockPos;ZLorg/bukkit/event/entity/CreatureSpawnEvent$SpawnReason;)Lnet/minecraft/world/entity/monster/ZombieVillager;", null, null) + ) + )) + .put("net.minecraft.world.entity.item.FallingBlockEntity", + Map.entry( + List.of(), + List.of( + new MethodNode(Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC, "fall", "(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;Lorg/bukkit/event/entity/CreatureSpawnEvent$SpawnReason;)Lnet/minecraft/world/entity/item/FallingBlockEntity;", null, null) + ) + )) .build(); // damn spigot diff --git a/arclight-common/src/main/resources/mixins.arclight.impl.forge.optimization.json b/arclight-common/src/main/resources/mixins.arclight.impl.forge.optimization.json index 012d7881..9bc01c77 100644 --- a/arclight-common/src/main/resources/mixins.arclight.impl.forge.optimization.json +++ b/arclight-common/src/main/resources/mixins.arclight.impl.forge.optimization.json @@ -9,7 +9,7 @@ "EntityDataManagerMixin_Optimize", "GoalMixin", "MobMixin_Optimization", - "UtilMixin_Optimize", + "ResourceKeyMixin_Optimize", "VoxelShapesMixin", "activationrange.ActivationRangeMixin", "activationrange.EntityMixin_ActivationRange",