Compare commits

...

11 Commits

Author SHA1 Message Date
Jason Penilla
0d528e59d7 Work on compatibility with porting lib on Fabric 2024-10-21 19:09:41 -07:00
Jason Penilla
f32a08738e Adjust min/max section optimizations (#55)
* Change min/max section optimisations

* Correctly init dimension type

We need to initialise the field as early as possible in the constructor
to avoid problems.

Also, do not cache min/max section in EntityLookup. Note that mods
that implement worlds with variable heights will not work still,
as the entity slices expect a fixed height.

* Cache calculated height values

---------

Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
2024-10-17 18:02:22 -07:00
Jason Penilla
56e48ed069 Back to 0.1.0-SNAPSHOT 2024-10-15 13:04:47 -07:00
Jason Penilla
9da99576a6 0.1.0-beta.6 2024-10-15 12:56:32 -07:00
Jason Penilla
dfbe1bcf8b Fix Mixin application failure in production
Work around https://github.com/FabricMC/tiny-remapper/issues/137
2024-10-15 12:45:22 -07:00
Jason Penilla
ae29196221 Back to 0.1.0-SNAPSHOT 2024-10-14 19:45:01 -07:00
Jason Penilla
f1eb61cc51 0.1.0-beta.5 2024-10-14 19:17:38 -07:00
Jason Penilla
58c933938f fabric: Call ServerChunkEvents.CHUNK_LOAD/CHUNK_UNLOAD, add and call FabricHooks.ON_EXPLOSION event (#52)
fixes #16
related to #45
2024-10-14 19:06:58 -07:00
Jason Penilla
1dc3cb5f14 Improve LeafProfiler output formatting (#28)
make it readable
2024-10-14 18:03:04 -07:00
Jason Penilla
2acfc6a68e Add missing require = 3 to util_threading_detector PalettedContainer constructor injection, and simplify fast_palette PalettedContainer constructor injection. 2024-10-02 10:54:52 -07:00
Jason Penilla
c22538c364 Back to 0.1.0-SNAPSHOT 2024-09-30 19:22:12 -07:00
20 changed files with 259 additions and 149 deletions

View File

@@ -24,7 +24,7 @@ dependencies {
include "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}" include "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
modImplementation "com.terraformersmc:modmenu:11.0.1" modImplementation "com.terraformersmc:modmenu:11.0.1"
modImplementation fabricApiLibs.command.api.v2 modImplementation fabricApiLibs.fabric.api
include fabricApiLibs.command.api.v2 include fabricApiLibs.command.api.v2
include fabricApiLibs.base include fabricApiLibs.base
} }

View File

@@ -3,6 +3,9 @@ package ca.spottedleaf.moonrise.fabric;
import ca.spottedleaf.moonrise.common.PlatformHooks; import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.util.ConfigHolder; import ca.spottedleaf.moonrise.common.util.ConfigHolder;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder; import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.GenerationChunkHolder; import net.minecraft.server.level.GenerationChunkHolder;
@@ -25,6 +28,45 @@ import java.util.function.Predicate;
public final class FabricHooks implements PlatformHooks { public final class FabricHooks implements PlatformHooks {
public interface OnExplosionDetonate {
public void onExplosion(final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter);
}
public static final Event<OnExplosionDetonate> ON_EXPLOSION_DETONATE = EventFactory.createArrayBacked(
OnExplosionDetonate.class,
listeners -> (final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter) -> {
for (int i = 0; i < listeners.length; i++) {
listeners[i].onExplosion(world, explosion, possiblyAffecting, diameter);
}
}
);
public interface OnChunkWatch {
public void onChunkWatch(final ServerLevel world, final LevelChunk chunk, final ServerPlayer player);
}
public static final Event<OnChunkWatch> ON_CHUNK_WATCH = EventFactory.createArrayBacked(
OnChunkWatch.class,
listeners -> (final ServerLevel world, final LevelChunk chunk, final ServerPlayer player) -> {
for (int i = 0; i < listeners.length; i++) {
listeners[i].onChunkWatch(world, chunk, player);
}
}
);
public interface OnChunkUnwatch {
public void onChunkUnwatch(final ServerLevel world, final ChunkPos chunk, final ServerPlayer player);
}
public static final Event<OnChunkUnwatch> ON_CHUNK_UNWATCH = EventFactory.createArrayBacked(
OnChunkUnwatch.class,
listeners -> (final ServerLevel world, final ChunkPos chunk, final ServerPlayer player) -> {
for (int i = 0; i < listeners.length; i++) {
listeners[i].onChunkUnwatch(world, chunk, player);
}
}
);
@Override @Override
public String getBrand() { public String getBrand() {
return "Moonrise"; return "Moonrise";
@@ -44,7 +86,7 @@ public final class FabricHooks implements PlatformHooks {
@Override @Override
public void onExplosion(final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter) { public void onExplosion(final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter) {
ON_EXPLOSION_DETONATE.invoker().onExplosion(world, explosion, possiblyAffecting, diameter);
} }
@Override @Override
@@ -69,7 +111,7 @@ public final class FabricHooks implements PlatformHooks {
@Override @Override
public void chunkFullStatusComplete(final LevelChunk newChunk, final ProtoChunk original) { public void chunkFullStatusComplete(final LevelChunk newChunk, final ProtoChunk original) {
ServerChunkEvents.CHUNK_LOAD.invoker().onChunkLoad((ServerLevel) newChunk.getLevel(), newChunk);
} }
@Override @Override
@@ -84,7 +126,7 @@ public final class FabricHooks implements PlatformHooks {
@Override @Override
public void chunkUnloadFromWorld(final LevelChunk chunk) { public void chunkUnloadFromWorld(final LevelChunk chunk) {
ServerChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload((ServerLevel) chunk.getLevel(), chunk);
} }
@Override @Override
@@ -94,12 +136,12 @@ public final class FabricHooks implements PlatformHooks {
@Override @Override
public void onChunkWatch(final ServerLevel world, final LevelChunk chunk, final ServerPlayer player) { public void onChunkWatch(final ServerLevel world, final LevelChunk chunk, final ServerPlayer player) {
ON_CHUNK_WATCH.invoker().onChunkWatch(world, chunk, player);
} }
@Override @Override
public void onChunkUnWatch(final ServerLevel world, final ChunkPos chunk, final ServerPlayer player) { public void onChunkUnWatch(final ServerLevel world, final ChunkPos chunk, final ServerPlayer player) {
ON_CHUNK_UNWATCH.invoker().onChunkUnwatch(world, chunk, player);
} }
@Override @Override

View File

@@ -0,0 +1,27 @@
package ca.spottedleaf.moonrise.fabric.mixin.chunk_system;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(Level.class)
abstract class FabricLevelMixin {
/**
* @reason Allow block updates in non-ticking chunks, as new chunk system sends non-ticking chunks to clients
* @author Spottedleaf
*/
@Redirect(
method = "setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;II)Z",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/FullChunkStatus;isOrAfter(Lnet/minecraft/server/level/FullChunkStatus;)Z"
)
)
private boolean sendUpdatesForFullChunks(final FullChunkStatus instance,
final FullChunkStatus fullChunkStatus) {
return instance.isOrAfter(FullChunkStatus.FULL);
}
}

View File

@@ -1,6 +1,6 @@
package ca.spottedleaf.moonrise.fabric.mixin.collisions; package ca.spottedleaf.moonrise.fabric.mixin.collisions;
import ca.spottedleaf.moonrise.patches.getblock.GetBlockLevel; import ca.spottedleaf.moonrise.common.util.WorldUtil;
import it.unimi.dsi.fastutil.objects.Object2DoubleMap; import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.tags.TagKey; import net.minecraft.tags.TagKey;
@@ -9,7 +9,6 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkSource; import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainer;
@@ -61,7 +60,7 @@ abstract class EntityMixin {
final AABB boundingBox = this.getBoundingBox().deflate(1.0E-3); final AABB boundingBox = this.getBoundingBox().deflate(1.0E-3);
final Level world = this.level; final Level world = this.level;
final int minSection = ((GetBlockLevel)world).moonrise$getMinSection(); final int minSection = WorldUtil.getMinSection(world);
final int minBlockX = Mth.floor(boundingBox.minX); final int minBlockX = Mth.floor(boundingBox.minX);
final int minBlockY = Math.max((minSection << 4), Mth.floor(boundingBox.minY)); final int minBlockY = Math.max((minSection << 4), Mth.floor(boundingBox.minY));
@@ -69,7 +68,7 @@ abstract class EntityMixin {
// note: bounds are exclusive in Vanilla, so we subtract 1 - our loop expects bounds to be inclusive // note: bounds are exclusive in Vanilla, so we subtract 1 - our loop expects bounds to be inclusive
final int maxBlockX = Mth.ceil(boundingBox.maxX) - 1; final int maxBlockX = Mth.ceil(boundingBox.maxX) - 1;
final int maxBlockY = Math.min((((GetBlockLevel)world).moonrise$getMaxSection() << 4) | 15, Mth.ceil(boundingBox.maxY) - 1); final int maxBlockY = Math.min((WorldUtil.getMaxSection(world) << 4) | 15, Mth.ceil(boundingBox.maxY) - 1);
final int maxBlockZ = Mth.ceil(boundingBox.maxZ) - 1; final int maxBlockZ = Mth.ceil(boundingBox.maxZ) - 1;
final boolean isPushable = this.isPushedByFluid(); final boolean isPushable = this.isPushedByFluid();

View File

@@ -3,6 +3,7 @@
"package": "ca.spottedleaf.moonrise.fabric.mixin", "package": "ca.spottedleaf.moonrise.fabric.mixin",
"mixins": [ "mixins": [
"chunk_system.FabricDistanceManagerMixin", "chunk_system.FabricDistanceManagerMixin",
"chunk_system.FabricLevelMixin",
"chunk_system.FabricMinecraftServerMixin", "chunk_system.FabricMinecraftServerMixin",
"chunk_system.FabricServerLevelMixin", "chunk_system.FabricServerLevelMixin",
"collisions.EntityMixin" "collisions.EntityMixin"

View File

@@ -12,6 +12,6 @@ concurrentutil_version=0.0.2-SNAPSHOT
cloth_version=15.0.128 cloth_version=15.0.128
lithium_version=mc1.21.1-0.13.1 lithium_version=mc1.21.1-0.13.1
# Mod Properties # Mod Properties
mod_version=0.1.0-beta.4 mod_version=0.1.0-SNAPSHOT
maven_group=ca.spottedleaf.moonrise maven_group=ca.spottedleaf.moonrise
archives_base_name=moonrise archives_base_name=moonrise

View File

@@ -0,0 +1,31 @@
package ca.spottedleaf.moonrise.neoforge.mixin.chunk_system;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(Level.class)
abstract class NeoForgeLevelMixin {
/**
* @reason Allow block updates in non-ticking chunks, as new chunk system sends non-ticking chunks to clients
* @author Spottedleaf
*/
@Redirect(
method = {
// "setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;II)Z",
// NeoForge splits logic from the original method into this one
"markAndNotifyBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/chunk/LevelChunk;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;II)V"
},
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/FullChunkStatus;isOrAfter(Lnet/minecraft/server/level/FullChunkStatus;)Z"
)
)
private boolean sendUpdatesForFullChunks(final FullChunkStatus instance,
final FullChunkStatus fullChunkStatus) {
return instance.isOrAfter(FullChunkStatus.FULL);
}
}

View File

@@ -1,7 +1,7 @@
package ca.spottedleaf.moonrise.neoforge.mixin.collisions; package ca.spottedleaf.moonrise.neoforge.mixin.collisions;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.neoforge.patches.collisions.FluidPushCalculation; import ca.spottedleaf.moonrise.neoforge.patches.collisions.FluidPushCalculation;
import ca.spottedleaf.moonrise.patches.getblock.GetBlockLevel;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceArrayMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceArrayMap;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@@ -10,7 +10,6 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkSource; import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainer;
@@ -59,7 +58,7 @@ abstract class EntityMixin implements IEntityExtension {
final AABB boundingBox = this.getBoundingBox().deflate(1.0E-3); final AABB boundingBox = this.getBoundingBox().deflate(1.0E-3);
final Level world = this.level; final Level world = this.level;
final int minSection = ((GetBlockLevel)world).moonrise$getMinSection(); final int minSection = WorldUtil.getMinSection(world);
final int minBlockX = Mth.floor(boundingBox.minX); final int minBlockX = Mth.floor(boundingBox.minX);
final int minBlockY = Math.max((minSection << 4), Mth.floor(boundingBox.minY)); final int minBlockY = Math.max((minSection << 4), Mth.floor(boundingBox.minY));
@@ -67,7 +66,7 @@ abstract class EntityMixin implements IEntityExtension {
// note: bounds are exclusive in Vanilla, so we subtract 1 // note: bounds are exclusive in Vanilla, so we subtract 1
final int maxBlockX = Mth.ceil(boundingBox.maxX) - 1; final int maxBlockX = Mth.ceil(boundingBox.maxX) - 1;
final int maxBlockY = Math.min((((GetBlockLevel)world).moonrise$getMaxSection() << 4) | 15, Mth.ceil(boundingBox.maxY) - 1); final int maxBlockY = Math.min((WorldUtil.getMaxSection(world) << 4) | 15, Mth.ceil(boundingBox.maxY) - 1);
final int maxBlockZ = Mth.ceil(boundingBox.maxZ) - 1; final int maxBlockZ = Mth.ceil(boundingBox.maxZ) - 1;
final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos(); final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();

View File

@@ -3,6 +3,7 @@
"package": "ca.spottedleaf.moonrise.neoforge.mixin", "package": "ca.spottedleaf.moonrise.neoforge.mixin",
"mixins": [ "mixins": [
"chunk_system.NeoForgeDistanceManagerMixin", "chunk_system.NeoForgeDistanceManagerMixin",
"chunk_system.NeoForgeLevelMixin",
"chunk_system.NeoForgeMinecraftServerMixin", "chunk_system.NeoForgeMinecraftServerMixin",
"chunk_system.NeoForgeServerLevelMixin", "chunk_system.NeoForgeServerLevelMixin",
"collisions.EntityMixin" "collisions.EntityMixin"

View File

@@ -11,10 +11,18 @@ public final class WorldUtil {
return world.getMaxSection() - 1; // getMaxSection() is exclusive return world.getMaxSection() - 1; // getMaxSection() is exclusive
} }
public static int getMaxSection(final Level world) {
return world.getMaxSection() - 1; // getMaxSection() is exclusive
}
public static int getMinSection(final LevelHeightAccessor world) { public static int getMinSection(final LevelHeightAccessor world) {
return world.getMinSection(); return world.getMinSection();
} }
public static int getMinSection(final Level world) {
return world.getMinSection();
}
public static int getMaxLightSection(final LevelHeightAccessor world) { public static int getMaxLightSection(final LevelHeightAccessor world) {
return getMaxSection(world) + 1; return getMaxSection(world) + 1;
} }

View File

@@ -9,7 +9,6 @@ import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup;
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.dfl.DefaultEntityLookup; import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.dfl.DefaultEntityLookup;
import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter; import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.util.profiling.ProfilerFiller; import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.EntityType;
@@ -28,7 +27,6 @@ import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -303,27 +301,6 @@ abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter,
return new BlockPos(blockPos.getX(), this.getHeight(types, blockPos.getX(), blockPos.getZ()), blockPos.getZ()); return new BlockPos(blockPos.getX(), this.getHeight(types, blockPos.getX(), blockPos.getZ()), blockPos.getZ());
} }
/**
* @reason Allow block updates in non-ticking chunks, as new chunk system sends non-ticking chunks to clients
* @author Spottedleaf
*/
@Redirect(
method = {
"setBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;II)Z",
// NeoForge splits logic from the original method into this one
"markAndNotifyBlock(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/chunk/LevelChunk;Lnet/minecraft/world/level/block/state/BlockState;Lnet/minecraft/world/level/block/state/BlockState;II)V"
},
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/FullChunkStatus;isOrAfter(Lnet/minecraft/server/level/FullChunkStatus;)Z"
)
)
private boolean sendUpdatesForFullChunks(final FullChunkStatus instance,
final FullChunkStatus fullChunkStatus) {
return instance.isOrAfter(FullChunkStatus.FULL);
}
// TODO: Thread.currentThread() != this.thread to TickThread? // TODO: Thread.currentThread() != this.thread to TickThread?

View File

@@ -1,11 +1,11 @@
package ca.spottedleaf.moonrise.mixin.collisions; package ca.spottedleaf.moonrise.mixin.collisions;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel; import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil; import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState; import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState;
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape; import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
import ca.spottedleaf.moonrise.patches.collisions.util.NoneMatchStream; import ca.spottedleaf.moonrise.patches.collisions.util.NoneMatchStream;
import ca.spottedleaf.moonrise.patches.getblock.GetBlockLevel;
import it.unimi.dsi.fastutil.floats.FloatArraySet; import it.unimi.dsi.fastutil.floats.FloatArraySet;
import it.unimi.dsi.fastutil.floats.FloatArrays; import it.unimi.dsi.fastutil.floats.FloatArrays;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
@@ -16,7 +16,6 @@ import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkSource; import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.LevelChunkSection; import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.PalettedContainer; import net.minecraft.world.level.chunk.PalettedContainer;
@@ -222,7 +221,7 @@ abstract class EntityMixin {
final int maxChunkY = maxBlockY >> 4; final int maxChunkY = maxBlockY >> 4;
final int maxChunkZ = maxBlockZ >> 4; final int maxChunkZ = maxBlockZ >> 4;
final int minSection = ((GetBlockLevel)world).moonrise$getMinSection(); final int minSection = WorldUtil.getMinSection(world);
final ChunkSource chunkSource = world.getChunkSource(); final ChunkSource chunkSource = world.getChunkSource();
final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos(); final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
@@ -331,7 +330,7 @@ abstract class EntityMixin {
return new NoneMatchStream<>(true); return new NoneMatchStream<>(true);
} }
final int minSection = ((GetBlockLevel)world).moonrise$getMinSection(); final int minSection = WorldUtil.getMinSection(world);
final ChunkSource chunkSource = world.getChunkSource(); final ChunkSource chunkSource = world.getChunkSource();
for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) { for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) {
@@ -406,7 +405,7 @@ abstract class EntityMixin {
return; return;
} }
final int minSection = ((GetBlockLevel)world).moonrise$getMinSection(); final int minSection = WorldUtil.getMinSection(world);
final ChunkSource chunkSource = world.getChunkSource(); final ChunkSource chunkSource = world.getChunkSource();
final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos(); final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();

View File

@@ -1,10 +1,10 @@
package ca.spottedleaf.moonrise.mixin.collisions; package ca.spottedleaf.moonrise.mixin.collisions;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection; import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection;
import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil; import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState; import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState;
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape; import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
import ca.spottedleaf.moonrise.patches.getblock.GetBlockLevel;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.util.Mth; import net.minecraft.util.Mth;
@@ -139,7 +139,7 @@ abstract class LevelMixin implements LevelAccessor, AutoCloseable {
int lastChunkY = Integer.MIN_VALUE; int lastChunkY = Integer.MIN_VALUE;
int lastChunkZ = Integer.MIN_VALUE; int lastChunkZ = Integer.MIN_VALUE;
final int minSection = ((GetBlockLevel)level).moonrise$getMinSection(); final int minSection = WorldUtil.getMinSection(level);
for (;;) { for (;;) {
currPos.set(currX, currY, currZ); currPos.set(currX, currY, currZ);
@@ -334,13 +334,13 @@ abstract class LevelMixin implements LevelAccessor, AutoCloseable {
*/ */
@Override @Override
public Optional<BlockPos> findSupportingBlock(final Entity entity, final AABB aabb) { public Optional<BlockPos> findSupportingBlock(final Entity entity, final AABB aabb) {
final int minSection = ((GetBlockLevel)(Level)(Object)this).moonrise$getMinSection(); final int minSection = WorldUtil.getMinSection((Level)(Object)this);
final int minBlockX = Mth.floor(aabb.minX - CollisionUtil.COLLISION_EPSILON) - 1; final int minBlockX = Mth.floor(aabb.minX - CollisionUtil.COLLISION_EPSILON) - 1;
final int maxBlockX = Mth.floor(aabb.maxX + CollisionUtil.COLLISION_EPSILON) + 1; final int maxBlockX = Mth.floor(aabb.maxX + CollisionUtil.COLLISION_EPSILON) + 1;
final int minBlockY = Math.max((minSection << 4) - 1, Mth.floor(aabb.minY - CollisionUtil.COLLISION_EPSILON) - 1); final int minBlockY = Math.max((minSection << 4) - 1, Mth.floor(aabb.minY - CollisionUtil.COLLISION_EPSILON) - 1);
final int maxBlockY = Math.min((((GetBlockLevel)(Level)(Object)this).moonrise$getMaxSection() << 4) + 16, Mth.floor(aabb.maxY + CollisionUtil.COLLISION_EPSILON) + 1); final int maxBlockY = Math.min((WorldUtil.getMaxSection((Level)(Object)this) << 4) + 16, Mth.floor(aabb.maxY + CollisionUtil.COLLISION_EPSILON) + 1);
final int minBlockZ = Mth.floor(aabb.minZ - CollisionUtil.COLLISION_EPSILON) - 1; final int minBlockZ = Mth.floor(aabb.minZ - CollisionUtil.COLLISION_EPSILON) - 1;
final int maxBlockZ = Mth.floor(aabb.maxZ + CollisionUtil.COLLISION_EPSILON) + 1; final int maxBlockZ = Mth.floor(aabb.maxZ + CollisionUtil.COLLISION_EPSILON) + 1;

View File

@@ -35,40 +35,18 @@ abstract class PalettedContainerMixin<T> implements PaletteResize<T>, PalettedCo
* @author Spottedleaf * @author Spottedleaf
*/ */
@Inject( @Inject(
method = "<init>(Lnet/minecraft/core/IdMap;Ljava/lang/Object;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;)V", // cannot use `<init>*` due to https://github.com/FabricMC/tiny-remapper/issues/137
method = {
"<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;Lnet/minecraft/world/level/chunk/PalettedContainer$Configuration;Lnet/minecraft/util/BitStorage;Ljava/util/List;)V",
"<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;Lnet/minecraft/world/level/chunk/PalettedContainer$Data;)V",
"<init>(Lnet/minecraft/core/IdMap;Ljava/lang/Object;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;)V"
},
at = @At( at = @At(
value = "RETURN" value = "RETURN"
) ),
require = 3 // Require matching all 3 constructors
) )
private void constructorHook1(final CallbackInfo ci) { private void constructorHook(final CallbackInfo ci) {
this.updateData(this.data);
}
/**
* @reason Hook to update raw palette data on object construction
* @author Spottedleaf
*/
@Inject(
method = "<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;Lnet/minecraft/world/level/chunk/PalettedContainer$Configuration;Lnet/minecraft/util/BitStorage;Ljava/util/List;)V",
at = @At(
value = "RETURN"
)
)
private void constructorHook2(final CallbackInfo ci) {
this.updateData(this.data);
}
/**
* @reason Hook to update raw palette data on object construction
* @author Spottedleaf
*/
@Inject(
method = "<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;Lnet/minecraft/world/level/chunk/PalettedContainer$Data;)V",
at = @At(
value = "RETURN"
)
)
private void constructorHook3(final CallbackInfo ci) {
this.updateData(this.data); this.updateData(this.data);
} }

View File

@@ -1,10 +1,11 @@
package ca.spottedleaf.moonrise.mixin.getblock; package ca.spottedleaf.moonrise.mixin.getblock;
import ca.spottedleaf.moonrise.common.util.WorldUtil; import com.llamalad7.mixinextras.sugar.Local;
import ca.spottedleaf.moonrise.patches.getblock.GetBlockLevel;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.dimension.DimensionType;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@@ -13,7 +14,16 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
// Higher priority to apply after Lithium mixin.world.inline_height.WorldMixin // Higher priority to apply after Lithium mixin.world.inline_height.WorldMixin
@Mixin(value = Level.class, priority = 1100) @Mixin(value = Level.class, priority = 1100)
abstract class LevelMixin implements GetBlockLevel, LevelAccessor, AutoCloseable { abstract class LevelMixin implements LevelAccessor, AutoCloseable {
@Unique
private int height;
@Unique
private int minBuildHeight;
@Unique
private int maxBuildHeight;
@Unique @Unique
private int minSection; private int minSection;
@@ -22,30 +32,7 @@ abstract class LevelMixin implements GetBlockLevel, LevelAccessor, AutoCloseable
private int maxSection; private int maxSection;
@Unique @Unique
private int minBuildHeight; private int sectionsCount;
@Unique
private int maxBuildHeight;
@Override
public final int moonrise$getMinSection() {
return this.minSection;
}
@Override
public final int moonrise$getMaxSection() {
return this.maxSection;
}
@Override
public final int moonrise$getMinBuildHeight() {
return this.minBuildHeight;
}
@Override
public final int moonrise$getMaxBuildHeight() {
return this.maxBuildHeight;
}
/** /**
* @reason Init min/max section * @reason Init min/max section
@@ -54,14 +41,43 @@ abstract class LevelMixin implements GetBlockLevel, LevelAccessor, AutoCloseable
@Inject( @Inject(
method = "<init>", method = "<init>",
at = @At( at = @At(
value = "RETURN" value = "CTOR_HEAD"
) )
) )
private void init(final CallbackInfo ci) { private void init(final CallbackInfo ci,
this.minSection = WorldUtil.getMinSection(this); @Local(ordinal = 0, argsOnly = true) final Holder<DimensionType> dimensionTypeHolder) {
this.maxSection = WorldUtil.getMaxSection(this); final DimensionType dimType = dimensionTypeHolder.value();
this.minBuildHeight = this.getMinBuildHeight(); this.height = dimType.height();
this.maxBuildHeight = this.getMaxBuildHeight(); this.minBuildHeight = dimType.minY();
this.maxBuildHeight = this.minBuildHeight + this.height;
this.minSection = this.minBuildHeight >> 4;
this.maxSection = ((this.maxBuildHeight - 1) >> 4) + 1;
this.sectionsCount = this.maxSection - this.minSection;
}
@Override
public int getHeight() {
return this.height;
}
@Override
public int getMinBuildHeight() {
return this.minBuildHeight;
}
@Override
public int getMaxBuildHeight() {
return this.maxBuildHeight;
}
@Override
public int getMinSection() {
return this.minSection;
}
@Override
public int getMaxSection() {
return this.maxSection;
} }
@Override @Override
@@ -73,4 +89,24 @@ abstract class LevelMixin implements GetBlockLevel, LevelAccessor, AutoCloseable
public boolean isOutsideBuildHeight(final BlockPos blockPos) { public boolean isOutsideBuildHeight(final BlockPos blockPos) {
return this.isOutsideBuildHeight(blockPos.getY()); return this.isOutsideBuildHeight(blockPos.getY());
} }
@Override
public int getSectionIndex(final int blockY) {
return (blockY >> 4) - this.minSection;
}
@Override
public int getSectionIndexFromSectionY(final int sectionY) {
return sectionY - this.minSection;
}
@Override
public int getSectionYFromSectionIndex(final int sectionIdx) {
return sectionIdx + this.minSection;
}
@Override
public int getSectionsCount() {
return this.sectionsCount;
}
} }

View File

@@ -17,11 +17,17 @@ abstract class PalettedContainerMixin {
* @author jpenilla * @author jpenilla
*/ */
@Redirect( @Redirect(
method = "<init>*", // cannot use `<init>*` due to https://github.com/FabricMC/tiny-remapper/issues/137
method = {
"<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;Lnet/minecraft/world/level/chunk/PalettedContainer$Configuration;Lnet/minecraft/util/BitStorage;Ljava/util/List;)V",
"<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;Lnet/minecraft/world/level/chunk/PalettedContainer$Data;)V",
"<init>(Lnet/minecraft/core/IdMap;Ljava/lang/Object;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;)V"
},
at = @At( at = @At(
value = "NEW", value = "NEW",
target = "Lnet/minecraft/util/ThreadingDetector;" target = "Lnet/minecraft/util/ThreadingDetector;"
) ),
require = 3 // Require matching all 3 constructors
) )
private static ThreadingDetector threadingDetector(final String name) { private static ThreadingDetector threadingDetector(final String name) {
return THREADING_DETECTOR; return THREADING_DETECTOR;

View File

@@ -46,8 +46,6 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
protected final SWMRLong2ObjectHashTable<ChunkSlicesRegion> regions = new SWMRLong2ObjectHashTable<>(128, 0.5f); protected final SWMRLong2ObjectHashTable<ChunkSlicesRegion> regions = new SWMRLong2ObjectHashTable<>(128, 0.5f);
protected final int minSection; // inclusive
protected final int maxSection; // inclusive
protected final LevelCallback<Entity> worldCallback; protected final LevelCallback<Entity> worldCallback;
protected final ConcurrentLong2ReferenceChainedHashTable<Entity> entityById = new ConcurrentLong2ReferenceChainedHashTable<>(); protected final ConcurrentLong2ReferenceChainedHashTable<Entity> entityById = new ConcurrentLong2ReferenceChainedHashTable<>();
@@ -56,8 +54,6 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
public EntityLookup(final Level world, final LevelCallback<Entity> worldCallback) { public EntityLookup(final Level world, final LevelCallback<Entity> worldCallback) {
this.world = world; this.world = world;
this.minSection = WorldUtil.getMinSection(world);
this.maxSection = WorldUtil.getMaxSection(world);
this.worldCallback = worldCallback; this.worldCallback = worldCallback;
} }
@@ -404,7 +400,7 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
protected boolean addEntity(final Entity entity, final boolean fromDisk, final boolean event) { protected boolean addEntity(final Entity entity, final boolean fromDisk, final boolean event) {
final BlockPos pos = entity.blockPosition(); final BlockPos pos = entity.blockPosition();
final int sectionX = pos.getX() >> 4; final int sectionX = pos.getX() >> 4;
final int sectionY = Mth.clamp(pos.getY() >> 4, this.minSection, this.maxSection); final int sectionY = Mth.clamp(pos.getY() >> 4, WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world));
final int sectionZ = pos.getZ() >> 4; final int sectionZ = pos.getZ() >> 4;
this.checkThread(sectionX, sectionZ, "Cannot add entity off-main thread"); this.checkThread(sectionX, sectionZ, "Cannot add entity off-main thread");
@@ -523,7 +519,7 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
final int sectionZ = ((ChunkSystemEntity)entity).moonrise$getSectionZ(); final int sectionZ = ((ChunkSystemEntity)entity).moonrise$getSectionZ();
final BlockPos newPos = entity.blockPosition(); final BlockPos newPos = entity.blockPosition();
final int newSectionX = newPos.getX() >> 4; final int newSectionX = newPos.getX() >> 4;
final int newSectionY = Mth.clamp(newPos.getY() >> 4, this.minSection, this.maxSection); final int newSectionY = Mth.clamp(newPos.getY() >> 4, WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world));
final int newSectionZ = newPos.getZ() >> 4; final int newSectionZ = newPos.getZ() >> 4;
if (newSectionX == sectionX && newSectionY == sectionY && newSectionZ == sectionZ) { if (newSectionX == sectionX && newSectionY == sectionY && newSectionZ == sectionZ) {

View File

@@ -1,12 +1,12 @@
package ca.spottedleaf.moonrise.patches.collisions; package ca.spottedleaf.moonrise.patches.collisions;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter; import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter;
import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState; import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState;
import ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity; import ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity;
import ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData; import ca.spottedleaf.moonrise.patches.collisions.shape.CachedShapeData;
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionDiscreteVoxelShape; import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionDiscreteVoxelShape;
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape; import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
import ca.spottedleaf.moonrise.patches.getblock.GetBlockLevel;
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection; import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection;
import it.unimi.dsi.fastutil.doubles.DoubleArrayList; import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.doubles.DoubleList; import it.unimi.dsi.fastutil.doubles.DoubleList;
@@ -1934,13 +1934,13 @@ public final class CollisionUtil {
} }
} }
final int minSection = ((GetBlockLevel)world).moonrise$getMinSection(); final int minSection = WorldUtil.getMinSection(world);
final int minBlockX = Mth.floor(aabb.minX - COLLISION_EPSILON) - 1; final int minBlockX = Mth.floor(aabb.minX - COLLISION_EPSILON) - 1;
final int maxBlockX = Mth.floor(aabb.maxX + COLLISION_EPSILON) + 1; final int maxBlockX = Mth.floor(aabb.maxX + COLLISION_EPSILON) + 1;
final int minBlockY = Math.max((minSection << 4) - 1, Mth.floor(aabb.minY - COLLISION_EPSILON) - 1); final int minBlockY = Math.max((minSection << 4) - 1, Mth.floor(aabb.minY - COLLISION_EPSILON) - 1);
final int maxBlockY = Math.min((((GetBlockLevel)world).moonrise$getMaxSection() << 4) + 16, Mth.floor(aabb.maxY + COLLISION_EPSILON) + 1); final int maxBlockY = Math.min((WorldUtil.getMaxSection(world) << 4) + 16, Mth.floor(aabb.maxY + COLLISION_EPSILON) + 1);
final int minBlockZ = Mth.floor(aabb.minZ - COLLISION_EPSILON) - 1; final int minBlockZ = Mth.floor(aabb.minZ - COLLISION_EPSILON) - 1;
final int maxBlockZ = Mth.floor(aabb.maxZ + COLLISION_EPSILON) + 1; final int maxBlockZ = Mth.floor(aabb.maxZ + COLLISION_EPSILON) + 1;

View File

@@ -1,13 +0,0 @@
package ca.spottedleaf.moonrise.patches.getblock;
public interface GetBlockLevel {
public int moonrise$getMinSection();
public int moonrise$getMaxSection();
public int moonrise$getMinBuildHeight();
public int moonrise$getMaxBuildHeight();
}

View File

@@ -2,6 +2,8 @@ package ca.spottedleaf.moonrise.patches.profiler;
import com.mojang.logging.LogUtils; import com.mojang.logging.LogUtils;
import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue; import it.unimi.dsi.fastutil.ints.IntArrayFIFOQueue;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue; import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap; import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -169,6 +171,7 @@ public final class LeafProfiler {
public final List<ProfileNode> children = new ArrayList<>(); public final List<ProfileNode> children = new ArrayList<>();
public long childrenTimingCount; public long childrenTimingCount;
public int depth = -1; public int depth = -1;
public boolean lastChild;
private ProfileNode(final ProfileNode parent, final int nodeId, final LProfilerRegistry.ProfilerEntry profiler, private ProfileNode(final ProfileNode parent, final int nodeId, final LProfilerRegistry.ProfilerEntry profiler,
final long totalTime, final long totalCount) { final long totalTime, final long totalCount) {
@@ -188,11 +191,6 @@ public final class LeafProfiler {
long[] timers, long[] timers,
long[] counters long[] counters
) { ) {
private static final char[][] INDENT_PATTERNS = new char[][] {
"|---".toCharArray(),
"|+++".toCharArray(),
};
public List<String> dumpToString() { public List<String> dumpToString() {
final List<LProfileGraph.GraphNode> graphDFS = this.graph.getDFS(); final List<LProfileGraph.GraphNode> graphDFS = this.graph.getDFS();
final Reference2ReferenceOpenHashMap<LProfileGraph.GraphNode, ProfileNode> nodeMap = new Reference2ReferenceOpenHashMap<>(); final Reference2ReferenceOpenHashMap<LProfileGraph.GraphNode, ProfileNode> nodeMap = new Reference2ReferenceOpenHashMap<>();
@@ -232,14 +230,10 @@ public final class LeafProfiler {
totalTime += node.totalTime; totalTime += node.totalTime;
} }
ProfileNode profileNode; final ArrayDeque<ProfileNode> flatOrderedNodes = new ArrayDeque<>();
final StringBuilder builder = new StringBuilder();
while ((profileNode = orderedNodes.pollFirst()) != null) {
if (profileNode.nodeId != LProfileGraph.ROOT_NODE && profileNode.totalCount == 0L) {
// skip nodes not recorded
continue;
}
ProfileNode profileNode;
while ((profileNode = orderedNodes.pollFirst()) != null) {
final int depth = profileNode.depth; final int depth = profileNode.depth;
profileNode.children.sort((final ProfileNode p1, final ProfileNode p2) -> { profileNode.children.sort((final ProfileNode p1, final ProfileNode p2) -> {
final int typeCompare = p1.profiler.type().compareTo(p2.profiler.type()); final int typeCompare = p1.profiler.type().compareTo(p2.profiler.type());
@@ -257,12 +251,32 @@ public final class LeafProfiler {
} }
}); });
boolean first = true;
for (int i = profileNode.children.size() - 1; i >= 0; --i) { for (int i = profileNode.children.size() - 1; i >= 0; --i) {
final ProfileNode child = profileNode.children.get(i); final ProfileNode child = profileNode.children.get(i);
if (child.totalCount == 0L) {
// skip nodes not recorded
continue;
}
if (first) {
child.lastChild = true;
first = false;
}
child.depth = depth + 1; child.depth = depth + 1;
orderedNodes.addFirst(child); orderedNodes.addFirst(child);
} }
flatOrderedNodes.addLast(profileNode);
}
final StringBuilder builder = new StringBuilder();
final IntList closed = new IntArrayList();
while ((profileNode = flatOrderedNodes.pollFirst()) != null) {
final int depth = profileNode.depth;
closed.removeIf((int d) -> d >= depth);
if (profileNode.lastChild) {
closed.add(depth);
}
if (profileNode.nodeId == LProfileGraph.ROOT_NODE) { if (profileNode.nodeId == LProfileGraph.ROOT_NODE) {
// don't display root // don't display root
continue; continue;
@@ -280,9 +294,18 @@ public final class LeafProfiler {
// <indent>#<name> avg X sum Y // <indent>#<name> avg X sum Y
builder.setLength(0); builder.setLength(0);
// prepare indent // prepare indent
final char[] indent = INDENT_PATTERNS[ret.size() % INDENT_PATTERNS.length];
for (int i = 0; i < depth; ++i) { for (int i = 0; i < depth; ++i) {
builder.append(indent); if (i == depth - 1) {
if (flatOrderedNodes.peekFirst() == null || profileNode.lastChild) {
builder.append(" └─");
} else {
builder.append(" ├─");
}
} else if (!closed.contains(i + 1)) {
builder.append("");
} else {
builder.append(" ");
}
} }
switch (profilerEntry.type()) { switch (profilerEntry.type()) {