1
0
Fork 0

improve client performance and fix chunk light concurrency

This commit is contained in:
Sen 2025-09-07 09:41:42 +02:00
parent 46c95630f3
commit ca97bf2e18
Signed by: sen
GPG key ID: 3AC50A6F47D1B722
10 changed files with 44 additions and 208 deletions

View file

@ -336,15 +336,11 @@ public class Client implements IThreadListener {
}
protected void onEntityAdded(Entity entityIn) {
if(Client.this.spawnQueue.contains(entityIn))
Client.this.spawnQueue.remove(entityIn);
}
protected void onEntityRemoved(Entity entityIn) {
if(Client.this.entityList.contains(entityIn)) {
if(entityIn.isEntityAlive())
Client.this.spawnQueue.add(entityIn);
else
if(!entityIn.isEntityAlive())
Client.this.entityList.remove(entityIn);
}
}
@ -446,10 +442,7 @@ public class Client implements IThreadListener {
public final Map<String, Integer> playerList = Maps.<String, Integer>newTreeMap();
public final List<PlayerCharacter> characterList = Lists.<PlayerCharacter>newArrayList();
private final Set<Entity> entityList = Sets.<Entity>newHashSet();
private final Set<Entity> spawnQueue = Sets.<Entity>newHashSet();
private final Set<ChunkPos> previousActive = Sets.<ChunkPos>newHashSet();
private final LongHashMap<ChunkClient> chunkMapping = new LongHashMap();
private final List<ChunkClient> chunkListing = Lists.<ChunkClient>newArrayList();
private final Set<Long> emptyChunkListing = Sets.<Long>newHashSet();
private final Set<Long> nextEmptyChunkListing = Sets.<Long>newHashSet();
public final int[] lastSelection = new int[ItemCategory.values().length];
@ -489,6 +482,7 @@ public class Client implements IThreadListener {
public boolean freecam;
public boolean servercam;
public boolean shaders;
public volatile boolean worldLight;
private int leftClickCounter;
private int rightClickTimer;
@ -587,12 +581,10 @@ public class Client implements IThreadListener {
public int renderDistance = 8;
@Variable(name = "chunk_build_time", category = CVarCategory.RENDER, min = 1, max = 100, display = "Zeit für Chunk-Bau", unit = "ms")
public int maxBuildTime = 8;
@Variable(name = "chunk_light_updates", category = CVarCategory.RENDER, min = 100, max = 10000, display = "Licht-Updates / Tick")
private int lightUpdates = 2048;
@Variable(name = "chunk_light_updates", category = CVarCategory.RENDER, min = 0, max = 10000, display = "Licht-Updates / Frame")
private int lightUpdates = 150;
@Variable(name = "chunk_light_range", category = CVarCategory.RENDER, min = 5, max = 1024, display = "Radius Licht-Updates")
private int lightRange = 32;
@Variable(name = "chunk_light_onload", category = CVarCategory.RENDER, min = 0, max = 32, display = "Licht-Init. / Tick")
private int lightInit = 0;
@Variable(name = "draw_fov", category = CVarCategory.RENDER, min = 20.0f, max = 160.0f, display = "Sichtfeld (FOV)", unit = "°", precision = 1)
public float fov = 70.0f;
@Variable(name = "draw_wireframe", category = CVarCategory.RENDER, display = "Gitter-Render-Modus")
@ -823,6 +815,7 @@ public class Client implements IThreadListener {
}
public void unloadWorld() {
this.worldLight = false;
ClientPlayer netHandler = this.getNetHandler();
if(netHandler != null)
netHandler.cleanup();
@ -1110,11 +1103,19 @@ public class Client implements IThreadListener {
GuiPlayer.INSTANCE.updatePlayer();
if (this.world != null)
{
this.tickWorld();
if (this.world != null)
this.world.updatePhysics();
this.markReload();
if (Vars.timeFlow > 0)
{
this.displayTick(ExtMath.floord(this.player.posX), ExtMath.floord(this.player.posY), ExtMath.floord(this.player.posZ));
if(this.world.dimension.hasOrbit())
this.world.setOrbit((this.world.getOrbit() + (long)Vars.timeFlow) % this.world.dimension.getOrbitalPeriod());
if(this.world.dimension.hasRotation())
this.world.setRotation((this.world.getRotation() + (long)Vars.timeFlow) % this.world.dimension.getRotationalPeriod());
this.world.dimension.setEpoch(this.world.dimension.getEpoch() + (long)Vars.timeFlow);
}
this.displayTick(ExtMath.floord(this.player.posX), ExtMath.floord(this.player.posY), ExtMath.floord(this.player.posZ));
this.effectRenderer.update();
if(this.player != null && (this.player.getHeldItem() == null || this.player.getHeldItem().getItem().getCategory() != this.itemSelection))
this.select(1);
@ -1843,6 +1844,7 @@ public class Client implements IThreadListener {
public World loadWorld(Dimension dim, int type)
{
this.worldLight = false;
this.resetWorld();
this.viewEntity = null;
this.freecam = this.servercam = false;
@ -1854,6 +1856,7 @@ public class Client implements IThreadListener {
this.tiles = this.world.tiles;
this.entityIds = this.world.entityIds;
this.initWorld();
this.worldLight = true;
this.renderer.setWorldAndLoadRenderers(this.world);
@ -2094,8 +2097,8 @@ public class Client implements IThreadListener {
// this.connected != null ? this.connected : "[???]"))),
this.renderer.getDebugInfoRenders() + "\n" +
this.renderer.getDebugInfoEntities() + "\n" +
"Partikel: " + this.effectRenderer.getParticleCount() + ". O: " + this.entities.size() + "\n" +
"Chunk-Cache: M " + this.chunkMapping.getNumHashElements() + ", L " + this.chunkListing.size() + "\n" +
"Partikel: " + this.effectRenderer.getParticleCount() + ", O: " + this.entities.size() + "\n" +
"Chunk-Cache: " + this.chunkMapping.getNumHashElements() + "\n" +
String.format("XYZ: %.3f / %.3f / %.3f", this.viewEntity.posX,
this.viewEntity.getEntityBoundingBox().minY, this.viewEntity.posZ) + "\n" +
String.format("Block: %d %d %d, R: '%s/%s'", pos.getX(), pos.getY(), pos.getZ(),
@ -2697,6 +2700,16 @@ public class Client implements IThreadListener {
this.tickFraction = ((double)this.tick_torun) / 1000000.0;
this.tick_ttime += this.tick_ftime;
this.tick_time = this.tickFrame != 0 ? (this.tick_ftime / (long)this.tickFrame) : 0L;
if(this.player != null) {
int radius = Math.min(this.renderDistance * 16, this.lightRange);
for(int n = 0; n < this.lightUpdates; n++) {
int x = ExtMath.floord(this.player.posX) + this.world.rand.range(-radius, radius);
int y = ExtMath.floord(this.player.posY) + this.world.rand.range(-radius, radius);
int z = ExtMath.floord(this.player.posZ) + this.world.rand.range(-radius, radius);
this.world.checkBlockLight(new LocalPos(x, y, z));
}
}
}
public void tick_target(float tps) {
@ -3640,10 +3653,7 @@ public class Client implements IThreadListener {
private void resetWorld() {
this.entityList.clear();
this.spawnQueue.clear();
this.previousActive.clear();
this.chunkMapping.clear();
this.chunkListing.clear();
this.emptyChunkListing.clear();
this.nextEmptyChunkListing.clear();
this.emptyChunk = null;
@ -3714,88 +3724,6 @@ public class Client implements IThreadListener {
}
}
private void tickWorld()
{
this.world.updatePhysics();
this.markReload();
if (Vars.timeFlow > 0)
{
if(this.world.dimension.hasOrbit())
this.world.setOrbit((this.world.getOrbit() + (long)Vars.timeFlow) % this.world.dimension.getOrbitalPeriod());
if(this.world.dimension.hasRotation())
this.world.setRotation((this.world.getRotation() + (long)Vars.timeFlow) % this.world.dimension.getRotationalPeriod());
this.world.dimension.setEpoch(this.world.dimension.getEpoch() + (long)Vars.timeFlow);
}
for (int i = 0; i < 10 && !this.spawnQueue.isEmpty(); ++i)
{
Entity entity = (Entity)this.spawnQueue.iterator().next();
this.spawnQueue.remove(entity);
if (!this.entities.contains(entity))
{
this.world.spawnEntityInWorld(entity);
}
}
long time = System.currentTimeMillis();
for (ChunkClient chunk : this.chunkListing)
{
chunk.spawnTiles();
}
if (System.currentTimeMillis() - time > 100L)
{
Log.TICK.warn("Render-Chunk-Tick dauerte " + (System.currentTimeMillis() - time) + " ms");
}
if(this.player != null) {
int radius = Math.min(this.renderDistance * 16, this.lightRange);
for(int n = 0; n < this.lightUpdates; n++) {
int x = ExtMath.floord(this.player.posX) + this.world.rand.range(-radius, radius);
int y = ExtMath.floord(this.player.posY) + this.world.rand.range(-radius, radius);
int z = ExtMath.floord(this.player.posZ) + this.world.rand.range(-radius, radius);
this.world.checkBlockLight(new LocalPos(x, y, z));
}
}
Set<ChunkPos> active = this.world.getActiveChunks();
active.clear();
if(this.player != null) {
int x = ExtMath.floord(this.player.posX / 16.0D);
int z = ExtMath.floord(this.player.posZ / 16.0D);
for(int cx = -this.renderDistance; cx <= this.renderDistance; cx++) {
for(int cz = -this.renderDistance; cz <= this.renderDistance; cz++) {
active.add(new ChunkPos(cx + x, cz + z));
if(this.lightInit > 0)
this.getChunk(cx + x, cz + z).updateLight(this.lightInit);
}
}
}
this.previousActive.retainAll(active);
if (this.previousActive.size() == active.size())
{
this.previousActive.clear();
}
int i = 0;
for (ChunkPos chunkcoordintpair : active)
{
if (!this.previousActive.contains(chunkcoordintpair))
{
ChunkClient chunk = this.getChunk(chunkcoordintpair.x, chunkcoordintpair.z);
this.previousActive.add(chunkcoordintpair);
++i;
if (i >= 10)
{
return;
}
}
}
}
public void doPreChunk(int x, int z, boolean load)
{
long id = LongHashMap.packInt(x, z);
@ -3805,7 +3733,6 @@ public class Client implements IThreadListener {
this.doPreChunk(x, z, false);
ChunkClient chunk = new ChunkClient(this.world, x, z);
this.chunkMapping.add(id, chunk);
this.chunkListing.add(chunk);
chunk.setLoaded();
}
else
@ -3813,7 +3740,6 @@ public class Client implements IThreadListener {
ChunkClient chunk = this.getChunk(x, z);
chunk.onChunkUnload();
this.chunkMapping.remove(id);
this.chunkListing.remove(chunk);
this.emptyChunkListing.remove(id);
}
@ -3875,9 +3801,7 @@ public class Client implements IThreadListener {
{
Entity entity2 = this.unloaded.get(l);
if(this.entityList.contains(entity2)) {
if(entity2.isEntityAlive())
this.spawnQueue.add(entity2);
else
if(!entity2.isEntityAlive())
this.entityList.remove(entity2);
}
}
@ -3919,10 +3843,8 @@ public class Client implements IThreadListener {
private void spawnEntity(Entity entityIn) {
boolean flag = this.world.spawnEntityInWorld(entityIn);
this.entityList.add(entityIn);
if(!flag)
this.spawnQueue.add(entityIn);
else if(entityIn instanceof EntityCart)
this.soundManager.playSound(new MovingSoundMinecart((EntityCart)entityIn));
if(flag && entityIn instanceof EntityCart cart)
this.soundManager.playSound(new MovingSoundMinecart(cart));
}
private void ensureAreaLoaded(Entity entity) {