fix performance regressions and fix issues

This commit is contained in:
Taiyou06
2024-08-13 01:20:44 +03:00
parent 36e5c571de
commit dd31ed6b54
9 changed files with 265 additions and 274 deletions

View File

@@ -1,70 +1,70 @@
package net.gensokyoreimagined.nitori.mixin;
import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.entity.EntityTickList;
import org.spongepowered.asm.mixin.Mixin;
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;
import java.util.function.Consumer;
@Mixin(EntityTickList.class)
public class MixinEntityTickList {
@Unique
private Int2ObjectLinkedOpenHashMap<Entity> nitori$entities = new Int2ObjectLinkedOpenHashMap<>();
@Unique
private Int2ObjectLinkedOpenHashMap<Entity> nitori$iteratorPointer = null;
// I've decided I hate Paper's design.
// All of these are effectively Overwrites.
@Unique
private void nitori$ensureActiveIsNotIterated() {
if (nitori$iteratorPointer == nitori$entities) {
// Avoid a ConcurrentModificationException by cloning the map before modifying it.
// Side effect is that it allocates more memory to avoid blocking the main thread, but it's all pointers anyway.
nitori$entities = nitori$entities.clone();
}
}
@Inject(method = "add", at = @At("HEAD"), cancellable = true)
public void add(Entity entity, CallbackInfo ci) {
nitori$ensureActiveIsNotIterated();
nitori$entities.put(entity.getId(), entity);
ci.cancel();
}
@Inject(method = "remove", at = @At("HEAD"), cancellable = true)
public void remove(Entity entity, CallbackInfo ci) {
nitori$ensureActiveIsNotIterated();
nitori$entities.remove(entity.getId());
ci.cancel();
}
@Inject(method = "contains", at = @At("HEAD"), cancellable = true)
public void contains(Entity entity, CallbackInfoReturnable<Boolean> ci) {
ci.setReturnValue(nitori$entities.containsKey(entity.getId()));
ci.cancel();
}
@Inject(method = "forEach", at = @At("HEAD"), cancellable = true)
public void forEach(Consumer<Entity> action, CallbackInfo ci) {
if (nitori$iteratorPointer == nitori$entities) {
nitori$entities = nitori$entities.clone(); // Avoid a ConcurrentModificationException by cloning the map before iterating over it.
}
nitori$iteratorPointer = nitori$entities; // Mark the map as being iterated.
try {
nitori$iteratorPointer.values().forEach(action); // Iterate over the map.
} finally {
nitori$iteratorPointer = null; // Mark the map as no longer being iterated.
}
ci.cancel();
}
}
//import it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap;
//import net.minecraft.world.entity.Entity;
//import net.minecraft.world.level.entity.EntityTickList;
//import org.spongepowered.asm.mixin.Mixin;
//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;
//
//import java.util.function.Consumer;
//
//@Mixin(EntityTickList.class)
//public class MixinEntityTickList {
// @Unique
// private Int2ObjectLinkedOpenHashMap<Entity> nitori$entities = new Int2ObjectLinkedOpenHashMap<>();
// @Unique
// private Int2ObjectLinkedOpenHashMap<Entity> nitori$iteratorPointer = null;
//
// // I've decided I hate Paper's design.
// // All of these are effectively Overwrites.
//
// @Unique
// private void nitori$ensureActiveIsNotIterated() {
// if (nitori$iteratorPointer == nitori$entities) {
// // Avoid a ConcurrentModificationException by cloning the map before modifying it.
// // Side effect is that it allocates more memory to avoid blocking the main thread, but it's all pointers anyway.
// nitori$entities = nitori$entities.clone();
// }
// }
//
// @Inject(method = "add", at = @At("HEAD"), cancellable = true)
// public void add(Entity entity, CallbackInfo ci) {
// nitori$ensureActiveIsNotIterated();
// nitori$entities.put(entity.getId(), entity);
// ci.cancel();
// }
//
// @Inject(method = "remove", at = @At("HEAD"), cancellable = true)
// public void remove(Entity entity, CallbackInfo ci) {
// nitori$ensureActiveIsNotIterated();
// nitori$entities.remove(entity.getId());
// ci.cancel();
// }
//
// @Inject(method = "contains", at = @At("HEAD"), cancellable = true)
// public void contains(Entity entity, CallbackInfoReturnable<Boolean> ci) {
// ci.setReturnValue(nitori$entities.containsKey(entity.getId()));
// ci.cancel();
// }
//
// @Inject(method = "forEach", at = @At("HEAD"), cancellable = true)
// public void forEach(Consumer<Entity> action, CallbackInfo ci) {
// if (nitori$iteratorPointer == nitori$entities) {
// nitori$entities = nitori$entities.clone(); // Avoid a ConcurrentModificationException by cloning the map before iterating over it.
// }
//
// nitori$iteratorPointer = nitori$entities; // Mark the map as being iterated.
//
// try {
// nitori$iteratorPointer.values().forEach(action); // Iterate over the map.
// } finally {
// nitori$iteratorPointer = null; // Mark the map as no longer being iterated.
// }
//
// ci.cancel();
// }
//}

View File

@@ -1,33 +0,0 @@
package net.gensokyoreimagined.nitori.mixin.collections.goals;
import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
import net.minecraft.world.entity.ai.goal.GoalSelector;
import net.minecraft.world.entity.ai.goal.WrappedGoal;
import net.minecraft.util.profiling.ProfilerFiller;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
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.Set;
import java.util.function.Supplier;
@Mixin(GoalSelector.class)
public abstract class GoalSelectorMixin {
@Mutable
@Shadow
@Final
private Set<WrappedGoal> availableGoals;
/**
* Replace the goal set with an optimized collection type which performs better for iteration.
*/
@Inject(method = "<init>", at = @At("RETURN"))
private void reinit(Supplier<ProfilerFiller> supplier, CallbackInfo ci) {
this.availableGoals = new ObjectLinkedOpenHashSet<>(this.availableGoals);
}
}

View File

@@ -0,0 +1,33 @@
package net.gensokyoreimagined.nitori.mixin.removed.collections.goals;
//import it.unimi.dsi.fastutil.objects.ObjectLinkedOpenHashSet;
//import net.minecraft.world.entity.ai.goal.GoalSelector;
//import net.minecraft.world.entity.ai.goal.WrappedGoal;
//import net.minecraft.util.profiling.ProfilerFiller;
//import org.spongepowered.asm.mixin.Final;
//import org.spongepowered.asm.mixin.Mixin;
//import org.spongepowered.asm.mixin.Mutable;
//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.Set;
//import java.util.function.Supplier;
//
//@Mixin(GoalSelector.class)
//public abstract class GoalSelectorMixin {
//
// @Mutable
// @Shadow
// @Final
// private Set<WrappedGoal> availableGoals;
//
// /**
// * Replace the goal set with an optimized collection type which performs better for iteration.
// */
// @Inject(method = "<init>", at = @At("RETURN"))
// private void reinit(Supplier<ProfilerFiller> supplier, CallbackInfo ci) {
// this.availableGoals = new ObjectLinkedOpenHashSet<>(this.availableGoals);
// }
//}

View File

@@ -1,110 +0,0 @@
package net.gensokyoreimagined.nitori.mixin.shapes.lazy_shape_context;
import net.minecraft.world.phys.shapes.EntityCollisionContext;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Constant;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyConstant;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.function.Predicate;
@Mixin(EntityCollisionContext.class)
public class EntityShapeContextMixin {
@Mutable
@Shadow
@Final
private ItemStack heldItem;
@Mutable
@Shadow
@Final
private Predicate<FluidState> canStandOnFluid;
@Shadow
@Final
@Nullable
private Entity entity;
/**
* Mixin the instanceof to always return false to avoid the expensive inventory access.
* No need to use Opcodes.INSTANCEOF or similar.
*/
@SuppressWarnings("InvalidInjectorMethodSignature")
@ModifyConstant(
method = "<init>(Lnet/minecraft/world/entity/Entity;)V",
constant = @Constant(classValue = LivingEntity.class, ordinal = 0)
)
private static boolean redirectInstanceOf(Object ignored, Class<?> constant) {
return false;
}
@SuppressWarnings("InvalidInjectorMethodSignature")
@ModifyConstant(
method = "<init>(Lnet/minecraft/world/entity/Entity;)V",
constant = @Constant(classValue = LivingEntity.class, ordinal = 2)
)
private static boolean redirectInstanceOf2(Object ignored, Class<?> constant) {
return false;
}
@Inject(
method = "<init>(Lnet/minecraft/world/entity/Entity;)V",
at = @At("TAIL")
)
private void initFields(Entity entity, CallbackInfo ci) {
this.heldItem = null;
this.canStandOnFluid = null;
}
@Inject(
method = "isHoldingItem",
at = @At("HEAD")
)
public void isHolding(Item item, CallbackInfoReturnable<Boolean> cir) {
this.nitori$initHeldItem();
}
@Intrinsic
public ItemStack getHeldItem() {
return this.heldItem;
}
@SuppressWarnings({"UnresolvedMixinReference", "MixinAnnotationTarget"})
@Inject(
method = "getHeldItem",
at = @At("HEAD")
)
private void nitori$initHeldItem(CallbackInfoReturnable<ItemStack> callbackInfoReturnable) {
this.nitori$initHeldItem();
}
@Unique
private void nitori$initHeldItem() {
if (this.heldItem == null) {
this.heldItem = this.entity instanceof LivingEntity ? ((LivingEntity) this.entity).getMainHandItem() : ItemStack.EMPTY;
}
}
@Inject(
method = "canStandOnFluid",
at = @At("HEAD")
)
public void canWalkOnFluid(FluidState state, FluidState fluidState, CallbackInfoReturnable<Boolean> cir) {
if (this.canStandOnFluid == null) {
if (this.entity instanceof LivingEntity livingEntity) {
this.canStandOnFluid = livingEntity::canStandOnFluid;
} else {
this.canStandOnFluid = (liquid) -> false;
}
}
}
}

View File

@@ -1,33 +0,0 @@
package net.gensokyoreimagined.nitori.mixin.shapes.precompute_shape_arrays;
import net.minecraft.world.phys.shapes.CubePointRange;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
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;
@Mixin(CubePointRange.class)
public class FractionalDoubleListMixin {
@Shadow
@Final
private int parts;
private double scale;
@Inject(method = "<init>(I)V", at = @At("RETURN"))
public void initScale(int sectionCount, CallbackInfo ci) {
this.scale = 1.0D / this.parts;
}
/**
* @author JellySquid
* @reason Replace division with multiplication
*/
@Overwrite
public double getDouble(int position) {
return position * this.scale;
}
}

View File

@@ -0,0 +1,110 @@
package net.gensokyoreimagined.nitori.mixin.unapplied.shapes.lazy_shape_context;
//import net.minecraft.world.phys.shapes.EntityCollisionContext;
//import net.minecraft.world.entity.Entity;
//import net.minecraft.world.entity.LivingEntity;
//import net.minecraft.world.level.material.FluidState;
//import net.minecraft.world.item.Item;
//import net.minecraft.world.item.ItemStack;
//import org.jetbrains.annotations.Nullable;
//import org.spongepowered.asm.mixin.*;
//import org.spongepowered.asm.mixin.injection.At;
//import org.spongepowered.asm.mixin.injection.Constant;
//import org.spongepowered.asm.mixin.injection.Inject;
//import org.spongepowered.asm.mixin.injection.ModifyConstant;
//import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
//
//import java.util.function.Predicate;
//
//@Mixin(EntityCollisionContext.class)
//public class EntityShapeContextMixin {
// @Mutable
// @Shadow
// @Final
// private ItemStack heldItem;
//
// @Mutable
// @Shadow
// @Final
// private Predicate<FluidState> canStandOnFluid;
//
// @Shadow
// @Final
// @Nullable
// private Entity entity;
//
// /**
// * Mixin the instanceof to always return false to avoid the expensive inventory access.
// * No need to use Opcodes.INSTANCEOF or similar.
// */
// @SuppressWarnings("InvalidInjectorMethodSignature")
// @ModifyConstant(
// method = "<init>(Lnet/minecraft/world/entity/Entity;)V",
// constant = @Constant(classValue = LivingEntity.class, ordinal = 0)
// )
// private static boolean redirectInstanceOf(Object ignored, Class<?> constant) {
// return false;
// }
//
// @SuppressWarnings("InvalidInjectorMethodSignature")
// @ModifyConstant(
// method = "<init>(Lnet/minecraft/world/entity/Entity;)V",
// constant = @Constant(classValue = LivingEntity.class, ordinal = 2)
// )
// private static boolean redirectInstanceOf2(Object ignored, Class<?> constant) {
// return false;
// }
//
// @Inject(
// method = "<init>(Lnet/minecraft/world/entity/Entity;)V",
// at = @At("TAIL")
// )
// private void initFields(Entity entity, CallbackInfo ci) {
// this.heldItem = null;
// this.canStandOnFluid = null;
// }
//
// @Inject(
// method = "isHoldingItem",
// at = @At("HEAD")
// )
// public void isHolding(Item item, CallbackInfoReturnable<Boolean> cir) {
// this.nitori$initHeldItem();
// }
//
// @Intrinsic
// public ItemStack getHeldItem() {
// return this.heldItem;
// }
//
// @SuppressWarnings({"UnresolvedMixinReference", "MixinAnnotationTarget"})
// @Inject(
// method = "getHeldItem",
// at = @At("HEAD")
// )
// private void nitori$initHeldItem(CallbackInfoReturnable<ItemStack> callbackInfoReturnable) {
// this.nitori$initHeldItem();
// }
//
// @Unique
// private void nitori$initHeldItem() {
// if (this.heldItem == null) {
// this.heldItem = this.entity instanceof LivingEntity ? ((LivingEntity) this.entity).getMainHandItem() : ItemStack.EMPTY;
// }
// }
//
// @Inject(
// method = "canStandOnFluid",
// at = @At("HEAD")
// )
// public void canWalkOnFluid(FluidState state, FluidState fluidState, CallbackInfoReturnable<Boolean> cir) {
// if (this.canStandOnFluid == null) {
// if (this.entity instanceof LivingEntity livingEntity) {
// this.canStandOnFluid = livingEntity::canStandOnFluid;
// } else {
// this.canStandOnFluid = (liquid) -> false;
// }
// }
// }
//}

View File

@@ -0,0 +1,33 @@
package net.gensokyoreimagined.nitori.mixin.unapplied.shapes.precompute_shape_arrays;
//import net.minecraft.world.phys.shapes.CubePointRange;
//import org.spongepowered.asm.mixin.Final;
//import org.spongepowered.asm.mixin.Mixin;
//import org.spongepowered.asm.mixin.Overwrite;
//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;
//
//@Mixin(CubePointRange.class)
//public class FractionalDoubleListMixin {
// @Shadow
// @Final
// private int parts;
//
// private double scale;
//
// @Inject(method = "<init>(I)V", at = @At("RETURN"))
// public void initScale(int sectionCount, CallbackInfo ci) {
// this.scale = 1.0D / this.parts;
// }
//
// /**
// * @author JellySquid
// * @reason Replace division with multiplication
// */
// @Overwrite
// public double getDouble(int position) {
// return position * this.scale;
// }
//}

View File

@@ -1,23 +1,23 @@
package net.gensokyoreimagined.nitori.mixin.world.portal_checks;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.portal.PortalShape;
import net.minecraft.world.phys.Vec3;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.EntityDimensions;
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;
@Mixin({PortalShape.class})
public class DisablePortalChecksMixin {
@Inject(
at = {@At("HEAD")},
method = {"findCollisionFreePosition"},
cancellable = true
)
private static void init(Vec3 fallback, ServerLevel world, Entity entity, EntityDimensions dimensions, CallbackInfoReturnable<Vec3> cir) {
cir.setReturnValue(fallback);
}
}
//import net.minecraft.world.entity.Entity;
//import net.minecraft.world.level.portal.PortalShape;
//import net.minecraft.world.phys.Vec3;
//import net.minecraft.server.level.ServerLevel;
//import net.minecraft.world.entity.EntityDimensions;
//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;
//
//@Mixin({PortalShape.class})
//public class DisablePortalChecksMixin {
// @Inject(
// at = {@At("HEAD")},
// method = {"findCollisionFreePosition"},
// cancellable = true
// )
// private static void init(Vec3 fallback, ServerLevel world, Entity entity, EntityDimensions dimensions, CallbackInfoReturnable<Vec3> cir) {
// cir.setReturnValue(fallback);
// }
//}

View File

@@ -25,7 +25,6 @@
"collections.chunk_tickets.SortedArraySetMixin",
"collections.entity_by_type.TypeFilterableListMixin",
"collections.entity_filtering.TypeFilterableListMixin",
"collections.goals.GoalSelectorMixin",
"collections.mob_spawning.SpawnSettingsMixin",
"collections.fluid_submersion.EntityMixin",
"collections.brain.BrainMixin",
@@ -62,14 +61,7 @@
"network.microopt.VarIntsMixin",
"network.microopt.StringEncodingMixin",
"network.block_breaking.CacheBlockBreakPacketMixin",
"vmp.playerwatching.MixinChunkFilter",
"vmp.playerwatching.MixinServerPlayerEntity",
"vmp.playerwatching.optimize_nearby_player_lookups.MixinMobEntity",
"vmp.general.collections.MixinTypeFilterableList",
"vmp.entity.move_zero_velocity.MixinEntity",
"shapes.blockstate_cache.BlockMixin",
"shapes.lazy_shape_context.EntityShapeContextMixin",
"shapes.precompute_shape_arrays.FractionalDoubleListMixin",
"shapes.precompute_shape_arrays.SimpleVoxelShapeMixin",
"shapes.specialized_shapes.VoxelShapeMixin",
"util.MixinLevelBlockEntityRetrieval",
@@ -81,7 +73,6 @@
"world.block_entity_ticking.support_cache.BlockEntityMixin",
"world.block_entity_ticking.support_cache.DirectBlockEntityTickInvokerMixin",
"world.block_entity_ticking.support_cache.WorldChunkMixin",
"world.portal_checks.DisablePortalChecksMixin",
"world.blending.BlendMixin",
"world.farmland.FarmlandBlockMixin",
"world.biome_access.BiomeAccessMixin"