Skip to content

Improve CubicPlayerManager and add support for third party modded cubic world generators#46

Open
RecursivePineapple wants to merge 15 commits into
masterfrom
world-generators-and-player-manager
Open

Improve CubicPlayerManager and add support for third party modded cubic world generators#46
RecursivePineapple wants to merge 15 commits into
masterfrom
world-generators-and-player-manager

Conversation

@RecursivePineapple
Copy link
Copy Markdown
Collaborator

@RecursivePineapple RecursivePineapple commented Apr 12, 2026

Code changes

  • Rewrote CubicPlayerManager to fix a lot of its race conditions. There's still a problem with the underworld's mushrooms and boulders not syncing, but I'm not sure what's causing that. Vanilla works fine, so I'm going to ignore it for now 🤣.
  • Added the ICubicWorldProvider interface, which is used by third party mods to make their dimensions cubic.
  • Added some (seemingly unused) utilities for this (see CubeStackBlockView).
  • Removed a large number of allocations (mostly CallbackInfoReturnables) by changing mixins around.
  • Sorted out cube/chunk ticking. This was a mess before, and there was a lot of unused pointless code.
  • Accidentally fixed the entity tracking issues by fixing CubicPlayerManager. Previously, entities in new chunks wouldn't be synced properly, causing them to glitch out constantly. Now, everything works normally.

Testing done

  • Fly around in the vanilla overworld. Whole chunks used to not sync, trees would pop into existence, and there would be this weird gradient pattern on water (see below). Now, everything will sync fine and there won't be skipped block updates.
  • Also fly around on a server, to make sure everything works the same.
  • For the memory allocations, I used visualvm and async profiler to diagnose which objects were allocated the most. The asprof -d 30 -f profile.html -e alloc GradleStart command will make a profile that shows allocations, but asprof only works on linux.
  • Publish CC to the local maven repo and run UtilitiesInExcess with it, to test the cubic underworld world generator.
  • For ticking, I placed water on a grassy hill and let it sit. The water cascaded properly and the grass below it slowly decayed into dirt.
  • For animals, I ran around the vanilla overworld and made sure they were working properly. I could bump into them as expected and hit them fine. I also tested mobs in the underworld, since it spawns them frequently.

See Also

Weird water gradients

image

Stress test

https://discord.com/channels/181078474394566657/1415607665375313961/1492890103457255564

Comment thread src/main/java/com/cardinalstar/cubicchunks/util/AddressTools.java
Copy link
Copy Markdown
Collaborator

@DarkShadow44 DarkShadow44 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bunch of questions and some points that could need improvement. Please don't resolve those, leave that for me.

}

@ModifyVariable(method = "generate", at = @At("LOAD"), ordinal = 1, argsOnly = true)
public int fixHeight(int value, @Local(argsOnly = true) World world, @Local(argsOnly = true, ordinal = 0) int x,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need to inject that at every load? At least that's what it currently does. TBH, I can't really follow this mixin's logic.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's one of its issues. I couldn't figure out how to modify the variable at the head.


void updateLightBetween(Chunk column, int localX, int y1, int y2, int localZ);

default void onSendCubes(Iterable<? extends ICube> cubes) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't we remove the whole method? It's currently unused.

args = "array=get",
target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;"))
private ExtendedBlockStorage init_getStorage(ExtendedBlockStorage[] ebs, int y) {
return ebs[y - (this.isColumn ? 0 : blockToCube(((IMinMaxHeight) worldObj).getMinHeight()))];
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why exactly can we remove that?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ebs array normally starts at y=0. It seems like modern CC shifts the ebses down as new cubes are added, which is kinda odd because all code that I've seen that interacts with the array expects it to have 16 indices. This is better compat-wise.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then the entire mixin can be removed, shouldn't do anything anymore right?

args = "array=get",
target = "Lnet/minecraft/world/chunk/Chunk;storageArrays:[Lnet/minecraft/world/chunk/storage/ExtendedBlockStorage;"))
private ExtendedBlockStorage getBlock_getStorage(ExtendedBlockStorage[] ebs, int y) {
return isColumn ? getEBS_CubicChunks(y) : ebs[y];
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can we remove this?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Everything should route through the same code either way, this is just for simplification from what I can see. I don't remember the specifics, all of these changes were really finicky.

* double-ticking is avoided by checking this lastTicked field instead of deduplication by putting them all into a
* Set.
*/
private long lastTicked = Long.MIN_VALUE;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now unused. Is this correct or do we still need to workaround whatever issue this tried to prevent?

}

public static int getLocalAddress(int localX, int localZ) {
return (Bits.packUnsignedToInt(localX, 4, 0) | Bits.packUnsignedToInt(localZ, 4, 4));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this also get the & 0xF treatment for consistency?

cubesToUnload.add(new CubePos(cubeX, cubeY, cubeZ));
}
}
public WorldVisibilityChange findChanged(CubePos oldPos, CubePos newPos, int oldHorizonalView, int oldVerticalView,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oldHorizonalView -> oldHorizontalView

}

public void registerCallback(CubeLoaderCallback callback) {
if (callback != null) this.callbacks.add(callback);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why drop those checks?

if (columnData.syncedCubeCount <= 0) {
syncedColumns.remove(pos.getX(), pos.getZ());

if (player.isWatchingColumn(pos.getX(), pos.getZ())) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While were at it, can we add

MinecraftForge.EVENT_BUS.post(new ChunkWatchEvent.UnWatch(
                            new ChunkCoordIntPair(pos.getX(), pos.getZ()), player.player));

here? Similar for Watch event. This makes FMP work (at least until you reload the chunk)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants