Skip to content

Commit 014bd1f

Browse files
committed
I AM SPEED
1 parent fefa645 commit 014bd1f

File tree

2 files changed

+63
-35
lines changed

2 files changed

+63
-35
lines changed

src/main/java/net/superkat/tidal/TidalWaveHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ public void debugChunkDirectionParticles(long chunkPosL, boolean farParticles) {
173173
for (Map.Entry<BlockPos, SitePos> entry : map.entrySet()) {
174174
BlockPos pos = entry.getKey();
175175
SitePos sitePos = entry.getValue();
176-
if(!sitePos.yawCalculated) continue;
176+
if(sitePos == null || !sitePos.yawCalculated) continue;
177177
DebugWaveMovementParticle.DebugWaveMovementParticleEffect particleEffect = new DebugWaveMovementParticle.DebugWaveMovementParticleEffect(
178178
Vec3d.unpackRgb(color.getRGB()).toVector3f(),
179179
1f,

src/main/java/net/superkat/tidal/water/WaterHandler.java

Lines changed: 62 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
package net.superkat.tidal.water;
22

33
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
4-
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
4+
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
5+
import it.unimi.dsi.fastutil.longs.LongArrayList;
56
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
67
import it.unimi.dsi.fastutil.objects.ObjectArrayFIFOQueue;
78
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
@@ -26,7 +27,6 @@
2627

2728
import java.awt.*;
2829
import java.util.Collection;
29-
import java.util.Iterator;
3030
import java.util.List;
3131
import java.util.Map;
3232
import java.util.Set;
@@ -72,22 +72,25 @@ public class WaterHandler {
7272

7373
//Chunk scanner for each chunk - SCANNER VALUE SET TO NULL ONCE SCANNER IS DONE!!
7474
//The chunk is not removed from this list until it is unloaded!
75-
public Long2ObjectLinkedOpenHashMap<ChunkScanner> scanners = new Long2ObjectLinkedOpenHashMap<>(81, 0.25f);
75+
public Long2ObjectOpenHashMap<ChunkScanner> scanners = new Long2ObjectOpenHashMap<>(81, 0.25f);
7676

7777
//Keep track of how many block updates have happened in a chunk - used to rescan chunks after enough(configurable) updates
7878
public Long2IntOpenHashMap chunkUpdates = new Long2IntOpenHashMap(81, 0.25f);
7979

8080
//Set of water blocks waiting to have their closest site found
81-
public Long2ObjectLinkedOpenHashMap<ObjectArrayFIFOQueue<BlockPos>> waitingWaterBlocks = new Long2ObjectLinkedOpenHashMap<>(81, 0.25f);
81+
public Long2ObjectOpenHashMap<ObjectArrayFIFOQueue<BlockPos>> waitingWaterBlocks = new Long2ObjectOpenHashMap<>(81, 0.25f);
8282

8383
//Set of shoreline sites, used to determine angle of area
84-
public Long2ObjectLinkedOpenHashMap<Set<SitePos>> sites = new Long2ObjectLinkedOpenHashMap<>(81, 0.25f);
84+
public Long2ObjectOpenHashMap<ObjectOpenHashSet<SitePos>> sites = new Long2ObjectOpenHashMap<>(81, 0.25f);
85+
86+
//Caches all the sites into one set, not split by chunk.
87+
public ObjectOpenHashSet<SitePos> cachedSiteSet = new ObjectOpenHashSet<>();
8588

8689
//Keep track of which SitePos is closest to all scanned water blocks
87-
public Long2ObjectLinkedOpenHashMap<Object2ObjectOpenHashMap<BlockPos, SitePos>> siteCache = new Long2ObjectLinkedOpenHashMap<>();
90+
public Long2ObjectOpenHashMap<Object2ObjectOpenHashMap<BlockPos, SitePos>> siteCache = new Long2ObjectOpenHashMap<>();
8891

8992
//All scanned shoreline blocks
90-
public Long2ObjectLinkedOpenHashMap<Set<BlockPos>> shoreBlocks = new Long2ObjectLinkedOpenHashMap<>(81, 0.25f);
93+
public Long2ObjectOpenHashMap<Set<BlockPos>> shoreBlocks = new Long2ObjectOpenHashMap<>(81, 0.25f);
9194

9295
//boolean for if the initial joining/chunk reloading build is finished or not
9396
public boolean built = false;
@@ -120,8 +123,8 @@ public void tick() {
120123

121124
if(built) {
122125
boolean noMoreWaitingBlocks = tickWaitingWaterBlocks(false);
123-
if(noMoreWaitingBlocks && recalcSiteCenters) {
124-
this.calcSiteCenters();
126+
if(noMoreWaitingBlocks && recalcSiteCenters) { //failsafe I guess?
127+
this.calcAllSiteCenters();
125128
this.recalcSiteCenters = false;
126129
}
127130
}
@@ -137,24 +140,17 @@ public void tick() {
137140
* @param pos The BlockPos to use for finding the closest SitePos
138141
* @return The closest SitePos, or null if no SitePos' are currently stored.
139142
*/
140-
@Nullable
143+
@Nullable //FIXME - optimize this(Hama said it should be easy)
141144
public SitePos findClosestSite(BlockPos pos) {
142145
if(this.sites.isEmpty()) return null;
143146

144-
Set<SitePos> siteSet;
145-
long chunkPosL = new ChunkPos(pos).toLong();
146-
if(this.sites.get(chunkPosL) != null) {
147-
//FIXME - this can cause a bug where, if there is a SitePos in the same chunk, but pretty much across the entire chunk,
148-
// and there's a SitePos closer, but in the neighbouring chunk, it is assumed to be closer to the SitePos
149-
// in the same chunk instead of knowing there's one closer block-wise, but in the neighbouring chunk.
150-
siteSet = this.sites.get(chunkPosL);
151-
} else {
152-
siteSet = this.sites.values().stream().flatMap(Collection::stream).collect(Collectors.toSet());
147+
if(this.cachedSiteSet == null || this.cachedSiteSet.isEmpty()) {
148+
this.cacheSiteSet();
153149
}
154150

155151
double distance = 0;
156152
SitePos closest = null;
157-
for (SitePos site : siteSet) {
153+
for (SitePos site : this.cachedSiteSet) {
158154
double dx = pos.getX() + 0.5 - site.getX();
159155
double dz = pos.getZ() + 0.5 - site.getZ();
160156
double dist = dx * dx + dz * dz;
@@ -254,6 +250,9 @@ public boolean build() {
254250

255251
long scannerTime = Util.getMeasuringTimeMs();
256252
int chunksScanned = 0;
253+
254+
//I believe doing it this way is faster than an iterator
255+
// LongArrayList finishedScanners = new LongArrayList();
257256
for (ChunkScanner scanner : this.scanners.values()) {
258257
if (scanner == null) continue;
259258
// long scannerStartTime = Util.getMeasuringTimeMs();
@@ -262,12 +261,14 @@ public boolean build() {
262261
while (!scanner.isFinished()) {
263262
scanner.tick();
264263
if (scanner.isFinished()) {
265-
scanners.put(scanner.chunkPos.toLong(), null);
264+
// finishedScanners.add(scanner.chunkPos.toLong());
265+
this.scanners.put(scanner.chunkPos.toLong(), null);
266266
MinecraftClient.getInstance().player.playSound(SoundEvents.ITEM_TRIDENT_HIT_GROUND, 0.05f, 1f);
267267
// Tidal.LOGGER.info("Scanner time: {} ms", Util.getMeasuringTimeMs() - scannerStartTime);
268268
}
269269
}
270270
}
271+
// finishedScanners.forEach(scannerPosL -> this.scanners.remove(scannerPosL));
271272

272273
Tidal.LOGGER.info("Total scan time: {} ms", Util.getMeasuringTimeMs() - scannerTime);
273274
Tidal.LOGGER.info("Chunks scanned: {}", chunksScanned);
@@ -280,7 +281,7 @@ public boolean build() {
280281
Tidal.LOGGER.info("Site cache time: {} ms", Util.getMeasuringTimeMs() - siteCacheTime);
281282

282283
long siteCenterCalcTime = Util.getMeasuringTimeMs();
283-
this.calcSiteCenters();
284+
this.calcAllSiteCenters();
284285
Tidal.LOGGER.info("Site center calc time: {} ms", Util.getMeasuringTimeMs() - siteCenterCalcTime);
285286

286287
Tidal.LOGGER.info("Total Chunk Build time: {} ms", Util.getMeasuringTimeMs() - overallStartTime);
@@ -295,7 +296,12 @@ public boolean build() {
295296
public void rebuild() {
296297
this.clear(); //clear all data(ticking scanners -> null, sites/shoreblocks/waterblocks all cleared)
297298

298-
for (Map.Entry<Long, ChunkScanner> entry : this.scanners.sequencedEntrySet()) {
299+
// for (ChunkPos chunkPos : this.tidalWaveHandler.getNearbyChunkPos()) {
300+
// long chunkPosL = chunkPos.toLong();
301+
// this.scanners.put(chunkPosL, new ChunkScanner(this, this.world, chunkPos));
302+
// }
303+
304+
for (Map.Entry<Long, ChunkScanner> entry : this.scanners.long2ObjectEntrySet()) {
299305
ChunkPos chunkPos = new ChunkPos(entry.getKey());
300306
long pos = chunkPos.toLong();
301307
this.scanners.put(pos, new ChunkScanner(this, this.world, chunkPos));
@@ -312,7 +318,10 @@ public void rebuild() {
312318
public void tickScheduledScanners(ClientPlayerEntity player) {
313319
BlockPos playerPos = player.getBlockPos();
314320
int chunkRadius = this.tidalWaveHandler.getChunkRadius(); //caching this call might help?
315-
for (Map.Entry<Long, ChunkScanner> entry : this.scanners.sequencedEntrySet()) {
321+
// Iterator<Map.Entry<Long, ChunkScanner>> iterator = this.scanners.sequencedEntrySet().iterator();
322+
323+
// LongArrayList finishedScanners = new LongArrayList();
324+
for (Map.Entry<Long, ChunkScanner> entry : this.scanners.long2ObjectEntrySet()) {
316325
if (entry.getValue() == null) continue;
317326

318327
long chunkPosL = entry.getKey();
@@ -324,10 +333,12 @@ public void tickScheduledScanners(ClientPlayerEntity player) {
324333
}
325334

326335
if (scanner.isFinished()) {
336+
// finishedScanners.add(chunkPosL);
327337
scanners.put(chunkPosL, null);
328338
MinecraftClient.getInstance().player.playSound(SoundEvents.ITEM_TRIDENT_HIT_GROUND, 0.25f, 1f);
329339
}
330340
}
341+
// finishedScanners.forEach(scannerPosL -> this.scanners.remove(scannerPosL));
331342
}
332343

333344
/**
@@ -339,33 +350,34 @@ public void tickScheduledScanners(ClientPlayerEntity player) {
339350
* @return True if there are no more waiting water blocks
340351
*/
341352
public boolean tickWaitingWaterBlocks(boolean assumeFullScan) {
342-
Iterator<Map.Entry<Long, ObjectArrayFIFOQueue<BlockPos>>> iterator = this.waitingWaterBlocks.sequencedEntrySet().iterator();
343-
344-
while(iterator.hasNext()) {
345-
Map.Entry<Long, ObjectArrayFIFOQueue<BlockPos>> entry = iterator.next();
346-
if(entry.getValue() == null) continue;
353+
LongArrayList finishedBlocks = new LongArrayList();
354+
for (Map.Entry<Long, ObjectArrayFIFOQueue<BlockPos>> entry : this.waitingWaterBlocks.long2ObjectEntrySet()) {
355+
if (entry.getValue() == null) continue;
347356
long chunkPosL = entry.getKey();
348357
//the nearbyScannersFinished call could probably be optimized?
349358
if (!assumeFullScan && !nearbyScannersFinished(chunkPosL)) continue;
350359

351360
ObjectArrayFIFOQueue<BlockPos> queue = entry.getValue();
352361
boolean finished = false;
353362
for (int i = 0; i < 10; i++) {
354-
if(queue.size() <= 0) {
363+
if (queue.size() <= 0) {
355364
finished = true;
356365
break;
357366
}
358367
BlockPos pos = queue.dequeue();
359368
getSiteForPos(pos); //caches pos' closest site
360369
}
361370

362-
if(finished || queue.size() <= 0) {
363-
iterator.remove();
371+
if (finished || queue.size() <= 0) {
372+
finishedBlocks.add(chunkPosL);
364373
recalcSiteCenters = true;
374+
this.calcSiteCenter(chunkPosL);
365375
MinecraftClient.getInstance().player.playSound(SoundEvents.BLOCK_VAULT_ACTIVATE, 0.1f, 1f);
366376
}
367377
}
368378

379+
finishedBlocks.forEach(chunkPosL -> this.waitingWaterBlocks.remove(chunkPosL));
380+
369381
return this.waitingWaterBlocks.isEmpty();
370382
}
371383

@@ -376,7 +388,7 @@ public boolean tickWaitingWaterBlocks(boolean assumeFullScan) {
376388
* @return If the nearby ChunkScanners are finished.
377389
*/
378390
public boolean nearbyScannersFinished(long chunkPosL) {
379-
int radius = 3; //will be configurable later
391+
int radius = 1; //will be configurable later
380392
ChunkPos pos = new ChunkPos(chunkPosL);
381393
ChunkPos start = new ChunkPos(pos.x + radius, pos.z + radius);
382394
ChunkPos end = new ChunkPos(pos.x - radius, pos.z - radius);
@@ -392,8 +404,16 @@ public boolean nearbyScannersFinished(long chunkPosL) {
392404
return true;
393405
}
394406

407+
public void calcSiteCenter(long chunkPosL) {
408+
if(!this.sites.containsKey(chunkPosL)) return;
409+
for (SitePos site : this.sites.get(chunkPosL)) {
410+
site.updateCenter();
411+
}
412+
MinecraftClient.getInstance().player.playSound(SoundEvents.BLOCK_BEEHIVE_ENTER, 0.3f, 1f);
413+
}
414+
395415
//I feel comfortable doing this because this calculation is usually only taken 1-3ms for me
396-
public void calcSiteCenters() {
416+
public void calcAllSiteCenters() {
397417
for (SitePos site : this.sites.values().stream().flatMap(Collection::stream).toList()) {
398418
site.updateCenter();
399419
}
@@ -416,6 +436,11 @@ public boolean scannerInDistance(BlockPos playerBlockPos, long chunkPosL, int ch
416436
return distance < chunkRadius;
417437
}
418438

439+
public void cacheSiteSet() {
440+
//caching this list saved ~200ms during a build/rebuild
441+
this.cachedSiteSet = new ObjectOpenHashSet<>(this.sites.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()));
442+
}
443+
419444
/**
420445
* Schedules a chunk to be scanned water blocks, shoreblocks, sites, etc. Called when a new chunk is loaded.
421446
*
@@ -471,6 +496,7 @@ public void createSitePos(BlockPos pos) {
471496
long chunkPosL = new ChunkPos(pos).toLong();
472497
SitePos site = new SitePos(pos);
473498
sites.computeIfAbsent(chunkPosL, aLong -> new ObjectOpenHashSet<>()).add(site);
499+
this.cachedSiteSet.add(site);
474500
}
475501

476502
/**
@@ -506,12 +532,14 @@ public void removeChunkFromTrackers(long chunkPosL) {
506532
this.shoreBlocks.remove(chunkPosL);
507533
this.siteCache.remove(chunkPosL);
508534
this.sites.remove(chunkPosL);
535+
this.cachedSiteSet.clear(); //resets it
509536
}
510537

511538
public void clear() {
512539
this.waitingWaterBlocks.clear();
513540
this.shoreBlocks.clear();
514541
this.sites.clear();
515542
this.siteCache.clear();
543+
this.cachedSiteSet.clear();
516544
}
517545
}

0 commit comments

Comments
 (0)