mirror of
https://github.com/Grasscutters/Grasscutter.git
synced 2025-02-09 12:52:52 +08:00
Multi-threaded resource loading
This commit is contained in:
parent
48959d54c5
commit
b6b9d3d744
@ -1,8 +1,5 @@
|
||||
package emu.grasscutter;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.SERVER;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import emu.grasscutter.auth.AuthenticationSystem;
|
||||
@ -29,12 +26,6 @@ import emu.grasscutter.server.http.handlers.GenericHandler;
|
||||
import emu.grasscutter.server.http.handlers.LogHandler;
|
||||
import emu.grasscutter.tools.Tools;
|
||||
import emu.grasscutter.utils.*;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.util.Calendar;
|
||||
import javax.annotation.Nullable;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.jline.reader.EndOfFileException;
|
||||
@ -46,6 +37,16 @@ import org.jline.terminal.TerminalBuilder;
|
||||
import org.reflections.Reflections;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.util.Calendar;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.SERVER;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
public final class Grasscutter {
|
||||
public static final File configFile = new File("./config.json");
|
||||
public static final Reflections reflector = new Reflections("emu.grasscutter");
|
||||
@ -120,7 +121,7 @@ public final class Grasscutter {
|
||||
}
|
||||
|
||||
// Initialize database.
|
||||
DatabaseManager.initialize();
|
||||
DatabaseManager.initializeAsync();
|
||||
|
||||
// Initialize the default systems.
|
||||
authenticationSystem = new DefaultAuthentication();
|
||||
|
@ -1,9 +1,5 @@
|
||||
package emu.grasscutter.data;
|
||||
|
||||
import static emu.grasscutter.utils.FileUtils.getDataPath;
|
||||
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.binout.*;
|
||||
@ -28,27 +24,34 @@ import emu.grasscutter.scripts.SceneIndexManager;
|
||||
import emu.grasscutter.scripts.ScriptLoader;
|
||||
import emu.grasscutter.utils.FileUtils;
|
||||
import emu.grasscutter.utils.JsonUtils;
|
||||
import emu.grasscutter.utils.Language;
|
||||
import emu.grasscutter.utils.TsvUtils;
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntArraySet;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.CompiledScript;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.script.Bindings;
|
||||
import javax.script.CompiledScript;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.val;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import static emu.grasscutter.utils.FileUtils.getDataPath;
|
||||
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
public final class ResourceLoader {
|
||||
|
||||
@ -97,87 +100,136 @@ public final class ResourceLoader {
|
||||
return List.copyOf(map.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a task asynchronously.
|
||||
*
|
||||
* @param task The task to run.
|
||||
* @return A CompletableFuture that will complete when the task is done.
|
||||
*/
|
||||
public static CompletableFuture<Boolean> runAsync(Runnable task) {
|
||||
return CompletableFuture.supplyAsync(
|
||||
() -> {
|
||||
task.run();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for all futures to complete.
|
||||
*
|
||||
* @param futures The futures to wait for.
|
||||
*/
|
||||
public static void waitForAll(Collection<CompletableFuture<Boolean>> futures) {
|
||||
futures.forEach(CompletableFuture::join);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public static void loadAll() {
|
||||
if (loadedAll) return;
|
||||
Grasscutter.getLogger().info(translate("messages.status.resources.loading"));
|
||||
|
||||
// Mark the starting time.
|
||||
var startTime = System.nanoTime();
|
||||
|
||||
// Initialize the script loader.
|
||||
ScriptLoader.init();
|
||||
|
||||
loadConfigData();
|
||||
// Load ability lists
|
||||
loadAbilityEmbryos();
|
||||
loadOpenConfig();
|
||||
loadAbilityModifiers();
|
||||
// Load resources
|
||||
loadResources(true);
|
||||
// Process into depots
|
||||
GameDepot.load();
|
||||
// Load spawn data and quests
|
||||
loadSpawnData();
|
||||
loadQuests();
|
||||
loadScriptSceneData();
|
||||
// Load scene points - must be done AFTER resources are loaded
|
||||
loadScenePoints();
|
||||
// Load 'TextMaps'.
|
||||
var textMaps = ResourceLoader.runAsync(Language::loadTextMaps);
|
||||
// Load 'BinOutput'.
|
||||
var binOutput = ResourceLoader.loadConfigData();
|
||||
// Load 'ExcelBinOutput'.
|
||||
var errors = new ConcurrentLinkedQueue<Pair<String, Exception>>();
|
||||
var excelBinOutput = ResourceLoader.loadResources(true, errors);
|
||||
// Load ability lists.
|
||||
var abilities = ResourceLoader.runAsync(() -> {
|
||||
ResourceLoader.loadAbilityEmbryos();
|
||||
ResourceLoader.loadOpenConfig();
|
||||
ResourceLoader.loadAbilityModifiers();
|
||||
});
|
||||
// Load spawn data and quests.
|
||||
var scene = ResourceLoader.runAsync(() -> {
|
||||
ResourceLoader.loadSpawnData();
|
||||
ResourceLoader.loadQuests();
|
||||
ResourceLoader.loadScriptSceneData();
|
||||
});
|
||||
// Load default home layout
|
||||
loadHomeworldDefaultSaveData();
|
||||
loadNpcBornData();
|
||||
loadBlossomResources();
|
||||
cacheTalentLevelSets();
|
||||
var entities = ResourceLoader.runAsync(() -> {
|
||||
ResourceLoader.loadHomeworldDefaultSaveData();
|
||||
ResourceLoader.loadNpcBornData();
|
||||
ResourceLoader.loadBlossomResources();
|
||||
ResourceLoader.cacheTalentLevelSets();
|
||||
});
|
||||
|
||||
// Load custom server resources.
|
||||
loadConfigLevelEntityData();
|
||||
loadQuestShareConfig();
|
||||
loadGadgetMappings();
|
||||
loadActivityCondGroups();
|
||||
loadGroupReplacements();
|
||||
loadTrialAvatarCustomData();
|
||||
var customServer = ResourceLoader.runAsync(() -> {
|
||||
ResourceLoader.loadConfigLevelEntityData();
|
||||
ResourceLoader.loadQuestShareConfig();
|
||||
ResourceLoader.loadGadgetMappings();
|
||||
ResourceLoader.loadActivityCondGroups();
|
||||
ResourceLoader.loadGroupReplacements();
|
||||
ResourceLoader.loadTrialAvatarCustomData();
|
||||
|
||||
EntityControllerScriptManager.load();
|
||||
});
|
||||
|
||||
// Wait for all futures to complete.
|
||||
var futures = new ArrayList<>(List.of(textMaps, abilities, scene, entities, customServer));
|
||||
futures.addAll(binOutput);
|
||||
futures.addAll(excelBinOutput);
|
||||
ResourceLoader.waitForAll(futures);
|
||||
|
||||
// Load dependent-resources.
|
||||
GameDepot.load(); // Process into depots
|
||||
ResourceLoader.loadScenePoints(); // Load scene points.
|
||||
|
||||
// Log any errors.
|
||||
errors.forEach(
|
||||
pair ->
|
||||
Grasscutter.getLogger()
|
||||
.error("Error loading resource file: " + pair.left(), pair.right() + "."));
|
||||
|
||||
// Calculate the ending time.
|
||||
var endTime = System.nanoTime();
|
||||
var ns = (endTime - startTime); // divide by 1000000 to get milliseconds.
|
||||
Grasscutter.getLogger().debug("Loading resources took " + ns + "ns (" + ns / 1000000 + "ms).");
|
||||
|
||||
Grasscutter.getLogger().info(translate("messages.status.resources.finish"));
|
||||
loadedAll = true;
|
||||
}
|
||||
|
||||
public static void loadResources() {
|
||||
loadResources(false);
|
||||
loadResources(false, new ConcurrentLinkedQueue<>());
|
||||
}
|
||||
|
||||
public static void loadResources(boolean doReload) {
|
||||
long startTime = System.nanoTime();
|
||||
val errors =
|
||||
new ConcurrentLinkedQueue<
|
||||
Pair<String, Exception>>(); // Logger in a parallel stream will deadlock
|
||||
/**
|
||||
* Loads all resources from annotated classes.
|
||||
*
|
||||
* @param doReload Whether to reload resources.
|
||||
*/
|
||||
public static List<CompletableFuture<Boolean>> loadResources(boolean doReload, Queue<Pair<String, Exception>> errors) {
|
||||
// Load all resources in parallel.
|
||||
return ResourceLoader.getResourceDefClassesPrioritySets().stream()
|
||||
.map(classes -> classes.stream()
|
||||
.parallel().unordered()
|
||||
.map(c -> {
|
||||
var type = c.getAnnotation(ResourceType.class);
|
||||
if (type == null) return null;
|
||||
|
||||
getResourceDefClassesPrioritySets()
|
||||
.forEach(
|
||||
classes -> {
|
||||
classes.stream()
|
||||
.parallel()
|
||||
.unordered()
|
||||
.forEach(
|
||||
c -> {
|
||||
val type = c.getAnnotation(ResourceType.class);
|
||||
if (type == null) return;
|
||||
|
||||
val map = GameData.getMapByResourceDef(c);
|
||||
if (map == null) return;
|
||||
var map = GameData.getMapByResourceDef(c);
|
||||
if (map == null) return null;
|
||||
|
||||
return ResourceLoader.runAsync(() -> {
|
||||
try {
|
||||
loadFromResource(c, type, map, doReload);
|
||||
} catch (Exception e) {
|
||||
errors.add(Pair.of(Arrays.toString(type.name()), e));
|
||||
}
|
||||
});
|
||||
});
|
||||
errors.forEach(
|
||||
pair ->
|
||||
Grasscutter.getLogger()
|
||||
.error("Error loading resource file: " + pair.left(), pair.right()));
|
||||
long endTime = System.nanoTime();
|
||||
long ns = (endTime - startTime); // divide by 1000000 to get milliseconds.
|
||||
Grasscutter.getLogger().debug("Loading resources took " + ns + "ns == " + ns / 1000000 + "ms");
|
||||
})
|
||||
.toList()
|
||||
).flatMap(Collection::stream)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@ -225,16 +277,13 @@ public final class ResourceLoader {
|
||||
|
||||
private static void loadScenePoints() {
|
||||
val pattern = Pattern.compile("scene([0-9]+)_point\\.json");
|
||||
try {
|
||||
Files.newDirectoryStream(getResourcePath("BinOutput/Scene/Point"), "scene*_point.json")
|
||||
.forEach(
|
||||
path -> {
|
||||
val matcher = pattern.matcher(path.getFileName().toString());
|
||||
try (var stream = Files.newDirectoryStream(getResourcePath("BinOutput/Scene/Point"), "scene*_point.json")) {
|
||||
stream.forEach(path -> {
|
||||
var matcher = pattern.matcher(path.getFileName().toString());
|
||||
if (!matcher.find()) return;
|
||||
int sceneId = Integer.parseInt(matcher.group(1));
|
||||
var sceneId = Integer.parseInt(matcher.group(1));
|
||||
|
||||
ScenePointConfig config;
|
||||
try {
|
||||
ScenePointConfig config; try {
|
||||
config = JsonUtils.loadToClass(path, ScenePointConfig.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@ -243,10 +292,10 @@ public final class ResourceLoader {
|
||||
|
||||
if (config.points == null) return;
|
||||
|
||||
val scenePoints = new IntArrayList();
|
||||
var scenePoints = new IntArrayList();
|
||||
config.points.forEach(
|
||||
(pointId, pointData) -> {
|
||||
val scenePoint = new ScenePointEntry(sceneId, pointData);
|
||||
var scenePoint = new ScenePointEntry(sceneId, pointData);
|
||||
scenePoints.add((int) pointId);
|
||||
pointData.setId(pointId);
|
||||
|
||||
@ -607,12 +656,21 @@ public final class ResourceLoader {
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadConfigData() {
|
||||
loadConfigData(GameData.getAvatarConfigData(), "BinOutput/Avatar/", ConfigEntityAvatar.class);
|
||||
loadConfigData(
|
||||
GameData.getMonsterConfigData(), "BinOutput/Monster/", ConfigEntityMonster.class);
|
||||
loadConfigDataMap(
|
||||
GameData.getGadgetConfigData(), "BinOutput/Gadget/", ConfigEntityGadget.class);
|
||||
/**
|
||||
* Loads data from parsed files.
|
||||
*/
|
||||
private static List<CompletableFuture<Boolean>> loadConfigData() {
|
||||
var tasks = new ArrayList<CompletableFuture<Boolean>>();
|
||||
|
||||
// Load config data.
|
||||
tasks.add(ResourceLoader.runAsync(() ->
|
||||
loadConfigData(GameData.getAvatarConfigData(), "BinOutput/Avatar/", ConfigEntityAvatar.class)));
|
||||
tasks.add(ResourceLoader.runAsync(() ->
|
||||
loadConfigData(GameData.getMonsterConfigData(), "BinOutput/Monster/", ConfigEntityMonster.class)));
|
||||
tasks.add(ResourceLoader.runAsync(() ->
|
||||
loadConfigDataMap(GameData.getGadgetConfigData(), "BinOutput/Gadget/", ConfigEntityGadget.class)));
|
||||
|
||||
return tasks;
|
||||
}
|
||||
|
||||
private static <T extends ConfigEntityBase> void loadConfigData(
|
||||
|
@ -1,7 +1,5 @@
|
||||
package emu.grasscutter.database;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.DATABASE;
|
||||
|
||||
import com.mongodb.MongoCommandException;
|
||||
import com.mongodb.client.MongoClient;
|
||||
import com.mongodb.client.MongoClients;
|
||||
@ -18,6 +16,8 @@ import emu.grasscutter.Grasscutter.ServerRunMode;
|
||||
import emu.grasscutter.game.Account;
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.DATABASE;
|
||||
|
||||
public final class DatabaseManager {
|
||||
private static Datastore gameDatastore;
|
||||
private static Datastore dispatchDatastore;
|
||||
@ -35,6 +35,18 @@ public final class DatabaseManager {
|
||||
return getGameDatastore().getDatabase();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the database initialization process.
|
||||
* This occurs on a separate thread.
|
||||
*/
|
||||
public static void initializeAsync() {
|
||||
new Thread(DatabaseManager::initialize).start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the database initialization process.
|
||||
* This method is blocking.
|
||||
*/
|
||||
public static void initialize() {
|
||||
// Initialize
|
||||
MongoClient gameMongoClient = MongoClients.create(DATABASE.game.connectionUri);
|
||||
|
@ -3,6 +3,7 @@ package emu.grasscutter.game.drop;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.DataLoader;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.ResourceLoader;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.game.entity.EntityItem;
|
||||
import emu.grasscutter.game.entity.EntityMonster;
|
||||
@ -26,7 +27,8 @@ public class DropSystemLegacy extends BaseGameSystem {
|
||||
public DropSystemLegacy(GameServer server) {
|
||||
super(server);
|
||||
this.dropData = new Int2ObjectOpenHashMap<>();
|
||||
this.load();
|
||||
|
||||
ResourceLoader.runAsync(this::load);
|
||||
}
|
||||
|
||||
public Int2ObjectMap<List<DropData>> getDropData() {
|
||||
|
@ -2,6 +2,7 @@ package emu.grasscutter.game.expedition;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.DataLoader;
|
||||
import emu.grasscutter.data.ResourceLoader;
|
||||
import emu.grasscutter.server.game.BaseGameSystem;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
@ -13,8 +14,9 @@ public class ExpeditionSystem extends BaseGameSystem {
|
||||
|
||||
public ExpeditionSystem(GameServer server) {
|
||||
super(server);
|
||||
|
||||
this.expeditionRewardData = new Int2ObjectOpenHashMap<>();
|
||||
this.load();
|
||||
ResourceLoader.runAsync(this::load);
|
||||
}
|
||||
|
||||
public Int2ObjectMap<List<ExpeditionRewardDataList>> getExpeditionRewardDataList() {
|
||||
|
@ -1,11 +1,10 @@
|
||||
package emu.grasscutter.game.gacha;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||
|
||||
import com.sun.nio.file.SensitivityWatchEventModifier;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.DataLoader;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.ResourceLoader;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.data.excels.ItemData;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
@ -31,11 +30,14 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
|
||||
import java.nio.file.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||
|
||||
public class GachaSystem extends BaseGameSystem {
|
||||
private static final int starglitterId = 221;
|
||||
@ -45,8 +47,9 @@ public class GachaSystem extends BaseGameSystem {
|
||||
|
||||
public GachaSystem(GameServer server) {
|
||||
super(server);
|
||||
|
||||
this.gachaBanners = new Int2ObjectOpenHashMap<>();
|
||||
this.load();
|
||||
ResourceLoader.runAsync(this::load);
|
||||
this.startWatcher(server);
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
package emu.grasscutter.game.managers.energy;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.DataLoader;
|
||||
@ -30,10 +28,13 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import lombok.Getter;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||
|
||||
public class EnergyManager extends BasePlayerManager {
|
||||
private static final Int2ObjectMap<List<EnergyDropInfo>> energyDropData =
|
||||
|
@ -1,10 +1,9 @@
|
||||
package emu.grasscutter.game.shop;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.DataLoader;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.ResourceLoader;
|
||||
import emu.grasscutter.data.common.ItemParamData;
|
||||
import emu.grasscutter.data.excels.ShopGoodsData;
|
||||
import emu.grasscutter.server.game.BaseGameSystem;
|
||||
@ -12,10 +11,13 @@ import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.GAME_OPTIONS;
|
||||
|
||||
public class ShopSystem extends BaseGameSystem {
|
||||
private static final int REFRESH_HOUR = 4; // In GMT+8 server
|
||||
private static final String TIME_ZONE = "Asia/Shanghai"; // GMT+8 Timezone
|
||||
@ -24,9 +26,10 @@ public class ShopSystem extends BaseGameSystem {
|
||||
|
||||
public ShopSystem(GameServer server) {
|
||||
super(server);
|
||||
|
||||
this.shopData = new Int2ObjectOpenHashMap<>();
|
||||
this.shopChestData = new Int2ObjectOpenHashMap<>();
|
||||
this.load();
|
||||
ResourceLoader.runAsync(this::load);
|
||||
}
|
||||
|
||||
public static int getShopNextRefreshTime(ShopInfo shopInfo) {
|
||||
|
@ -2,6 +2,7 @@ package emu.grasscutter.game.systems;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.DataLoader;
|
||||
import emu.grasscutter.data.ResourceLoader;
|
||||
import emu.grasscutter.game.player.Player;
|
||||
import emu.grasscutter.game.world.World;
|
||||
import emu.grasscutter.net.proto.AnnounceDataOuterClass;
|
||||
@ -10,12 +11,13 @@ import emu.grasscutter.server.game.GameServer;
|
||||
import emu.grasscutter.server.packet.send.PacketServerAnnounceNotify;
|
||||
import emu.grasscutter.server.packet.send.PacketServerAnnounceRevokeNotify;
|
||||
import emu.grasscutter.utils.Utils;
|
||||
import java.util.*;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.FieldDefaults;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Getter
|
||||
public class AnnouncementSystem extends BaseGameSystem {
|
||||
private final Map<Integer, AnnounceConfigItem> announceConfigItemMap;
|
||||
@ -23,7 +25,7 @@ public class AnnouncementSystem extends BaseGameSystem {
|
||||
public AnnouncementSystem(GameServer server) {
|
||||
super(server);
|
||||
this.announceConfigItemMap = new HashMap<>();
|
||||
loadConfig();
|
||||
ResourceLoader.runAsync(this::loadConfig);
|
||||
}
|
||||
|
||||
private int loadConfig() {
|
||||
|
@ -3,6 +3,7 @@ package emu.grasscutter.game.tower;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.DataLoader;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.ResourceLoader;
|
||||
import emu.grasscutter.data.excels.tower.TowerScheduleData;
|
||||
import emu.grasscutter.server.game.BaseGameSystem;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
@ -15,7 +16,8 @@ public class TowerSystem extends BaseGameSystem {
|
||||
|
||||
public TowerSystem(GameServer server) {
|
||||
super(server);
|
||||
this.load();
|
||||
|
||||
ResourceLoader.runAsync(this::load);
|
||||
}
|
||||
|
||||
public synchronized void load() {
|
||||
|
@ -3,6 +3,7 @@ package emu.grasscutter.game.world;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.data.DataLoader;
|
||||
import emu.grasscutter.data.GameData;
|
||||
import emu.grasscutter.data.ResourceLoader;
|
||||
import emu.grasscutter.data.excels.InvestigationMonsterData;
|
||||
import emu.grasscutter.data.excels.RewardPreviewData;
|
||||
import emu.grasscutter.data.excels.world.WorldLevelData;
|
||||
@ -15,12 +16,13 @@ import emu.grasscutter.scripts.data.SceneGroup;
|
||||
import emu.grasscutter.scripts.data.SceneMonster;
|
||||
import emu.grasscutter.server.game.BaseGameSystem;
|
||||
import emu.grasscutter.server.game.GameServer;
|
||||
import org.luaj.vm2.LuaError;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import org.luaj.vm2.LuaError;
|
||||
|
||||
public class WorldDataSystem extends BaseGameSystem {
|
||||
private final Map<String, ChestInteractHandler> chestInteractHandlerMap; // chestType-Handler
|
||||
@ -31,7 +33,7 @@ public class WorldDataSystem extends BaseGameSystem {
|
||||
this.chestInteractHandlerMap = new HashMap<>();
|
||||
this.sceneInvestigationGroupMap = new ConcurrentHashMap<>();
|
||||
|
||||
loadChestConfig();
|
||||
ResourceLoader.runAsync(this::loadChestConfig);
|
||||
}
|
||||
|
||||
public synchronized void loadChestConfig() {
|
||||
|
@ -1,13 +1,15 @@
|
||||
package emu.grasscutter.plugin;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.server.event.Event;
|
||||
import emu.grasscutter.server.event.EventHandler;
|
||||
import emu.grasscutter.server.event.HandlerPriority;
|
||||
import emu.grasscutter.utils.FileUtils;
|
||||
import emu.grasscutter.utils.JsonUtils;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStreamReader;
|
||||
@ -18,9 +20,8 @@ import java.net.URLClassLoader;
|
||||
import java.util.*;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import javax.annotation.Nullable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
/** Manages the server's plugins and the event system. */
|
||||
public final class PluginManager {
|
||||
|
@ -1,12 +1,9 @@
|
||||
package emu.grasscutter.server.game;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.DISPATCH_INFO;
|
||||
import static emu.grasscutter.config.Configuration.GAME_INFO;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.Grasscutter.ServerRunMode;
|
||||
import emu.grasscutter.data.ResourceLoader;
|
||||
import emu.grasscutter.database.DatabaseHelper;
|
||||
import emu.grasscutter.game.Account;
|
||||
import emu.grasscutter.game.battlepass.BattlePassSystem;
|
||||
@ -41,17 +38,22 @@ import emu.grasscutter.server.event.internal.ServerStopEvent;
|
||||
import emu.grasscutter.server.event.types.ServerEvent;
|
||||
import emu.grasscutter.server.scheduler.ServerTaskScheduler;
|
||||
import emu.grasscutter.task.TaskMap;
|
||||
import kcp.highway.ChannelConfig;
|
||||
import kcp.highway.KcpServer;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import kcp.highway.ChannelConfig;
|
||||
import kcp.highway.KcpServer;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.DISPATCH_INFO;
|
||||
import static emu.grasscutter.config.Configuration.GAME_INFO;
|
||||
import static emu.grasscutter.utils.Language.translate;
|
||||
|
||||
@Getter
|
||||
public final class GameServer extends KcpServer {
|
||||
@ -140,11 +142,14 @@ public final class GameServer extends KcpServer {
|
||||
|
||||
this.init(GameSessionManager.getListener(), channelConfig, address);
|
||||
|
||||
// Load game managers asyncronously.
|
||||
ResourceLoader.runAsync(() -> {
|
||||
EnergyManager.initialize();
|
||||
StaminaManager.initialize();
|
||||
CookingManager.initialize();
|
||||
CookingCompoundManager.initialize();
|
||||
CombineManger.initialize();
|
||||
});
|
||||
|
||||
// Game Server base
|
||||
this.address = address;
|
||||
|
@ -1,8 +1,5 @@
|
||||
package emu.grasscutter.tools;
|
||||
|
||||
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
||||
import static emu.grasscutter.utils.Language.getTextMapKey;
|
||||
|
||||
import emu.grasscutter.GameConstants;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
import emu.grasscutter.command.CommandHandler;
|
||||
@ -20,6 +17,10 @@ import emu.grasscutter.utils.Language;
|
||||
import emu.grasscutter.utils.Language.TextStrings;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntRBTreeMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectRBTreeMap;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.val;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
@ -31,9 +32,9 @@ import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import java.util.stream.LongStream;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.val;
|
||||
|
||||
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
||||
import static emu.grasscutter.utils.Language.getTextMapKey;
|
||||
|
||||
public final class Tools {
|
||||
/**
|
||||
@ -52,6 +53,10 @@ public final class Tools {
|
||||
* @throws Exception If an error occurs while generating the handbooks.
|
||||
*/
|
||||
public static void createGmHandbooks(boolean message) throws Exception {
|
||||
// Check if the GM Handbook directory exists.
|
||||
val handbookDir = new File("GM Handbook");
|
||||
if (handbookDir.exists()) return;
|
||||
|
||||
val languages = Language.TextStrings.getLanguages();
|
||||
|
||||
ResourceLoader.loadAll();
|
||||
|
@ -1,9 +1,5 @@
|
||||
package emu.grasscutter.utils;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.FALLBACK_LANGUAGE;
|
||||
import static emu.grasscutter.utils.FileUtils.getCachePath;
|
||||
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import emu.grasscutter.Grasscutter;
|
||||
@ -17,6 +13,8 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
@ -28,7 +26,10 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import static emu.grasscutter.config.Configuration.FALLBACK_LANGUAGE;
|
||||
import static emu.grasscutter.utils.FileUtils.getCachePath;
|
||||
import static emu.grasscutter.utils.FileUtils.getResourcePath;
|
||||
|
||||
public final class Language {
|
||||
private static final Map<String, Language> cachedLanguages = new ConcurrentHashMap<>();
|
||||
@ -339,28 +340,30 @@ public final class Language {
|
||||
*/
|
||||
public static void loadTextMaps(boolean bypassCache) {
|
||||
// Check system timestamps on cache and resources
|
||||
if (!bypassCache)
|
||||
if (!bypassCache) {
|
||||
try {
|
||||
long cacheModified = Files.getLastModifiedTime(TEXTMAP_CACHE_PATH).toMillis();
|
||||
long textmapsModified =
|
||||
Files.list(getResourcePath("TextMap"))
|
||||
.filter(path -> path.toString().endsWith(".json"))
|
||||
|
||||
var stream = Files.list(getResourcePath("TextMap"));
|
||||
var textmapsModified = stream.filter(path ->
|
||||
path.toString().endsWith(".json"))
|
||||
.map(
|
||||
path -> {
|
||||
try {
|
||||
return Files.getLastModifiedTime(path).toMillis();
|
||||
} catch (Exception ignored) {
|
||||
Grasscutter.getLogger()
|
||||
.debug("Exception while checking modified time: ", path);
|
||||
.debug("Exception while checking modified time: {}.", path);
|
||||
return Long.MAX_VALUE; // Don't use cache, something has gone wrong
|
||||
}
|
||||
})
|
||||
.max(Long::compare)
|
||||
.get();
|
||||
stream.close();
|
||||
|
||||
Grasscutter.getLogger()
|
||||
.debug(
|
||||
"Cache modified %d, textmap modified %d"
|
||||
"Cache modified %d, textmap modified %d."
|
||||
.formatted(cacheModified, textmapsModified));
|
||||
if (textmapsModified < cacheModified) {
|
||||
// Try loading from cache
|
||||
@ -369,7 +372,8 @@ public final class Language {
|
||||
return;
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
Grasscutter.getLogger().error("Error loading textmaps cache: " + exception.toString());
|
||||
Grasscutter.getLogger().error("Error loading textmaps cache: " + exception);
|
||||
}
|
||||
}
|
||||
|
||||
// Regenerate cache
|
||||
|
Loading…
Reference in New Issue
Block a user