Skip to content

Commit 35d7f3a

Browse files
committed
Fix several issues around sectioned world data i/o, bump neoforge version, bump version
Signed-off-by: HellFirePvP <7419378+HellFirePvP@users.noreply.github.com>
1 parent ed25151 commit 35d7f3a

7 files changed

Lines changed: 176 additions & 93 deletions

File tree

build.gradle

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,10 @@ tasks.withType(ProcessResources).configureEach {
8383
}
8484
}
8585

86-
// Example configuration to allow publishing using the maven-publish plugin
86+
java {
87+
withSourcesJar()
88+
}
89+
8790
publishing {
8891
publications {
8992
register('mavenJava', MavenPublication) {

gradle.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ neogradle.subsystems.parchment.mappingsVersion=2024.11.17
77

88
minecraft_version=1.21.1
99
minecraft_version_range=[1.21.1,1.22)
10-
neo_version=21.1.85
10+
neo_version=21.1.173
1111
neo_version_range=[21.1.0,)
1212
loader_version_range=[4,)
1313

1414
mod_id=observerlib
1515
mod_name=ObserverLib
1616
mod_license=GNU Lesser General Public License v3.0
17-
mod_version=1.9.0
17+
mod_version=1.10.1
1818
mod_group_id=hellfirepvp.observerlib
1919
mod_authors=HellFirePvP
2020
mod_description=Cached world structure and change monitoring library.

src/main/java/hellfirepvp/observerlib/common/data/CachedWorldData.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
public abstract class CachedWorldData<T extends CachedWorldData<T>> implements IWorldRelatedData<T> {
2121

2222
private final ReadWriteLock rwLock = new ReentrantReadWriteLock();
23-
protected final Random rand = new Random();
2423
private final WorldCacheDomain.SaveKey<T> key;
2524

2625
protected CachedWorldData(WorldCacheDomain.SaveKey<T> key) {
Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
package hellfirepvp.observerlib.common.data;
22

3+
import com.mojang.serialization.Codec;
4+
import net.minecraft.util.Tuple;
35
import net.minecraft.world.level.Level;
46

57
import java.io.File;
68
import java.io.IOException;
9+
import java.util.Optional;
10+
import java.util.function.BiFunction;
11+
import java.util.function.Function;
712

813
/**
914
* This class is part of the ObserverLib Mod
@@ -14,14 +19,23 @@
1419
*/
1520
public interface IWorldRelatedData<T extends IWorldRelatedData<T>> {
1621

17-
public WorldCacheDomain.SaveKey<T> getSaveKey();
22+
WorldCacheDomain.SaveKey<T> getSaveKey();
1823

19-
public abstract void markSaved();
24+
void markSaved();
2025

21-
default public void onLoad(Level world) {}
26+
default void onLoad(Level world) {}
2227

23-
public void writeAdditionalData(File saveDir, File backupDir) throws IOException;
28+
default void setLoader(FileLoader<?> loader) {}
2429

25-
public void readAdditionalData(File dir) throws IOException;
30+
void writeAdditionalData(File saveDir, File backupDir) throws IOException;
2631

32+
void readAdditionalData(File directory, FileLoader<?> fileLoader);
33+
34+
interface FileResolver {
35+
File resolveFile(File directory);
36+
}
37+
38+
interface FileLoader<F> {
39+
Optional<Tuple<F, File>> loadData(FileResolver resolver, Codec<F> codec);
40+
}
2741
}

src/main/java/hellfirepvp/observerlib/common/data/WorldCacheDomain.java

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package hellfirepvp.observerlib.common.data;
22

33
import com.google.common.io.Files;
4-
import com.mojang.datafixers.util.Pair;
54
import com.mojang.serialization.Codec;
6-
import com.mojang.serialization.DataResult;
75
import com.mojang.serialization.codecs.RecordCodecBuilder;
86
import hellfirepvp.observerlib.ObserverLib;
97
import net.minecraft.server.MinecraftServer;
@@ -142,23 +140,23 @@ public Codec<T> getInstanceCodec() {
142140
return instanceCodec;
143141
}
144142

145-
public T getNewInstance(SaveKey<T> key) {
146-
return instanceProvider.apply(key);
143+
public T newInstance() {
144+
return instanceProvider.apply(this);
147145
}
148146

149-
public File getSaveFile(File directory) {
150-
return directory.toPath().resolve(this.getIdentifier() + ".dat").toFile();
147+
public IWorldRelatedData.FileResolver saveFileResolver() {
148+
return directory -> directory.toPath().resolve(this.getIdentifier() + ".dat").toFile();
151149
}
152150

153151
public File createAndBackupSaveFile(File saveDir, File backupDir) throws IOException {
154-
return this.createAndBackupSaveFile(saveDir, backupDir, this::getSaveFile);
152+
return this.createAndBackupSaveFile(saveDir, backupDir, this.saveFileResolver());
155153
}
156154

157-
public File createAndBackupSaveFile(File saveDir, File backupDir, Function<File, File> fileResolver) throws IOException {
158-
File saveFile = fileResolver.apply(saveDir);
155+
public File createAndBackupSaveFile(File saveDir, File backupDir, IWorldRelatedData.FileResolver fileResolver) throws IOException {
156+
File saveFile = fileResolver.resolveFile(saveDir);
159157
if (saveFile.exists()) {
160158
try {
161-
Files.copy(saveFile, fileResolver.apply(backupDir));
159+
Files.copy(saveFile, fileResolver.resolveFile(backupDir));
162160
} catch (Exception exc) {
163161
ObserverLib.log.info("Copying '{}' 's actual file to its backup file failed!", this.getIdentifier());
164162
exc.printStackTrace();

src/main/java/hellfirepvp/observerlib/common/data/WorldCacheIOThread.java

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
import net.minecraft.nbt.Tag;
1111
import net.minecraft.resources.ResourceLocation;
1212
import net.minecraft.SharedConstants;
13+
import net.minecraft.util.Tuple;
1314
import net.minecraft.world.level.Level;
14-
import org.apache.commons.io.FileUtils;
1515

1616
import javax.annotation.Nonnull;
1717
import java.io.File;
1818
import java.io.IOException;
1919
import java.util.*;
20+
import java.util.function.BiFunction;
2021

2122
/**
2223
* This class is part of the ObserverLib Mod
@@ -155,56 +156,81 @@ private static <T extends IWorldRelatedData<T>> void writeDataToFile(IWorldRelat
155156
@Nonnull
156157
private static <T extends IWorldRelatedData<T>> T loadDataFromFile(WorldCacheDomain domain, ResourceLocation dimTypeName, WorldCacheDomain.SaveKey<T> key) {
157158
DirectorySet f = getDirectorySet(domain.getSaveDirectory(), dimTypeName, key);
158-
if (!f.getActualDirectory().exists() && !f.getBackupDirectory().exists()) {
159-
return key.getNewInstance(key);
160-
}
161-
ObserverLib.log.info("Load WorldRelatedData '" + key.getIdentifier() + "' for world " + dimTypeName);
162-
boolean errored = false;
163-
T data = null;
164-
try {
165-
if (f.getActualDirectory().exists()) {
166-
data = attemptLoad(key, f.getActualDirectory());
159+
IWorldRelatedData.FileLoader<T> loader = createLoadingContext(f, key);
160+
161+
ObserverLib.log.info("Loading WorldData {}/{} for level {}", key.getDomainName().getNamespace(), key.getIdentifier(), dimTypeName);
162+
T loaded = loader.loadData(key.saveFileResolver(), key.getInstanceCodec())
163+
.map(dataTpl -> {
164+
dataTpl.getA().readAdditionalData(dataTpl.getB().getParentFile(), loader);
165+
return dataTpl.getA();
166+
})
167+
.orElseGet(key::newInstance);
168+
ObserverLib.log.info("Loading WorldData {}/{} for level {} finished", key.getDomainName().getNamespace(), key.getIdentifier(), dimTypeName);
169+
return loaded;
170+
}
171+
172+
private static <F> IWorldRelatedData.FileLoader<F> createLoadingContext(DirectorySet dirSet, WorldCacheDomain.SaveKey<?> rootKey) {
173+
String rootName = rootKey.saveFileResolver().resolveFile(new File("/")).getAbsolutePath();
174+
return (fileResolver, codec) -> {
175+
if (!dirSet.getActualDirectory().exists() && !dirSet.getBackupDirectory().exists()) {
176+
return Optional.empty();
167177
}
168-
} catch (Exception exc) {
169-
ObserverLib.log.info("Loading worlddata '" + key.getIdentifier() + "' failed for its actual save. Attempting load from backup.");
170-
errored = true;
171-
}
172-
if(data == null) {
178+
// Resolve from root to get an idea of what's being loaded.
179+
String attemptName = fileResolver.resolveFile(new File("/")).getAbsolutePath();
180+
boolean isSaveRoot = attemptName.equals(rootName);
181+
182+
F data = null;
183+
File dataFile = null;
184+
185+
// Try load from actual fileset
173186
try {
174-
if (f.getBackupDirectory().exists()) {
175-
data = attemptLoad(key, f.getBackupDirectory());
187+
if (dirSet.getActualDirectory().exists()) {
188+
dataFile = fileResolver.resolveFile(dirSet.getActualDirectory());
189+
if (dataFile.exists()) {
190+
CompoundTag dataTag = NbtIo.read(dataFile.toPath());
191+
data = codec.parse(NbtOps.INSTANCE, dataTag.get("data")).getOrThrow(IOException::new);
192+
}
176193
}
177194
} catch (Exception exc) {
178-
ObserverLib.log.info("Loading worlddata '" + key.getIdentifier() + "' failed for its backup save. Creating empty one for current runtime and copying erroneous files to error directory.");
179-
errored = true;
195+
ObserverLib.log.warn("Loading level data {} failed for its actual save. Attempting load from backup.",
196+
(isSaveRoot ? rootKey.getIdentifier() : rootKey.getIdentifier() + attemptName));
180197
}
181-
}
182-
if(data == null && errored) {
183-
DirectorySet errorSet = f.getErrorDirectories();
184-
try {
185-
if(f.getActualDirectory().exists()) {
186-
Files.copy(f.getActualDirectory(), errorSet.getActualDirectory());
187-
FileUtils.deleteDirectory(f.getActualDirectory());
198+
// Try load from backup fileset
199+
if (data == null) {
200+
try {
201+
if (dirSet.getBackupDirectory().exists()) {
202+
dataFile = fileResolver.resolveFile(dirSet.getBackupDirectory());
203+
if (dataFile.exists()) {
204+
CompoundTag dataTag = NbtIo.read(dataFile.toPath());
205+
data = codec.parse(NbtOps.INSTANCE, dataTag.get("data")).getOrThrow(IOException::new);
206+
}
207+
}
208+
} catch (Exception exc) {
209+
ObserverLib.log.warn("Loading level data {} failed for its backup save. Copying erroneous files to error directory.",
210+
(isSaveRoot ? rootKey.getIdentifier() : rootKey.getIdentifier() + attemptName));
188211
}
189-
if(f.getBackupDirectory().exists()) {
190-
Files.copy(f.getBackupDirectory(), errorSet.getBackupDirectory());
191-
FileUtils.deleteDirectory(f.getBackupDirectory());
212+
}
213+
// Copy files to error directory and give up.
214+
if (data == null) {
215+
DirectorySet errorSet = dirSet.getErrorDirectories();
216+
try {
217+
if (dirSet.getActualDirectory().exists()) {
218+
Files.copy(dirSet.getActualDirectory(), errorSet.getActualDirectory());
219+
}
220+
if (dirSet.getBackupDirectory().exists()) {
221+
Files.copy(dirSet.getBackupDirectory(), errorSet.getBackupDirectory());
222+
}
223+
} catch (Exception e) {
224+
ObserverLib.log.warn("Copying erroneous level data {} to the error directory failed.",
225+
(isSaveRoot ? rootKey.getIdentifier() : rootKey.getIdentifier() + attemptName));
226+
ObserverLib.log.error("Copying files failed.", e);
192227
}
193-
} catch (Exception e) {
194-
ObserverLib.log.info("Attempting to copy erroneous worlddata '" + key.getIdentifier() + "' to its error files directory failed.");
195-
e.printStackTrace();
196228
}
197-
}
198-
if (data == null) {
199-
data = key.getNewInstance(key);
200-
}
201-
ObserverLib.log.info("Loading of '" + key.getIdentifier() + "' for world " + dimTypeName + " finished.");
202-
return data;
203-
}
204-
205-
private static <T extends IWorldRelatedData<T>> T attemptLoad(WorldCacheDomain.SaveKey<T> key, File baseDirectory) throws IOException {
206-
CompoundTag dataTag = NbtIo.read(key.getSaveFile(baseDirectory).toPath());
207-
return key.getInstanceCodec().parse(NbtOps.INSTANCE, dataTag.get("data")).getOrThrow(IOException::new);
229+
if (data == null) {
230+
return Optional.empty();
231+
}
232+
return Optional.of(new Tuple<>(data, dataFile));
233+
};
208234
}
209235

210236
private synchronized static DirectorySet getDirectorySet(File baseDirectory, ResourceLocation dimTypeName, WorldCacheDomain.SaveKey<?> key) {
@@ -217,15 +243,6 @@ private synchronized static DirectorySet getDirectorySet(File baseDirectory, Res
217243
return new DirectorySet(new File(worldDir, key.getIdentifier()));
218244
}
219245

220-
private static File getServerWorldDirectory(File baseDirectory) {
221-
File pDir = new File(baseDirectory, "worlddata");
222-
if (!pDir.exists()) {
223-
pDir.mkdirs();
224-
}
225-
ensureFolder(pDir);
226-
return pDir;
227-
}
228-
229246
private static void ensureFolder(File f) {
230247
if (!f.isDirectory()) {
231248
ObserverLib.log.warn("dataFile exists, but is a file instead of a folder! Please ensure that this is a folder/delete the file!");

0 commit comments

Comments
 (0)