StandardDataSource class
Пакет: com.hypixel.hytale.builtin.asseteditor.datasource
Файл: com/hypixel/hytale/builtin/asseteditor/datasource/StandardDataSource.java
implements: DataSource
Поля (25)
| Модификаторы | Тип | Имя |
|---|---|---|
final |
HytaleLogger |
LOGGER |
|
|
return |
|
Path |
var1 |
|
|
var1 |
|
BsonDocument |
var1 |
|
BsonDocument |
var2 |
|
BsonArray |
var2 |
|
Path |
var2 |
|
Deque |
var2 |
|
ModifiedAsset |
var2 |
|
|
var2 |
|
|
var2 |
|
ModifiedAsset |
var3 |
|
byte[] |
var3 |
|
Deque |
var3 |
|
Path |
var4 |
|
Path |
var4 |
|
String |
var4 |
|
ModifiedAsset |
var4 |
|
String |
var5 |
|
String |
var5 |
|
long |
var5 |
|
ModifiedAsset |
var6 |
|
ModifiedAsset |
var6 |
|
ModifiedAsset |
var6 |
Методы (18)
| Модификаторы | Возврат | Сигнатура |
|---|---|---|
abstract |
return new |
AssetTreereturn new AssetTree(this.rootPath, this.packKey, this.isImmutable, this.isAssetPackBeDeleteable, var1) |
|
record |
EditorFileSaveInforecord EditorFileSaveInfo(String hash, long expiryMs) |
abstract |
throw new |
IllegalArgumentExceptionthrow new IllegalArgumentException("Invalid path: " + var1) |
public |
boolean |
canAssetPackBeDeletedboolean canAssetPackBeDeleted() |
|
|
for for(StandardDataSource.EditorFileSaveInfo var9 : var2) |
public |
Map<Path, ModifiedAsset> |
getRecentlyModifiedAssetsMap<Path, ModifiedAsset> getRecentlyModifiedAssets() |
|
|
if if(this.saveSchedule != null) |
|
|
if if(var6 != null) |
|
|
if if(var3 == null) |
|
|
if if(var2 == null) |
static |
boolean |
isInModsDirectoryboolean isInModsDirectory(Path var0) |
private |
void |
loadRecentModificationsvoid loadRecentModifications() |
public |
void |
putModifiedAssetvoid putModifiedAsset(ModifiedAsset var1) |
public |
Path |
resolveAbsolutePathPath resolveAbsolutePath(Path var1) |
public |
void |
saveRecentModificationsvoid saveRecentModifications() |
|
|
synchronized synchronized(var2) |
|
|
synchronized synchronized(var3) |
private |
void |
trackEditorFileSavevoid trackEditorFileSave(Path var1, String var2) |
Исходный код
Показать/скрыть
class="kw">package com.hypixel.hytale.builtin.asseteditor.datasource;
class="kw">import com.hypixel.hytale.builtin.asseteditor.AssetTree;
class="kw">import com.hypixel.hytale.builtin.asseteditor.EditorClient;
class="kw">import com.hypixel.hytale.builtin.asseteditor.assettypehandler.AssetTypeHandler;
class="kw">import com.hypixel.hytale.builtin.asseteditor.data.AssetState;
class="kw">import com.hypixel.hytale.builtin.asseteditor.data.ModifiedAsset;
class="kw">import com.hypixel.hytale.codec.ExtraInfo;
class="kw">import com.hypixel.hytale.common.plugin.PluginManifest;
class="kw">import com.hypixel.hytale.common.util.PathUtil;
class="kw">import com.hypixel.hytale.logger.HytaleLogger;
class="kw">import com.hypixel.hytale.server.core.HytaleServer;
class="kw">import com.hypixel.hytale.server.core.Options;
class="kw">import com.hypixel.hytale.server.core.plugin.PluginManager;
class="kw">import com.hypixel.hytale.server.core.util.BsonUtil;
class="kw">import com.hypixel.hytale.server.core.util.HashUtil;
class="kw">import java.io.IOException;
class="kw">import java.nio.file.Files;
class="kw">import java.nio.file.Path;
class="kw">import java.nio.file.StandardOpenOption;
class="kw">import java.time.Instant;
class="kw">import java.util.ArrayDeque;
class="kw">import java.util.Collection;
class="kw">import java.util.Deque;
class="kw">import java.util.Map;
class="kw">import java.util.Map.Entry;
class="kw">import java.util.concurrent.ConcurrentHashMap;
class="kw">import java.util.concurrent.ScheduledFuture;
class="kw">import java.util.concurrent.TimeUnit;
class="kw">import java.util.concurrent.atomic.AtomicBoolean;
class="kw">import java.util.logging.Level;
class="kw">import org.bson.BsonArray;
class="kw">import org.bson.BsonDocument;
class="kw">import org.bson.BsonValue;
class="kw">public class StandardDataSource class="kw">implements DataSource {
class="kw">private class="kw">static class="kw">final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
class="kw">private class="kw">final Path rootPath;
class="kw">private class="kw">final ConcurrentHashMap<Path, Deque<StandardDataSource.EditorFileSaveInfo>> editorSaves;
class="kw">private class="kw">final AssetTree assetTree;
class="kw">private class="kw">final String packKey;
class="kw">private class="kw">final PluginManifest manifest;
class="kw">private class="kw">final boolean isImmutable;
class="kw">private class="kw">final Path recentModificationsFilePath;
class="kw">private class="kw">final AtomicBoolean indexNeedsSaving = new AtomicBoolean();
class="kw">private class="kw">final Map<Path, ModifiedAsset> modifiedAssets = new ConcurrentHashMap<>();
class="kw">private ScheduledFuture<?> saveSchedule;
class="kw">private boolean isAssetPackBeDeleteable;
class="kw">public StandardDataSource(String var1, Path var2, boolean var3, PluginManifest var4) {
this.rootPath = var2;
this.editorSaves = new ConcurrentHashMap<>();
this.packKey = var1;
this.isImmutable = var3;
this.manifest = var4;
this.isAssetPackBeDeleteable = !var3 && isInModsDirectory(var2);
this.assetTree = new AssetTree(var2, var1, var3, this.isAssetPackBeDeleteable);
this.recentModificationsFilePath = Path.of("assetEditor", "recentAssetEdits_" + var1.replace(':', '-') + ".json");
}
class="kw">private class="kw">static boolean isInModsDirectory(Path var0) {
if (var0.startsWith(PluginManager.MODS_PATH.toAbsolutePath())) {
class="kw">return true;
}
for (Path var2 : Options.getOptionSet().valuesOf(Options.MODS_DIRECTORIES)) {
if (var0.startsWith(var2)) {
class="kw">return true;
}
}
class="kw">return false;
}
@Override
class="kw">public void start() {
this.loadRecentModifications();
this.saveSchedule = HytaleServer.SCHEDULED_EXECUTOR.scheduleWithFixedDelay(() -> {
try {
this.saveRecentModifications();
} catch (Exception var2) {
((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var2)).log("Failed to save assets index");
}
}, 1L, 1L, TimeUnit.MINUTES);
}
@Override
class="kw">public void shutdown() {
if (this.saveSchedule != null) {
this.saveSchedule.cancel(false);
}
this.saveRecentModifications();
}
class="kw">private void loadRecentModifications() {
Path var1 = this.recentModificationsFilePath;
if (!Files.exists(var1)) {
var1 = var1.resolveSibling(var1.getFileName() + ".bak");
if (!Files.exists(var1)) {
class="kw">return;
}
}
BsonDocument var2 = BsonUtil.readDocument(var1).join();
for (BsonValue var5 : var2.getArray("Assets")) {
ModifiedAsset var6 = ModifiedAsset.CODEC.decode(var5, new ExtraInfo());
if (var6 != null) {
this.modifiedAssets.put(var6.path, var6);
}
}
}
class="kw">public void saveRecentModifications() {
if (this.indexNeedsSaving.getAndSet(false)) {
LOGGER.at(Level.INFO).log("Saving recent asset modification index...");
BsonDocument var1 = new BsonDocument();
BsonArray var2 = new BsonArray();
for (Entry var4 : this.modifiedAssets.entrySet()) {
var2.add(ModifiedAsset.CODEC.encode(var4.getValue(), new ExtraInfo()));
}
var1.append("Assets", var2);
BsonUtil.writeDocument(this.recentModificationsFilePath, var1).exceptionally(var1x -> {
((HytaleLogger.Api)LOGGER.at(Level.SEVERE).withCause(var1x)).log("Failed to save recent asset modification index...");
this.indexNeedsSaving.set(true);
class="kw">return null;
});
}
}
class="kw">public boolean canAssetPackBeDeleted() {
class="kw">return this.isAssetPackBeDeleteable;
}
class="kw">public Path resolveAbsolutePath(Path var1) {
Path var2 = this.rootPath.resolve(var1.toString()).toAbsolutePath();
if (!PathUtil.isChildOf(this.rootPath, var2)) {
throw new IllegalArgumentException("Invalid path: " + var1);
} else {
class="kw">return var2;
}
}
@Override
class="kw">public Path getFullPathToAssetData(Path var1) {
class="kw">return this.resolveAbsolutePath(var1);
}
@Override
class="kw">public AssetTree getAssetTree() {
class="kw">return this.assetTree;
}
@Override
class="kw">public boolean isImmutable() {
class="kw">return this.isImmutable;
}
@Override
class="kw">public Path getRootPath() {
class="kw">return this.rootPath;
}
@Override
class="kw">public PluginManifest getManifest() {
class="kw">return this.manifest;
}
@Override
class="kw">public boolean doesDirectoryExist(Path var1) {
class="kw">return Files.isDirectory(this.resolveAbsolutePath(var1));
}
@Override
class="kw">public boolean createDirectory(Path var1, EditorClient var2) {
try {
Files.createDirectory(this.resolveAbsolutePath(var1));
class="kw">return true;
} catch (IOException var4) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var4)).log("Failed to create directory %s", var1);
class="kw">return false;
}
}
@Override
class="kw">public boolean deleteDirectory(Path var1) {
try {
Files.deleteIfExists(this.resolveAbsolutePath(var1));
class="kw">return true;
} catch (IOException var3) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var3)).log("Failed to delete directory %s", var1);
class="kw">return false;
}
}
@Override
class="kw">public boolean moveDirectory(Path var1, Path var2) {
try {
Files.move(this.resolveAbsolutePath(var1), this.resolveAbsolutePath(var2));
class="kw">return true;
} catch (IOException var4) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var4)).log("Failed to move directory %s to %s", var1, var2);
class="kw">return false;
}
}
@Override
class="kw">public boolean doesAssetExist(Path var1) {
class="kw">return Files.isRegularFile(this.resolveAbsolutePath(var1));
}
@Override
class="kw">public byte[] getAssetBytes(Path var1) {
try {
class="kw">return Files.readAllBytes(this.resolveAbsolutePath(var1));
} catch (IOException var3) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var3)).log("Failed to read asset %s", var1);
class="kw">return null;
}
}
@Override
class="kw">public boolean updateAsset(Path var1, byte[] var2, EditorClient var3) {
Path var4 = this.resolveAbsolutePath(var1);
try {
String var5 = HashUtil.sha256(var2);
this.trackEditorFileSave(var1, var5);
Files.write(var4, var2, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);
ModifiedAsset var6 = new ModifiedAsset();
var6.path = var1;
var6.state = AssetState.CHANGED;
var6.markEditedBy(var3);
this.putModifiedAsset(var6);
class="kw">return true;
} catch (IOException var7) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var7)).log("Failed to update asset %s", var1);
class="kw">return false;
}
}
@Override
class="kw">public boolean createAsset(Path var1, byte[] var2, EditorClient var3) {
Path var4 = this.resolveAbsolutePath(var1);
try {
String var5 = HashUtil.sha256(var2);
this.trackEditorFileSave(var1, var5);
Files.createDirectories(var4.getParent());
Files.write(var4, var2, StandardOpenOption.CREATE);
ModifiedAsset var6 = new ModifiedAsset();
var6.path = var1;
var6.state = AssetState.NEW;
var6.markEditedBy(var3);
this.putModifiedAsset(var6);
class="kw">return true;
} catch (IOException var7) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var7)).log("Failed to create asset %s", var1);
class="kw">return false;
}
}
@Override
class="kw">public boolean deleteAsset(Path var1, EditorClient var2) {
try {
Files.deleteIfExists(this.resolveAbsolutePath(var1));
ModifiedAsset var3 = new ModifiedAsset();
var3.path = var1;
var3.state = AssetState.DELETED;
var3.markEditedBy(var2);
this.putModifiedAsset(var3);
class="kw">return true;
} catch (IOException var4) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var4)).log("Failed to delete asset %s", var1);
class="kw">return false;
}
}
@Override
class="kw">public boolean shouldReloadAssetFromDisk(Path var1) {
Deque var2 = this.editorSaves.get(var1);
if (var2 != null && !var2.isEmpty()) {
byte[] var3 = this.getAssetBytes(var1);
if (var3 == null) {
class="kw">return true;
}
String var4 = HashUtil.sha256(var3);
long var5 = System.currentTimeMillis();
class="kw">synchronized (var2) {
var2.removeIf(var2x -> var2x.expiryMs <= var5);
for (StandardDataSource.EditorFileSaveInfo var9 : var2) {
if (var9.hash.equals(var4)) {
class="kw">return false;
}
}
class="kw">return true;
}
} else {
class="kw">return true;
}
}
@Override
class="kw">public Instant getLastModificationTimestamp(Path var1) {
class="kw">return null;
}
@Override
class="kw">public boolean moveAsset(Path var1, Path var2, EditorClient var3) {
try {
Files.move(this.resolveAbsolutePath(var1), this.resolveAbsolutePath(var2));
ModifiedAsset var4 = new ModifiedAsset();
var4.path = var2;
var4.oldPath = var1;
var4.state = AssetState.CHANGED;
var4.markEditedBy(var3);
this.putModifiedAsset(var4);
class="kw">return true;
} catch (IOException var5) {
((HytaleLogger.Api)LOGGER.at(Level.WARNING).withCause(var5)).log("Failed to move asset %s to %s", var1, var2);
class="kw">return false;
}
}
@Override
class="kw">public AssetTree loadAssetTree(Collection<AssetTypeHandler> var1) {
class="kw">return new AssetTree(this.rootPath, this.packKey, this.isImmutable, this.isAssetPackBeDeleteable, var1);
}
class="kw">public void putModifiedAsset(ModifiedAsset var1) {
this.modifiedAssets.put(var1.path, var1);
if (this.modifiedAssets.size() > 50) {
ModifiedAsset var2 = null;
for (ModifiedAsset var4 : this.modifiedAssets.values()) {
if (var2 == null) {
var2 = var4;
} else if (var4.lastModificationTimestamp.isBefore(var2.lastModificationTimestamp)) {
var2 = var4;
}
}
this.modifiedAssets.remove(var2.path);
}
this.indexNeedsSaving.set(true);
}
class="kw">public Map<Path, ModifiedAsset> getRecentlyModifiedAssets() {
class="kw">return this.modifiedAssets;
}
class="kw">private void trackEditorFileSave(Path var1, String var2) {
Deque var3 = this.editorSaves.computeIfAbsent(var1, var0 -> new ArrayDeque<>());
class="kw">synchronized (var3) {
var3.addLast(new StandardDataSource.EditorFileSaveInfo(var2, System.currentTimeMillis() + 30000L));
while (var3.size() > 20) {
var3.removeFirst();
}
}
}
record EditorFileSaveInfo(String hash, long expiryMs) {
EditorFileSaveInfo {
}
}
}