77
77
import java .util .HashSet ;
78
78
import java .util .IdentityHashMap ;
79
79
import java .util .Iterator ;
80
+ import java .util .Map ;
80
81
import java .util .Objects ;
81
82
import java .util .Set ;
82
83
import java .util .concurrent .TimeUnit ;
@@ -151,6 +152,12 @@ public class PlayerCubeMap extends PlayerChunkMap implements LightingManager.IHe
151
152
*/
152
153
private final Set <ColumnWatcher > columnWatchersToUpdate = new HashSet <>();
153
154
155
+ /**
156
+ * A queue of cubes to add a player to, this limits the amount of cubes sent to a player per tick to the set limit
157
+ * even when joining an area with already existing cube watchers
158
+ */
159
+ private final Map <EntityPlayerMP , WatchersSortingList <CubeWatcher >> cubesToAddPlayerTo = new IdentityHashMap <>();
160
+
154
161
/**
155
162
* Contains all CubeWatchers that need to be sent to clients,
156
163
* but these cubes are not fully loaded/generated yet.
@@ -342,6 +349,7 @@ public void tick() {
342
349
this .toSendToClientNeedSort = false ;
343
350
this .cubesToSendToClients .sort ();
344
351
this .columnsToSendToClients .sort ();
352
+ this .cubesToAddPlayerTo .forEach ((p , set ) -> set .sort ());
345
353
}
346
354
347
355
getWorldServer ().profiler .endStartSection ("generate" );
@@ -413,7 +421,7 @@ public void tick() {
413
421
}
414
422
if (!this .cubesToSendToClients .isEmpty ()) {
415
423
getWorldServer ().profiler .startSection ("cubes" );
416
- int toSend = CubicChunksConfig .cubesToSendPerTick ;//sending cubes, so send 8x more at once
424
+ int toSend = CubicChunksConfig .cubesToSendPerTick ;
417
425
Iterator <CubeWatcher > it = this .cubesToSendToClients .iterator ();
418
426
419
427
while (it .hasNext () && toSend > 0 ) {
@@ -432,6 +440,29 @@ public void tick() {
432
440
getWorldServer ().profiler .endSection (); // cubes
433
441
}
434
442
443
+ if (!cubesToAddPlayerTo .isEmpty ()) {
444
+ for (Iterator <EntityPlayerMP > iterator = cubesToAddPlayerTo .keySet ().iterator (); iterator .hasNext (); ) {
445
+ EntityPlayerMP entityPlayerMP = iterator .next ();
446
+ WatchersSortingList <CubeWatcher > watchers = cubesToAddPlayerTo .get (entityPlayerMP );
447
+ int toSend = CubicChunksConfig .cubesToSendPerTick ;
448
+ Iterator <CubeWatcher > iter ;
449
+ for (iter = watchers .iterator (); toSend > 0 && iter .hasNext (); ) {
450
+ CubeWatcher watcher = iter .next ();
451
+ watcher .addPlayer (entityPlayerMP );
452
+ CubeWatcher .SendToPlayersResult state = watcher .sendToPlayers ();
453
+ if (state == CubeWatcher .SendToPlayersResult .WAITING_LIGHT || state == CubeWatcher .SendToPlayersResult .WAITING ) {
454
+ if (!cubesToGenerate .contains (watcher )) {
455
+ cubesToGenerate .appendToStart (watcher );
456
+ }
457
+ }
458
+ toSend --;
459
+ iter .remove ();
460
+ }
461
+ if (!iter .hasNext ()) {
462
+ iterator .remove ();
463
+ }
464
+ }
465
+ }
435
466
getWorldServer ().profiler .endStartSection ("unload" );
436
467
//if there are no players - unload everything
437
468
if (this .players .isEmpty ()) {
@@ -581,7 +612,7 @@ public void addPlayer(EntityPlayerMP player) {
581
612
}
582
613
CubeWatcher cubeWatcher = getOrCreateCubeWatcher (currentPos );
583
614
584
- cubeWatcher . addPlayer ( player );
615
+ scheduleAddPlayerToWatcher ( cubeWatcher , player );
585
616
});
586
617
this .players .put (player .getEntityId (), playerWrapper );
587
618
this .setNeedSort ();
@@ -606,7 +637,7 @@ public void removePlayer(EntityPlayerMP player) {
606
637
CubeWatcher watcher = getCubeWatcher (cubePos );
607
638
if (watcher != null ) {
608
639
// remove from the watcher, it also removes the watcher if it becomes empty
609
- watcher . removePlayer ( player );
640
+ removePlayerFromCubeWatcher ( watcher , player );
610
641
}
611
642
612
643
// remove column watchers if needed
@@ -690,14 +721,14 @@ private void updatePlayer(PlayerWrapper entry, CubePos oldPos, CubePos newPos) {
690
721
cubesToLoad .forEach (pos -> {
691
722
CubeWatcher cubeWatcher = this .getOrCreateCubeWatcher (pos );
692
723
assert cubeWatcher .getCubePos ().equals (pos );
693
- cubeWatcher . addPlayer ( entry .playerEntity );
724
+ scheduleAddPlayerToWatcher ( cubeWatcher , entry .playerEntity );
694
725
});
695
726
getWorldServer ().profiler .endStartSection ("removeCubes" );
696
727
cubesToRemove .forEach (pos -> {
697
728
CubeWatcher cubeWatcher = this .getCubeWatcher (pos );
698
729
if (cubeWatcher != null ) {
699
730
assert cubeWatcher .getCubePos ().equals (pos );
700
- cubeWatcher . removePlayer ( entry .playerEntity );
731
+ removePlayerFromCubeWatcher ( cubeWatcher , entry .playerEntity );
701
732
}
702
733
});
703
734
getWorldServer ().profiler .endStartSection ("removeColumns" );
@@ -710,6 +741,26 @@ private void updatePlayer(PlayerWrapper entry, CubePos oldPos, CubePos newPos) {
710
741
});
711
742
getWorldServer ().profiler .endSection ();//removeColumns
712
743
getWorldServer ().profiler .endSection ();//updateMovedPlayer
744
+ setNeedSort ();
745
+ }
746
+
747
+ private void removePlayerFromCubeWatcher (CubeWatcher cubeWatcher , EntityPlayerMP playerEntity ) {
748
+ if (!cubeWatcher .containsPlayer (playerEntity )) {
749
+ WatchersSortingList <CubeWatcher > cubeWatchers = cubesToAddPlayerTo .get (playerEntity );
750
+ if (cubeWatchers != null ) {
751
+ cubeWatchers .remove (cubeWatcher );
752
+ }
753
+ }
754
+ cubeWatcher .removePlayer (playerEntity );
755
+ }
756
+
757
+ private void scheduleAddPlayerToWatcher (CubeWatcher cubeWatcher , EntityPlayerMP playerEntity ) {
758
+ cubesToAddPlayerTo .computeIfAbsent (playerEntity , p -> new WatchersSortingList <>(Comparator .comparingDouble (w -> {
759
+ double dx = w .getCubePos ().getXCenter () - playerEntity .posX ;
760
+ double dy = w .getCubePos ().getYCenter () - playerEntity .posY ;
761
+ double dz = w .getCubePos ().getZCenter () - playerEntity .posZ ;
762
+ return dx *dx + dy *dy + dz *dz ;
763
+ }))).appendToEnd (cubeWatcher );
713
764
}
714
765
715
766
// CHECKED: 1.10.2-12.18.1.2092
@@ -776,7 +827,7 @@ public final void setPlayerViewDistance(int newHorizontalViewDistance, int newVe
776
827
}
777
828
CubeWatcher cubeWatcher = this .getOrCreateCubeWatcher (pos );
778
829
if (!cubeWatcher .containsPlayer (player )) {
779
- cubeWatcher . addPlayer ( player );
830
+ scheduleAddPlayerToWatcher ( cubeWatcher , player );
780
831
}
781
832
});
782
833
// either both got smaller or only one of them changed
@@ -790,10 +841,10 @@ public final void setPlayerViewDistance(int newHorizontalViewDistance, int newVe
790
841
791
842
cubesToUnload .forEach (pos -> {
792
843
CubeWatcher cubeWatcher = this .getCubeWatcher (pos );
793
- if (cubeWatcher != null && cubeWatcher . containsPlayer ( player ) ) {
794
- cubeWatcher . removePlayer ( player );
844
+ if (cubeWatcher != null ) {
845
+ removePlayerFromCubeWatcher ( cubeWatcher , player );
795
846
} else {
796
- CubicChunks .LOGGER .warn ("cubeWatcher null or doesn't contain player on render distance change" );
847
+ CubicChunks .LOGGER .warn ("cubeWatcher null on render distance change" );
797
848
}
798
849
});
799
850
columnsToUnload .forEach (pos -> {
@@ -837,6 +888,14 @@ void addToUpdateEntry(ColumnWatcher columnWatcher) {
837
888
838
889
// CHECKED: 1.10.2-12.18.1.2092
839
890
void removeEntry (CubeWatcher cubeWatcher ) {
891
+ if (!cubesToAddPlayerTo .isEmpty ()) {
892
+ for (WatchersSortingList <CubeWatcher > value : cubesToAddPlayerTo .values ()) {
893
+ if (value .contains (cubeWatcher )) {
894
+ return ;
895
+ }
896
+ }
897
+ }
898
+ cubeWatcher .invalidate ();
840
899
CubePos cubePos = cubeWatcher .getCubePos ();
841
900
cubeWatcher .updateInhabitedTime ();
842
901
CubeWatcher removed = this .cubeWatchers .remove (cubePos .getX (), cubePos .getY (), cubePos .getZ ());
@@ -847,6 +906,15 @@ void removeEntry(CubeWatcher cubeWatcher) {
847
906
if (cubeWatcher .getCube () != null ) {
848
907
cubeWatcher .getCube ().getTickets ().remove (cubeWatcher ); // remove the ticket, so this Cube can unload
849
908
}
909
+ if (!cubesToAddPlayerTo .isEmpty ()) {
910
+ for (Iterator <WatchersSortingList <CubeWatcher >> iterator = cubesToAddPlayerTo .values ().iterator (); iterator .hasNext (); ) {
911
+ WatchersSortingList <CubeWatcher > value = iterator .next ();
912
+ value .remove (cubeWatcher );
913
+ if (value .isEmpty ()) {
914
+ iterator .remove ();
915
+ }
916
+ }
917
+ }
850
918
//don't unload, ChunkGc unloads chunks
851
919
}
852
920
0 commit comments