3636
3737import java .io .IOException ;
3838import java .io .InputStream ;
39+ import java .util .HashMap ;
3940import java .util .List ;
4041import java .util .Map ;
4142import java .util .concurrent .ConcurrentHashMap ;
@@ -99,10 +100,22 @@ public void removeTileUpdateListener(BiConsumer<Vector2i, Integer> listener) {
99100 }
100101
101102 public synchronized void save () {
102- pendingChanges .entrySet ().removeIf (entry -> saveTile (entry .getKey (), entry .getValue ()));
103- if (pendingChanges .size () >= DISCARD_THRESHOLD ) {
104- Logger .global .logDebug ("Discarding changes of " + pendingChanges .size () + " lowres-tiles that failed to save!" );
105- pendingChanges .clear ();
103+ Map <Vector2i , LowresTile > failed = new HashMap <>();
104+
105+ // save tiles and remember which tiles are not saved
106+ pendingChanges .forEach ((pos , tile ) -> {
107+ if (!saveTile (pos , tile )) failed .put (pos , tile );
108+ });
109+
110+ // if there is more than DISCARD_THRESHOLD failed saves, drop them
111+ if (failed .size () >= DISCARD_THRESHOLD ) {
112+ Logger .global .logDebug ("Discarding changes of " + failed .size () + " lowres-tiles that failed to save!" );
113+ failed .forEach (pendingChanges ::remove );
114+ }
115+
116+ // atomically test every tile if it is modified and remove it if it is not
117+ for (Vector2i pos : pendingChanges .keySet ()) {
118+ pendingChanges .computeIfPresent (pos , (_ , tile ) -> tile .isModified () ? tile : null );
106119 }
107120 }
108121
@@ -124,6 +137,7 @@ private LowresTile createTile(Vector2i tilePos) {
124137 }
125138
126139 private boolean saveTile (Vector2i tilePos , LowresTile tile ) {
140+ if (!tile .isModified ()) return true ;
127141
128142 // check if storage is closed
129143 if (storage .isClosed ()){
@@ -134,7 +148,8 @@ private boolean saveTile(Vector2i tilePos, LowresTile tile) {
134148 // save the tile
135149 try {
136150 storage .write (tilePos .getX (), tilePos .getY (), tile ::save );
137- } catch (IOException e ) {
151+ } catch (Exception e ) {
152+ tile .markModified ();
138153 Logger .global .logError ("Failed to save tile " + tilePos + " (lod: " + lod + ")" , e );
139154 return false ;
140155 }
@@ -193,35 +208,31 @@ private boolean saveTile(Vector2i tilePos, LowresTile tile) {
193208 return true ;
194209 }
195210
196- private LowresTile accessTile (int x , int z ) {
197- Vector2i tilePos = VECTOR_2_I_CACHE .get (x , z );
198- LowresTile tile = tileCache .get (tilePos );
199-
200- if (pendingChanges .size () >= MAX_PENDING ) save ();
201- pendingChanges .put (tilePos , tile );
202-
203- return tile ;
204- }
205-
206211 void set (int cellX , int cellZ , int pixelX , int pixelZ , Color color , int height , int blockLight ) {
207- accessTile (cellX , cellZ )
208- .set (pixelX , pixelZ , color , height , blockLight );
212+ setPixel (cellX , cellZ , pixelX , pixelZ , color , height , blockLight );
209213
210214 // for seamless edges
211215 if (pixelX == 0 ) {
212- accessTile (cellX - 1 , cellZ )
213- .set (tileGrid .getGridSize ().getX (), pixelZ , color , height , blockLight );
216+ setPixel (cellX - 1 , cellZ , tileGrid .getGridSize ().getX (), pixelZ , color , height , blockLight );
214217 }
215218
216219 if (pixelZ == 0 ) {
217- accessTile (cellX , cellZ - 1 )
218- .set (pixelX , tileGrid .getGridSize ().getY (), color , height , blockLight );
220+ setPixel (cellX , cellZ - 1 , pixelX , tileGrid .getGridSize ().getY (), color , height , blockLight );
219221 }
220222
221223 if (pixelX == 0 && pixelZ == 0 ) {
222- accessTile (cellX - 1 , cellZ - 1 )
223- .set (tileGrid .getGridSize ().getX (), tileGrid .getGridSize ().getY (), color , height , blockLight );
224+ setPixel (cellX - 1 , cellZ - 1 , tileGrid .getGridSize ().getX (), tileGrid .getGridSize ().getY (), color , height , blockLight );
224225 }
225226 }
226227
228+ private void setPixel (int cellX , int cellZ , int pixelX , int pixelZ , Color color , int height , int blockLight ) {
229+ Vector2i tilePos = VECTOR_2_I_CACHE .get (cellX , cellZ );
230+ LowresTile tile = tileCache .get (tilePos );
231+
232+ tile .set (pixelX , pixelZ , color , height , blockLight );
233+
234+ pendingChanges .put (tilePos , tile );
235+ if (pendingChanges .size () >= MAX_PENDING ) save ();
236+ }
237+
227238}
0 commit comments