Jump to content

Recommended Posts

Posted

Alright so I recently tested my algorithm for moving 5000 blocks from one world to another, sadly its very slow  :P

 

So I profiled it for "Hot Spots" and found some interesting results, (My flood fill algorithm took 0% cpu time so it's not that)

the things causing the lag seem to be basic functions that Minecraft does by default when placing and breaking blocks. Here's the breakdown of the biggest offenders:

 

net.minecraft.world.storage.ThreadedFileIOBase.processQueue()	 (20.1%)

paulscode.sound.SimpleThread.snooze() (19.6%)	

net.minecraft.server.MinecraftServer.run()  (19.1%)

net.minecraft.client.Minecraft.addScheduledTask()	 (18.7%)	

net.minecraft.world.World.getChunkFromChunkCoords()  (7.9%)	

FlyingFortress.Entities.Ship.updateMinMax()  (4.9%)

FlyingFortress.Region.WorldUtils.RegionChunkProvider.provideChunk()  (2.2%)

 

It seems that most of the time is spent by the saving thread, but I'm not sure why  ???

 

Anyway let me give the code of mine that could also be causing the lag

 

Starting with the makeWorld() method which I use to move the blocks from one world to another:

 

int x = (int)(posX); int y = (int)posY; int z = (int)(posZ);
	BlockPos start = new BlockPos(x,y,z);
    	SpatialDetector attatchedBlocks = new SpatialDetector(start, worldObj, 5000,true);
    	ArrayList<BlockPos> detectedBlockPos = new ArrayList<BlockPos>(attatchedBlocks.foundSet.size()+1);
    	boolean forcedStop = false;
    	TIntIterator intIter = attatchedBlocks.foundSet.iterator();
    	while(intIter.hasNext()&&!forcedStop){
    		int hash = (Integer) intIter.next();
    		BlockPos fromHash = attatchedBlocks.getPosWithRespectTo(hash, start);
    		if(fromHash.getY()+128-y<0){
    			forcedStop = true;
    		}
    		detectedBlockPos.add(fromHash);
    	}
    	if(forcedStop){
    		detectedBlockPos.clear();
    	}
	for(BlockPos global:detectedBlockPos){
		IBlockState state = worldObj.getBlockState(global);
		BlockPos pos = global.add(-x,128-y,-z);
		region.setBlockState(pos, state,0);
	}
	((ShipRegionServer)region).isNew=false;
	for(BlockPos global:detectedBlockPos){
		NextTickListEntry scheduledUpdate;
		BlockPos local = global.add(-x,128-y,-z);
		//region.scheduleUpdate(new BlockPos(bs.x-x,bs.y+128-y,bs.z-z), region.getBlockState(new BlockPos(bs.x-x,bs.y+128-y,bs.z-z)).getBlock(), 0);
		Iterator tickListIter = ((WorldServer)worldObj).pendingTickListEntriesHashSet.iterator();
		while(tickListIter.hasNext()){
			scheduledUpdate = (NextTickListEntry)tickListIter.next();
			if(scheduledUpdate.position.equals(global)){
				region.scheduleUpdate(local, region.getBlockState(local).getBlock(), scheduledUpdate.priority);
			}
		}
	}
	for(BlockPos pos:detectedBlockPos){
		BlockPos local = pos.add(-x,128-y,-z);
		TileEntity tile = worldObj.getTileEntity(pos);
		if(tile!=null){
			if(tile instanceof IInventory){
				IInventory inventory = ((IInventory)tile);
				TileEntity inRegion = region.getTileEntity(local);
				for(int i=0;i<inventory.getSizeInventory();i++){
					((IInventory)inRegion).setInventorySlotContents(i, inventory.getStackInSlot(i));
				}
				inventory.clear();
			}
			worldObj.getTileEntity(pos).invalidate();
		}
	}
	for(BlockPos global:detectedBlockPos){
		worldObj.setBlockState(global, Blocks.planks.getDefaultState(),;
	}
	for(BlockPos global:detectedBlockPos){
		worldObj.setBlockState(global, Blocks.air.getDefaultState(), 3);
	}

 

And the updateMinMax() method, I need it to keep track of the min/max xyz values of the current world

 

private void updateMinMax(){
	if(blockPositions.isEmpty()){
		minX=0;minY=0;minZ=0;maxX=0;maxY=0;maxZ=0;
		return;
	}
	RegionChunkProvider provider = (RegionChunkProvider) region.getChunkProvider();
	boolean good = false;
	for(BlockPos pos:blockPositions){
		if(!good){
			minX=pos.getX();minY=pos.getY();minZ=pos.getZ();maxX=pos.getX();maxY=pos.getY();maxZ=pos.getZ();
			good = true;
		}
		if(!chunksInUse.contains(IntegerChunkCoordIntPair.toKeyFromPos(pos))){
			int xCor = pos.getX()>>4;
			int zCor = pos.getZ()>>4;
			provider.addChunk(IntegerChunkCoordIntPair.toKeyFromPos(pos));
			chunksInUse.add(IntegerChunkCoordIntPair.toKeyFromPos(pos));
			if(!worldObj.isRemote){
				ShipRegionServer server = (ShipRegionServer) region;
				server.chunkQueues.put(IntegerChunkCoordIntPair.toKeyFromPos(pos), new ArrayList<BlockPos>());
			}
		}
		if(pos.getX()<minX){
			minX = pos.getX();
		}
		if(pos.getX()>maxX){
			maxX = pos.getX();
		}
		if(pos.getY()<minY){
			minY = pos.getY();
		}
		if(pos.getY()>maxY){
			maxY = pos.getY();
		}
		if(pos.getZ()<minZ){
			minZ = pos.getZ();
		}
		if(pos.getZ()>maxZ){
			maxZ = pos.getZ();
		}
	}
}

 

Any tips for getting past this terrible lag spike?

"you seem to be THE best modder I've seen imo."

~spynathan

 

ლ(́◉◞౪◟◉‵ლ

Posted

Someone that knows more about chunk loader / saving can probably help you better. I expect there would be a way to only update the chunk after doing all the copying, whereas the current lag might be because it is saving every time you place a block. Just a wild guess.

 

But I have a couple other thoughts:

1) In the case where the current block matches the block you're moving to that position, like would happen for a lot of air blocks, you might not want to actually copy the block. Depending on how many air blocks are included in your copy, that might make it much more efficient (i.e. not triggering all the vanilla add block stuff).

2) When I was doing a mod that generated a castle in the sky I found that placing blocks high up were way slower (thousands of times slower). I traced it down to issue where Minecraft recalculates the lighting after every block placed and therefore higher up blocks have more processing. I was able to find a way to disable this although it was slightly tricky. If you think this is related to your problem I can maybe give you some code examples.

3) When placing blocks there is option to place it with notification of neighbors. That is often useful, but I assume there is some performance impact. Depending on how you do the copying though you might want to disable some of that.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Posted

Without reading code (I am going to bed), I can point few things:

- If you are using setBlock, use propeer flags.

- Even that is shit (above), so what you really want is to manipulate world's block data directly, without asking for shit, you could do that with:

Chunk chunk = event.world.getChunkFromChunkCoords(event.chunkX, event.chunkZ);
	for (ExtendedBlockStorage storage : chunk.getBlockStorageArray())

Do note that this will introduce new problems because you WILL have to do post-processing (light updates and chunk-synchronization calls), but it will be fast.

 

There is also partial solution by introducting Queued placement with ServerTickHandler that will place blocks per tick. Idk if that satisfies you, but I can tell that even when it's slow, it looks damn cool in-game :D (filling effect).

 

*flies away* #pointingOutObvious #notUsefulAtAll :x

1.7.10 is no longer supported by forge, you are on your own.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • 1) Update to the latest build of Forge for your MC version. The recommended build actually means minimum recommended. I can’t remember if it was backported to 1.20.1 or not, but we did clean up the early loading screen a bit in newer builds to look less cluttered. 2) Change the accessibility setting in game to black background. The early loading screen will then be black instead of red.
    • I'm sure this entire community knows exactly who you are, what mixin you're talking about, and how deer function in minecraft.  But being new here, and I am ignorant about all of those things. That said, I'd love to review your mixin.  I'm also having mixin issues, and I feel that if I can help you, perhaps both of our problems might get solved. Can you provide some links and context for people who aren't aware of your renown?  I'm asking humbly because I know you probably have better things to do, and you just want somebody to fix things for you.
    • I am working in the latest MDK.  Minecraft 1.21.4, Forge 54.1.0. I am trying to create a mixin.  The implementation doesn't matter.  Assume it is doing nothing more than logging to the console: @Mixin(LevelRenderer.class) public abstract class LevelRendererMixin { private static final Logger LOGGER = LogManager.getLogger("LevelRendererMixin"); @Inject(method = "renderLevel", at = @At("TAIL")) private void onRenderLevel( com.mojang.blaze3d.resource.GraphicsResourceAllocator allocator, net.minecraft.client.DeltaTracker deltaTracker, boolean someFlag, Camera camera, GameRenderer gameRenderer, Matrix4f matrix1, Matrix4f matrix2, CallbackInfo ci ) { Assuming my whole implementation is just to write something to console, it works perfectly fine in when I debug (runClient) in IntelliJ.  Whenever the Minecraft `renderLevel` runs every frame, my logging is overlaid at "TAIL". Yes, this spams the sht out of the console. But when I `build` and use the jar as a mod, it does not.  The mixin annotation processor shows to be loading, and my other parts of my mod work, but the nothing gets logged by my mixin. I am apparently generating a proper `refmap` and it's in the jar root.  Other files are also in the jar appropriately, including mods.toml.  And all the naming and reference paths are correct. I had to add this to my build.gradle to get my refmap into the jar ([name] obviously replaced): tasks.register("copyRefmap", Copy) { dependsOn tasks.named("compileJava") from("${project.buildDir}/tmp/compileJava") { include "mixins.[name].refmap.json" } into("${project.buildDir}/resources/main") } tasks.named("processResources", ProcessResources).configure { dependsOn(tasks.named("copyRefmap")) } tasks.named("jar", Jar).configure { // Include the generated refmap from build/resources/main into the jar. from("${project.buildDir}/resources/main") { include "mixins.[name].refmap.json" } }   Just for fun, here is my refmap in case something looks wrong to anybody:   { "mappings": { "com/[name]/mixin/LevelRendererMixin": { "renderLevel": "Lnet/minecraft/client/renderer/LevelRenderer;m_109599_(Lcom/mojang/blaze3d/resource/GraphicsResourceAllocator;Lnet/minecraft/client/DeltaTracker;ZLnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/GameRenderer;Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V" } }, "data": { "searge": { "com/[name]/mixin/LevelRendererMixin": { "renderLevel": "Lnet/minecraft/client/renderer/LevelRenderer;m_109599_(Lcom/mojang/blaze3d/resource/GraphicsResourceAllocator;Lnet/minecraft/client/DeltaTracker;ZLnet/minecraft/client/Camera;Lnet/minecraft/client/renderer/GameRenderer;Lorg/joml/Matrix4f;Lorg/joml/Matrix4f;)V" } } } } TLDR; My mixin works in dev, but not when built and run in an official Forge/Minecraft environment.  Like it's not overlaying/replacing the minecraft function. What are some typical other things to check when a mixin works in dev, but not after build?
    • Thank you, Ugdhar.  But that only confirms the problem.  Both in the github and in my IDE, if I search for objects extended from net.minecraftforge.client.event, it isn't there.  Though the javadocs (at least at nekoyue) say it should be. Maybe since it definitely isn't there, is there some other way anybody knows to highlight some blocks (without mixins and drawing artificial faces on the camera).
  • Topics

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.