Add logging/messaging for corrupted DB files

This commit is contained in:
James Seibel
2025-12-09 07:12:33 -06:00
parent 5ca754d2ac
commit 26d4220967
26 changed files with 171 additions and 78 deletions
@@ -47,6 +47,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.*; import java.util.*;
import java.util.concurrent.*; import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
@@ -80,8 +82,8 @@ public class GeneratedFullDataSourceProvider extends FullDataSourceProviderV2 im
// constructor // // constructor //
//=============// //=============//
public GeneratedFullDataSourceProvider(IDhLevel level, ISaveStructure saveStructure) { super(level, saveStructure); } public GeneratedFullDataSourceProvider(IDhLevel level, ISaveStructure saveStructure) throws SQLException, IOException { super(level, saveStructure); }
public GeneratedFullDataSourceProvider(IDhLevel level, ISaveStructure saveStructure, @Nullable File saveDirOverride) public GeneratedFullDataSourceProvider(IDhLevel level, ISaveStructure saveStructure, @Nullable File saveDirOverride) throws SQLException, IOException
{ {
super(level, saveStructure, saveDirOverride); super(level, saveStructure, saveDirOverride);
@@ -31,6 +31,8 @@ import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Collections; import java.util.Collections;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@@ -58,7 +60,8 @@ public class RemoteFullDataSourceProvider extends GeneratedFullDataSourceProvide
public RemoteFullDataSourceProvider( public RemoteFullDataSourceProvider(
IDhLevel level, ISaveStructure saveStructure, @Nullable File saveDirOverride, IDhLevel level, ISaveStructure saveStructure, @Nullable File saveDirOverride,
@Nullable SyncOnLoadRequestQueue syncOnLoadRequestQueue) @Nullable SyncOnLoadRequestQueue syncOnLoadRequestQueue
) throws SQLException, IOException
{ {
super(level, saveStructure, saveDirOverride); super(level, saveStructure, saveDirOverride);
this.syncOnLoadRequestQueue = syncOnLoadRequestQueue; this.syncOnLoadRequestQueue = syncOnLoadRequestQueue;
@@ -43,7 +43,7 @@ public class FullDataSourceProviderV1<TDhLevel extends IDhLevel>
// constructor // // constructor //
//=============// //=============//
public FullDataSourceProviderV1(TDhLevel level, File saveDir) public FullDataSourceProviderV1(TDhLevel level, File saveDir) throws SQLException, IOException
{ {
this.level = level; this.level = level;
this.saveDir = saveDir; this.saveDir = saveDir;
@@ -52,7 +52,7 @@ public class FullDataSourceProviderV1<TDhLevel extends IDhLevel>
LOGGER.warn("Unable to create full data folder, file saving may fail."); LOGGER.warn("Unable to create full data folder, file saving may fail.");
} }
this.repo = this.createRepo(); this.repo = new FullDataSourceV1Repo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, new File(this.saveDir.getPath() + File.separator + ISaveStructure.DATABASE_NAME));
} }
@@ -61,21 +61,6 @@ public class FullDataSourceProviderV1<TDhLevel extends IDhLevel>
// abstract methods // // abstract methods //
//==================// //==================//
/** When this is called the parent folders should be created */
protected FullDataSourceV1Repo createRepo()
{
try
{
return new FullDataSourceV1Repo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, new File(this.saveDir.getPath() + File.separator + ISaveStructure.DATABASE_NAME));
}
catch (SQLException e)
{
// should only happen if there is an issue with the database (it's locked or can't be created if missing)
// or the database update failed
throw new RuntimeException(e);
}
}
protected FullDataSourceV1 createDataSourceFromDto(FullDataSourceV1DTO dto) throws InterruptedException, IOException, DataCorruptedException protected FullDataSourceV1 createDataSourceFromDto(FullDataSourceV1DTO dto) throws InterruptedException, IOException, DataCorruptedException
{ {
FullDataSourceV1 dataSource = FullDataSourceV1.createEmpty(dto.pos); FullDataSourceV1 dataSource = FullDataSourceV1.createEmpty(dto.pos);
@@ -14,6 +14,8 @@ import com.seibel.distanthorizons.core.render.renderer.IDebugRenderable;
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil; import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.text.NumberFormat; import java.text.NumberFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -62,7 +64,8 @@ public class DataMigratorV1 implements IDebugRenderable, AutoCloseable
public DataMigratorV1( public DataMigratorV1(
FullDataUpdaterV2 dataUpdater, FullDataUpdaterV2 dataUpdater,
IDhLevel level, String levelId, File saveDir) IDhLevel level, String levelId, File saveDir
) throws SQLException, IOException
{ {
this.dataUpdater = dataUpdater; this.dataUpdater = dataUpdater;
this.saveDir = saveDir; this.saveDir = saveDir;
@@ -96,11 +96,11 @@ public class FullDataSourceProviderV2 implements IDebugRenderable, AutoCloseable
// constructor // // constructor //
//=============// //=============//
public FullDataSourceProviderV2(IDhLevel level, ISaveStructure saveStructure) { this(level, saveStructure, null); } public FullDataSourceProviderV2(IDhLevel level, ISaveStructure saveStructure) throws SQLException, IOException { this(level, saveStructure, null); }
public FullDataSourceProviderV2(IDhLevel level, ISaveStructure saveStructure, @Nullable File saveDirOverride) public FullDataSourceProviderV2(IDhLevel level, ISaveStructure saveStructure, @Nullable File saveDirOverride) throws SQLException, IOException
{ {
this.saveDir = (saveDirOverride == null) ? saveStructure.getSaveFolder(level.getLevelWrapper()) : saveDirOverride; this.saveDir = (saveDirOverride == null) ? saveStructure.getSaveFolder(level.getLevelWrapper()) : saveDirOverride;
this.repo = this.createRepo(); this.repo = new FullDataSourceV2Repo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, new File(this.saveDir.getPath() + File.separator + ISaveStructure.DATABASE_NAME));
this.level = level; this.level = level;
this.levelId = this.level.getLevelWrapper().getDhIdentifier(); this.levelId = this.level.getLevelWrapper().getDhIdentifier();
@@ -112,19 +112,6 @@ public class FullDataSourceProviderV2 implements IDebugRenderable, AutoCloseable
DebugRenderer.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showFullDataUpdateStatus); DebugRenderer.register(this, Config.Client.Advanced.Debugging.DebugWireframe.showFullDataUpdateStatus);
} }
private FullDataSourceV2Repo createRepo()
{
try
{
return new FullDataSourceV2Repo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, new File(this.saveDir.getPath() + File.separator + ISaveStructure.DATABASE_NAME));
}
catch (SQLException e)
{
// should only happen if there is an issue with the database (it's locked or the folder path is missing)
// or the database update failed
throw new RuntimeException(e);
}
}
@@ -239,7 +226,27 @@ public class FullDataSourceProviderV2 implements IDebugRenderable, AutoCloseable
catch (InterruptedException ignore) { } catch (InterruptedException ignore) { }
catch (IOException e) catch (IOException e)
{ {
LOGGER.warn("File read Error for pos ["+DhSectionPos.toString(pos)+"], error: "+e.getMessage(), e); String message = e.getMessage();
if (CORRUPT_DATA_ERRORS_LOGGED.add(message))
{
LOGGER.warn("File read Error for pos [" + DhSectionPos.toString(pos) + "], this error message will only be logged once, error: [" + message + "].", e);
}
}
catch (IllegalStateException e)
{
String message = e.getMessage();
if (CORRUPT_DATA_ERRORS_LOGGED.add(message))
{
LOGGER.warn("Incorrectly formatted data for: [" + DhSectionPos.toString(pos) + "], this error message will only be logged once, error: [" + message + "].", e);
}
}
catch (Exception e)
{
String message = e.getMessage();
if (CORRUPT_DATA_ERRORS_LOGGED.add(message))
{
LOGGER.warn("Unexpected error getting: [" + DhSectionPos.toString(pos) + "], this error message will only be logged once, error: [" + message + "].", e);
}
} }
// an error occurred // an error occurred
@@ -216,7 +216,7 @@ public class JarMain
{ {
repo = new FullDataSourceV2Repo(FullDataSourceV2Repo.DEFAULT_DATABASE_TYPE, dbFile); repo = new FullDataSourceV2Repo(FullDataSourceV2Repo.DEFAULT_DATABASE_TYPE, dbFile);
} }
catch (SQLException e) catch (SQLException | IOException e)
{ {
LOGGER.error("Failed to initialize connection with database: ["+exportFile.getAbsolutePath()+"], error: ["+e.getMessage()+"].", e); LOGGER.error("Failed to initialize connection with database: ["+exportFile.getAbsolutePath()+"], error: ["+e.getMessage()+"].", e);
return; return;
@@ -55,6 +55,7 @@ import org.jetbrains.annotations.Nullable;
import java.awt.*; import java.awt.*;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
@@ -106,9 +107,9 @@ public abstract class AbstractDhLevel implements IDhLevel
{ {
newChunkHashRepo = new ChunkHashRepo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, databaseFile); newChunkHashRepo = new ChunkHashRepo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, databaseFile);
} }
catch (SQLException e) catch (SQLException | IOException e)
{ {
LOGGER.error("Unable to create [ChunkHashRepo], error: ["+e.getMessage()+"].", e); LOGGER.fatal("Unable to create ["+ChunkHashRepo.class.getSimpleName()+"], error: ["+e.getMessage()+"].", e);
} }
this.chunkHashRepo = newChunkHashRepo; this.chunkHashRepo = newChunkHashRepo;
@@ -119,9 +120,9 @@ public abstract class AbstractDhLevel implements IDhLevel
{ {
newBeaconBeamRepo = new BeaconBeamRepo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, databaseFile); newBeaconBeamRepo = new BeaconBeamRepo(AbstractDhRepo.DEFAULT_DATABASE_TYPE, databaseFile);
} }
catch (SQLException e) catch (SQLException | IOException e)
{ {
LOGGER.error("Unable to create [BeaconBeamRepo], error: ["+e.getMessage()+"].", e); LOGGER.error("Unable to create ["+BeaconBeamRepo.class.getSimpleName()+"], error: ["+e.getMessage()+"].", e);
} }
this.beaconBeamRepo = newBeaconBeamRepo; this.beaconBeamRepo = newBeaconBeamRepo;
} }
@@ -29,6 +29,8 @@ import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List; import java.util.List;
import java.util.concurrent.*; import java.util.concurrent.*;
@@ -56,16 +58,19 @@ public abstract class AbstractDhServerLevel extends AbstractDhLevel implements I
// constructor // // constructor //
//=============// //=============//
public AbstractDhServerLevel(ISaveStructure saveStructure, IServerLevelWrapper serverLevelWrapper, ServerPlayerStateManager serverPlayerStateManager) public AbstractDhServerLevel(
{ ISaveStructure saveStructure,
this(saveStructure, serverLevelWrapper, serverPlayerStateManager, true); IServerLevelWrapper serverLevelWrapper,
} ServerPlayerStateManager serverPlayerStateManager
) throws SQLException, IOException
{ this(saveStructure, serverLevelWrapper, serverPlayerStateManager, true); }
public AbstractDhServerLevel( public AbstractDhServerLevel(
ISaveStructure saveStructure, ISaveStructure saveStructure,
IServerLevelWrapper serverLevelWrapper, IServerLevelWrapper serverLevelWrapper,
ServerPlayerStateManager serverPlayerStateManager, ServerPlayerStateManager serverPlayerStateManager,
boolean runRepoReliantSetup boolean runRepoReliantSetup
) ) throws SQLException, IOException
{ {
if (saveStructure.getSaveFolder(serverLevelWrapper).mkdirs()) if (saveStructure.getSaveFolder(serverLevelWrapper).mkdirs())
{ {
@@ -49,6 +49,8 @@ import org.jetbrains.annotations.Nullable;
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;
import java.awt.*; import java.awt.*;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.sql.SQLException;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -94,9 +96,18 @@ public class DhClientLevel extends AbstractDhLevel implements IDhClientLevel
// constructor // // constructor //
//=============// //=============//
public DhClientLevel(ISaveStructure saveStructure, IClientLevelWrapper clientLevelWrapper, @Nullable ClientNetworkState networkState) public DhClientLevel(
ISaveStructure saveStructure,
IClientLevelWrapper clientLevelWrapper,
@Nullable ClientNetworkState networkState
) throws SQLException, IOException
{ this(saveStructure, clientLevelWrapper, null, networkState); } { this(saveStructure, clientLevelWrapper, null, networkState); }
public DhClientLevel(ISaveStructure saveStructure, IClientLevelWrapper clientLevelWrapper, @Nullable File fullDataSaveDirOverride, @Nullable ClientNetworkState networkState) public DhClientLevel(
ISaveStructure saveStructure,
IClientLevelWrapper clientLevelWrapper,
@Nullable File fullDataSaveDirOverride,
@Nullable ClientNetworkState networkState
) throws SQLException, IOException
{ {
File saveFolder = saveStructure.getSaveFolder(clientLevelWrapper); File saveFolder = saveStructure.getSaveFolder(clientLevelWrapper);
File pre23Folder = saveStructure.getPre23SaveFolder(clientLevelWrapper); File pre23Folder = saveStructure.getPre23SaveFolder(clientLevelWrapper);
@@ -33,6 +33,8 @@ import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapp
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.awt.*; import java.awt.*;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List; import java.util.List;
/** The level used for a singleplayer world */ /** The level used for a singleplayer world */
@@ -48,7 +50,11 @@ public class DhClientServerLevel extends AbstractDhServerLevel implements IDhCli
// constructor // // constructor //
//=============// //=============//
public DhClientServerLevel(ISaveStructure saveStructure, IServerLevelWrapper serverLevelWrapper, ServerPlayerStateManager serverPlayerStateManager) public DhClientServerLevel(
ISaveStructure saveStructure,
IServerLevelWrapper serverLevelWrapper,
ServerPlayerStateManager serverPlayerStateManager
) throws SQLException, IOException
{ {
super(saveStructure, serverLevelWrapper, serverPlayerStateManager, false); super(saveStructure, serverLevelWrapper, serverPlayerStateManager, false);
@@ -27,6 +27,8 @@ import com.seibel.distanthorizons.core.render.renderer.generic.GenericObjectRend
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.sql.SQLException;
import java.util.List; import java.util.List;
public class DhServerLevel extends AbstractDhServerLevel public class DhServerLevel extends AbstractDhServerLevel
@@ -35,10 +37,12 @@ public class DhServerLevel extends AbstractDhServerLevel
// constructor // // constructor //
//=============// //=============//
public DhServerLevel(ISaveStructure saveStructure, IServerLevelWrapper serverLevelWrapper, ServerPlayerStateManager serverPlayerStateManager) public DhServerLevel(
{ ISaveStructure saveStructure,
super(saveStructure, serverLevelWrapper, serverPlayerStateManager); IServerLevelWrapper serverLevelWrapper,
} ServerPlayerStateManager serverPlayerStateManager
) throws SQLException, IOException
{ super(saveStructure, serverLevelWrapper, serverPlayerStateManager); }
@@ -28,6 +28,9 @@ import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
import com.seibel.distanthorizons.coreapi.DependencyInjection.WorldGeneratorInjector; import com.seibel.distanthorizons.coreapi.DependencyInjection.WorldGeneratorInjector;
import com.seibel.distanthorizons.core.logging.DhLogger; import com.seibel.distanthorizons.core.logging.DhLogger;
import java.io.IOException;
import java.sql.SQLException;
public class ServerLevelModule implements AutoCloseable public class ServerLevelModule implements AutoCloseable
{ {
private static final DhLogger LOGGER = new DhLoggerBuilder().build(); private static final DhLogger LOGGER = new DhLoggerBuilder().build();
@@ -44,7 +47,7 @@ public class ServerLevelModule implements AutoCloseable
// constructor // // constructor //
//=============// //=============//
public ServerLevelModule(IDhServerLevel parentServerLevel, ISaveStructure saveStructure) public ServerLevelModule(IDhServerLevel parentServerLevel, ISaveStructure saveStructure) throws SQLException, IOException
{ {
this.parentServerLevel = parentServerLevel; this.parentServerLevel = parentServerLevel;
this.saveStructure = saveStructure; this.saveStructure = saveStructure;
@@ -75,7 +75,7 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
//=============// //=============//
/** @throws SQLException if the repo is unable to access the database or has trouble updating said database. */ /** @throws SQLException if the repo is unable to access the database or has trouble updating said database. */
public AbstractDhRepo(String databaseType, File databaseFile, Class<? extends TDTO> dtoClass) throws SQLException public AbstractDhRepo(String databaseType, File databaseFile, Class<? extends TDTO> dtoClass) throws SQLException, IOException
{ {
this.databaseType = databaseType; this.databaseType = databaseType;
this.databaseFile = databaseFile; this.databaseFile = databaseFile;
@@ -107,7 +107,7 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
{ {
if (!parentFolder.mkdirs()) if (!parentFolder.mkdirs())
{ {
throw new RuntimeException("Unable to create the necessary parent folders for the database file at location ["+databaseFile.getPath()+"]."); throw new IOException("Unable to create the necessary parent folders for the database file at location ["+databaseFile.getPath()+"].");
} }
} }
@@ -119,18 +119,18 @@ public abstract class AbstractDhRepo<TKey, TDTO extends IBaseDTO<TKey>> implemen
} }
catch (IOException e) catch (IOException e)
{ {
throw new RuntimeException("Unable to create database file at location ["+databaseFile.getPath()+"] due to error: ["+e.getMessage()+"]", e); throw new IOException("Unable to create database file at location ["+databaseFile.getPath()+"] due to error: ["+e.getMessage()+"]", e);
} }
} }
} }
if (!databaseFile.canRead()) if (!databaseFile.canRead())
{ {
throw new RuntimeException("Unable to read database file at location ["+databaseFile.getPath()+"], please make sure the folder and file has the correct permissions."); throw new IOException("Unable to read database file at location ["+databaseFile.getPath()+"], please make sure the folder and file has the correct permissions.");
} }
if (!databaseFile.canWrite()) if (!databaseFile.canWrite())
{ {
throw new RuntimeException("Unable to write database file at location ["+databaseFile.getPath()+"], please make sure the folder and file aren't set to read-only."); throw new IOException("Unable to write database file at location ["+databaseFile.getPath()+"], please make sure the folder and file aren't set to read-only.");
} }
@@ -31,6 +31,7 @@ import org.jetbrains.annotations.Nullable;
import java.awt.*; import java.awt.*;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -47,7 +48,7 @@ public class BeaconBeamRepo extends AbstractDhRepo<DhBlockPos, BeaconBeamDTO>
// constructor // // constructor //
//=============// //=============//
public BeaconBeamRepo(String databaseType, File databaseFile) throws SQLException public BeaconBeamRepo(String databaseType, File databaseFile) throws SQLException, IOException
{ {
super(databaseType, databaseFile, BeaconBeamDTO.class); super(databaseType, databaseFile, BeaconBeamDTO.class);
} }
@@ -26,6 +26,7 @@ import com.seibel.distanthorizons.core.logging.DhLogger;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -40,7 +41,7 @@ public class ChunkHashRepo extends AbstractDhRepo<DhChunkPos, ChunkHashDTO>
// constructor // // constructor //
//=============// //=============//
public ChunkHashRepo(String databaseType, File databaseFile) throws SQLException public ChunkHashRepo(String databaseType, File databaseFile) throws SQLException, IOException
{ {
super(databaseType, databaseFile, ChunkHashDTO.class); super(databaseType, databaseFile, ChunkHashDTO.class);
} }
@@ -28,6 +28,7 @@ import it.unimi.dsi.fastutil.longs.LongArrayList;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -45,7 +46,7 @@ public class FullDataSourceV1Repo extends AbstractDhRepo<Long, FullDataSourceV1D
// constructor // // constructor //
//=============// //=============//
public FullDataSourceV1Repo(String databaseType, File databaseFile) throws SQLException public FullDataSourceV1Repo(String databaseType, File databaseFile) throws SQLException, IOException
{ {
super(databaseType, databaseFile, FullDataSourceV1DTO.class); super(databaseType, databaseFile, FullDataSourceV1DTO.class);
} }
@@ -51,7 +51,7 @@ public class FullDataSourceV2Repo extends AbstractDhRepo<Long, FullDataSourceV2D
// constructor // // constructor //
//=============// //=============//
public FullDataSourceV2Repo(String databaseType, File databaseFile) throws SQLException public FullDataSourceV2Repo(String databaseType, File databaseFile) throws SQLException, IOException
{ {
super(databaseType, databaseFile, FullDataSourceV2DTO.class); super(databaseType, databaseFile, FullDataSourceV2DTO.class);
} }
@@ -54,7 +54,13 @@ public abstract class AbstractDhServerWorld<TDhServerLevel extends AbstractDhSer
public void addPlayer(IServerPlayerWrapper serverPlayer) public void addPlayer(IServerPlayerWrapper serverPlayer)
{ {
ServerPlayerState playerState = this.serverPlayerStateManager.registerJoinedPlayer(serverPlayer); ServerPlayerState playerState = this.serverPlayerStateManager.registerJoinedPlayer(serverPlayer);
((TDhServerLevel) this.getOrLoadServerLevel(serverPlayer.getLevel())).addPlayer(serverPlayer); AbstractDhServerLevel serverLevel = (AbstractDhServerLevel) this.getOrLoadServerLevel(serverPlayer.getLevel());
if (serverLevel == null)
{
return;
}
serverLevel.addPlayer(serverPlayer);
Iterator<TDhServerLevel> it = this.dhLevelByLevelWrapper.values().stream().distinct().iterator(); Iterator<TDhServerLevel> it = this.dhLevelByLevelWrapper.values().stream().distinct().iterator();
while (it.hasNext()) while (it.hasNext())
@@ -19,6 +19,7 @@
package com.seibel.distanthorizons.core.world; package com.seibel.distanthorizons.core.world;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.level.DhClientServerLevel; import com.seibel.distanthorizons.core.level.DhClientServerLevel;
import com.seibel.distanthorizons.core.util.ThreadUtil; import com.seibel.distanthorizons.core.util.ThreadUtil;
import com.seibel.distanthorizons.core.util.objects.EventLoop; import com.seibel.distanthorizons.core.util.objects.EventLoop;
@@ -66,10 +67,23 @@ public class DhClientServerWorld extends AbstractDhServerWorld<DhClientServerLev
if (wrapper instanceof IServerLevelWrapper) if (wrapper instanceof IServerLevelWrapper)
{ {
return this.dhLevelByLevelWrapper.computeIfAbsent(wrapper, (levelWrapper) -> return this.dhLevelByLevelWrapper.computeIfAbsent(wrapper, (levelWrapper) ->
{
try
{ {
DhClientServerLevel level = new DhClientServerLevel(this.saveStructure, (IServerLevelWrapper) levelWrapper, this.getServerPlayerStateManager()); DhClientServerLevel level = new DhClientServerLevel(this.saveStructure, (IServerLevelWrapper) levelWrapper, this.getServerPlayerStateManager());
this.dhLevels.add(level); this.dhLevels.add(level);
return level; return level;
}
catch (Exception e)
{
LOGGER.fatal("Failed to load client-server level, error: ["+e.getMessage()+"].", e);
ClientApi.INSTANCE.showChatMessageNextFrame(// red text
"\u00A7c" + "Distant Horizons: ClientServer level loading failed." + "\u00A7r \n" +
"Unable to load level ["+levelWrapper.getDhIdentifier()+"], LODs may not appear. See log for more information.");
return null;
}
}); });
} }
else else
@@ -19,6 +19,7 @@
package com.seibel.distanthorizons.core.world; package com.seibel.distanthorizons.core.world;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure; import com.seibel.distanthorizons.core.file.structure.ClientOnlySaveStructure;
import com.seibel.distanthorizons.core.level.DhClientLevel; import com.seibel.distanthorizons.core.level.DhClientLevel;
import com.seibel.distanthorizons.core.level.IDhLevel; import com.seibel.distanthorizons.core.level.IDhLevel;
@@ -75,7 +76,23 @@ public class DhClientWorld extends AbstractDhWorld implements IDhClientWorld
} }
return this.levels.computeIfAbsent((IClientLevelWrapper) wrapper, return this.levels.computeIfAbsent((IClientLevelWrapper) wrapper,
(clientLevelWrapper) -> new DhClientLevel(this.saveStructure, clientLevelWrapper, this.networkState)); (clientLevelWrapper) ->
{
try
{
return new DhClientLevel(this.saveStructure, clientLevelWrapper, this.networkState);
}
catch (Exception e)
{
LOGGER.fatal("Failed to load client level, error: ["+e.getMessage()+"].", e);
ClientApi.INSTANCE.showChatMessageNextFrame(// red text
"\u00A7c" + "Distant Horizons: Client level loading failed." + "\u00A7r \n" +
"Unable to load level ["+clientLevelWrapper.getDhIdentifier()+"], LODs may not appear. See log for more information.");
return null;
}
});
} }
@Override @Override
@@ -19,6 +19,7 @@
package com.seibel.distanthorizons.core.world; package com.seibel.distanthorizons.core.world;
import com.seibel.distanthorizons.core.api.internal.ClientApi;
import com.seibel.distanthorizons.core.level.DhServerLevel; import com.seibel.distanthorizons.core.level.DhServerLevel;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
@@ -51,7 +52,23 @@ public class DhServerWorld extends AbstractDhServerWorld<DhServerLevel>
} }
return this.dhLevelByLevelWrapper.computeIfAbsent(wrapper, return this.dhLevelByLevelWrapper.computeIfAbsent(wrapper,
(serverLevelWrapper) -> new DhServerLevel(this.saveStructure, (IServerLevelWrapper) serverLevelWrapper, this.getServerPlayerStateManager())); (serverLevelWrapper) ->
{
try
{
return new DhServerLevel(this.saveStructure, (IServerLevelWrapper) serverLevelWrapper, this.getServerPlayerStateManager());
}
catch (Exception e)
{
LOGGER.fatal("Failed to load server level, error: ["+e.getMessage()+"].", e);
ClientApi.INSTANCE.showChatMessageNextFrame(// red text
"\u00A7c" + "Distant Horizons: Server level loading failed." + "\u00A7r \n" +
"Unable to load level ["+serverLevelWrapper.getDhIdentifier()+"], LODs may not appear. See log for more information.");
return null;
}
});
} }
@Override @Override
@@ -24,6 +24,7 @@ import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerStateManag
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper; import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
import org.jetbrains.annotations.Nullable;
/** Used both for dedicated server and singleplayer worlds */ /** Used both for dedicated server and singleplayer worlds */
public interface IDhServerWorld extends IDhWorld public interface IDhServerWorld extends IDhWorld
@@ -33,6 +34,7 @@ public interface IDhServerWorld extends IDhWorld
void removePlayer(IServerPlayerWrapper serverPlayer); void removePlayer(IServerPlayerWrapper serverPlayer);
void changePlayerLevel(IServerPlayerWrapper player, IServerLevelWrapper originLevel, IServerLevelWrapper destinationLevel); void changePlayerLevel(IServerPlayerWrapper player, IServerLevelWrapper originLevel, IServerLevelWrapper destinationLevel);
@Nullable
default IDhServerLevel getOrLoadServerLevel(ILevelWrapper levelWrapper) { return (IDhServerLevel) this.getOrLoadLevel(levelWrapper); } default IDhServerLevel getOrLoadServerLevel(ILevelWrapper levelWrapper) { return (IDhServerLevel) this.getOrLoadLevel(levelWrapper); }
} }
@@ -31,6 +31,7 @@ import java.util.concurrent.CompletableFuture;
public interface IDhWorld extends Closeable public interface IDhWorld extends Closeable
{ {
@Nullable
IDhLevel getOrLoadLevel(@NotNull ILevelWrapper levelWrapper); IDhLevel getOrLoadLevel(@NotNull ILevelWrapper levelWrapper);
@Nullable @Nullable
IDhLevel getLevel(@NotNull ILevelWrapper wrapper); IDhLevel getLevel(@NotNull ILevelWrapper wrapper);
@@ -25,6 +25,7 @@ import com.seibel.distanthorizons.core.sql.repo.AbstractDhRepo;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -33,7 +34,7 @@ import java.util.Map;
public class TestCompoundKeyRepo extends AbstractDhRepo<DhChunkPos, TestCompoundKeyDto> public class TestCompoundKeyRepo extends AbstractDhRepo<DhChunkPos, TestCompoundKeyDto>
{ {
public TestCompoundKeyRepo(String databaseType, File databaseFile) throws SQLException public TestCompoundKeyRepo(String databaseType, File databaseFile) throws SQLException, IOException
{ {
super(databaseType, databaseFile, TestCompoundKeyDto.class); super(databaseType, databaseFile, TestCompoundKeyDto.class);
@@ -24,6 +24,7 @@ import com.seibel.distanthorizons.core.sql.repo.AbstractDhRepo;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -32,7 +33,7 @@ import java.util.Map;
public class TestPrimaryKeyRepo extends AbstractDhRepo<Integer, TestSingleKeyDto> public class TestPrimaryKeyRepo extends AbstractDhRepo<Integer, TestSingleKeyDto>
{ {
public TestPrimaryKeyRepo(String databaseType, File databaseFile) throws SQLException public TestPrimaryKeyRepo(String databaseType, File databaseFile) throws SQLException, IOException
{ {
super(databaseType, databaseFile, TestSingleKeyDto.class); super(databaseType, databaseFile, TestSingleKeyDto.class);
@@ -34,6 +34,7 @@ import testItems.sql.TestPrimaryKeyRepo;
import testItems.sql.TestSingleKeyDto; import testItems.sql.TestSingleKeyDto;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -137,7 +138,7 @@ public class DhRepoSqliteTest
Assert.assertFalse("DTO exists failed", primaryKeyRepo.existsWithKey(insertDto.getKey())); Assert.assertFalse("DTO exists failed", primaryKeyRepo.existsWithKey(insertDto.getKey()));
} }
catch (SQLException e) catch (SQLException | IOException e)
{ {
Assert.fail(e.getMessage()); Assert.fail(e.getMessage());
} }
@@ -200,7 +201,7 @@ public class DhRepoSqliteTest
Assert.assertFalse("DTO exists failed", compoundKeyRepo.existsWithKey(insertDto.getKey())); Assert.assertFalse("DTO exists failed", compoundKeyRepo.existsWithKey(insertDto.getKey()));
} }
catch (SQLException e) catch (SQLException | IOException e)
{ {
Assert.fail(e.getMessage()); Assert.fail(e.getMessage());
} }
@@ -330,7 +331,7 @@ public class DhRepoSqliteTest
Assert.assertNotEquals(0, primaryKeyRepo.openClosables.size()); Assert.assertNotEquals(0, primaryKeyRepo.openClosables.size());
} }
} }
catch (SQLException e) catch (SQLException | IOException e)
{ {
Assert.fail(e.getMessage()); Assert.fail(e.getMessage());
} }
@@ -367,7 +368,7 @@ public class DhRepoSqliteTest
long endMs = System.currentTimeMillis(); long endMs = System.currentTimeMillis();
System.out.println("Bulk update took ["+(endMs - startMs)+"] ms"); System.out.println("Bulk update took ["+(endMs - startMs)+"] ms");
} }
catch (SQLException e) catch (SQLException | IOException e)
{ {
Assert.fail(e.getMessage()); Assert.fail(e.getMessage());
} }