From 981d160e9ac77d70d6665830dc1a0aee6b858f37 Mon Sep 17 00:00:00 2001 From: test Date: Fri, 23 Aug 2024 19:02:08 +1000 Subject: [PATCH 01/27] WIP lazy startup --- .../java/link/locutus/discord/Locutus.java | 494 +++++------------- src/main/java/link/locutus/discord/Logg.java | 6 + .../locutus/discord/{ => _main}/Backup.java | 4 +- .../discord/_main/FinalizedLoader.java | 30 ++ .../link/locutus/discord/_main/ILoader.java | 42 ++ .../link/locutus/discord/_main/PreLoader.java | 275 ++++++++++ .../discord/apiv3/PoliticsAndWarV3.java | 3 +- .../java/link/locutus/discord/apiv3/README.md | 5 +- .../discord/{ => apiv3}/RequestTracker.java | 5 +- .../link/locutus/discord/commands/README.md | 2 + .../commands/manager/CommandManager.java | 7 +- .../manager/v2/impl/SlashCommandManager.java | 35 +- .../manager/v2/impl/pw/CommandManager2.java | 17 + .../v2/impl/pw/commands/AdminCommands.java | 9 +- .../link/locutus/discord/config/GuildIds.java | 61 --- .../link/locutus/discord/config/README.md | 1 + .../link/locutus/discord/config/Settings.java | 1 + .../config/yaml/file/FileConfiguration.java | 1 - .../config/yaml/file/YamlConfiguration.java | 7 - .../discord/db/AEmbeddingDatabase.java | 44 +- .../java/link/locutus/discord/db/BankDB.java | 4 +- .../link/locutus/discord/db/DBMainV2.java | 20 +- .../link/locutus/discord/db/NationDB.java | 2 +- .../java/link/locutus/discord/db/README.md | 1 + .../java/link/locutus/discord/db/WarDB.java | 279 ++++++---- .../locutus/discord/db/entities/DBNation.java | 2 +- .../locutus/discord/db/entities/DBWar.java | 17 + .../discord/db/handlers/ActiveWarHandler.java | 2 +- .../discord/db/handlers/AttackQuery.java | 2 +- .../java/link/locutus/discord/event/README.md | 5 + .../link/locutus/discord/gpt/GptHandler.java | 17 +- .../discord/gpt/imps/MiniEmbedding.java | 50 +- .../locutus/discord/gpt/pw/PWGPTHandler.java | 9 +- .../link/locutus/discord/network/README.md | 4 + .../java/link/locutus/discord/util/README.md | 2 + .../discord/util/io/PageRequestQueue.java | 8 +- .../discord/util/trade/TradeManager.java | 5 +- .../java/link/locutus/discord/web/README.md | 1 + 38 files changed, 869 insertions(+), 610 deletions(-) rename src/main/java/link/locutus/discord/{ => _main}/Backup.java (97%) create mode 100644 src/main/java/link/locutus/discord/_main/FinalizedLoader.java create mode 100644 src/main/java/link/locutus/discord/_main/ILoader.java create mode 100644 src/main/java/link/locutus/discord/_main/PreLoader.java rename src/main/java/link/locutus/discord/{ => apiv3}/RequestTracker.java (98%) create mode 100644 src/main/java/link/locutus/discord/commands/README.md delete mode 100644 src/main/java/link/locutus/discord/config/GuildIds.java create mode 100644 src/main/java/link/locutus/discord/config/README.md create mode 100644 src/main/java/link/locutus/discord/db/README.md create mode 100644 src/main/java/link/locutus/discord/event/README.md create mode 100644 src/main/java/link/locutus/discord/network/README.md create mode 100644 src/main/java/link/locutus/discord/util/README.md create mode 100644 src/main/java/link/locutus/discord/web/README.md diff --git a/src/main/java/link/locutus/discord/Locutus.java b/src/main/java/link/locutus/discord/Locutus.java index 995eccf9..e43d9bb1 100644 --- a/src/main/java/link/locutus/discord/Locutus.java +++ b/src/main/java/link/locutus/discord/Locutus.java @@ -1,7 +1,9 @@ package link.locutus.discord; import com.google.common.eventbus.AsyncEventBus; -import link.locutus.discord.apiv1.core.ApiKeyPool; +import link.locutus.discord._main.FinalizedLoader; +import link.locutus.discord._main.ILoader; +import link.locutus.discord._main.PreLoader; import link.locutus.discord.apiv2.PoliticsAndWarV2; import link.locutus.discord.apiv3.csv.DataDumpParser; import link.locutus.discord.apiv3.PoliticsAndWarV3; @@ -30,7 +32,6 @@ import link.locutus.discord.db.handlers.GuildCustomMessageHandler; import link.locutus.discord.event.Event; import link.locutus.discord.event.game.TurnChangeEvent; -import link.locutus.discord.network.ProxyHandler; import link.locutus.discord.pnw.PNWUser; import link.locutus.discord.util.*; import link.locutus.discord.util.scheduler.CaughtRunnable; @@ -46,11 +47,9 @@ import link.locutus.discord.util.task.roles.AutoRoleInfo; import link.locutus.discord.util.trade.TradeManager; import link.locutus.discord.util.update.*; -import link.locutus.discord.web.jooby.WebRoot; import com.google.common.eventbus.EventBus; -import link.locutus.discord.apiv1.PoliticsAndWarBuilder; +import link.locutus.discord.web.jooby.WebRoot; import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.entities.SelfUser; import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; @@ -79,22 +78,10 @@ import net.dv8tion.jda.api.interactions.components.buttons.Button; import net.dv8tion.jda.api.interactions.modals.ModalInteraction; import net.dv8tion.jda.api.interactions.modals.ModalMapping; -import net.dv8tion.jda.api.requests.GatewayIntent; -import net.dv8tion.jda.api.utils.ChunkingFilter; -import net.dv8tion.jda.api.utils.Compression; -import net.dv8tion.jda.api.utils.MemberCachePolicy; -import net.dv8tion.jda.api.utils.cache.CacheFlag; -import org.apache.logging.log4j.Level; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.core.LoggerContext; -import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector; -import org.apache.logging.log4j.core.config.Configuration; -import org.apache.logging.log4j.core.config.LoggerConfig; import org.jetbrains.annotations.NotNull; import javax.annotation.Nonnull; import javax.security.auth.login.LoginException; -import java.io.IOException; import java.nio.ByteBuffer; import java.sql.SQLException; import java.util.*; @@ -102,42 +89,24 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Consumer; -import java.util.logging.Logger; public final class Locutus extends ListenerAdapter { private static Locutus INSTANCE; - private final CommandManager commandManager; - private final Logger logger; - private final StockDB stockDB; - private PnwPusherShardManager pusher; - private ForumDB forumDb; - - private GuildShardManager manager = new GuildShardManager(); - - private final String discordToken; - - private final DiscordDB discordDB; - private final NationDB nationDB; - private Guild server; + private ILoader loader; - private final PoliticsAndWarV2 pnwApi; - - private final PoliticsAndWarV3 v3; - - private final TradeManager tradeManager; - private final WarDB warDb; - private BaseballDB baseBallDB; - private final BankDB bankDb; private final ExecutorService executor; - private final Map guildDatabases = new ConcurrentHashMap<>(); - private EventBus eventBus; - private SlashCommandManager slashCommands; + private final EventBus eventBus; - private ProxyHandler proxyHandler; + private final GuildShardManager manager = new GuildShardManager(); private GuildCustomMessageHandler messageHandler; private DataDumpParser dataDumpParser; - private Object dataDumpParserLock = new Object(); + + private final Map guildDatabases = new ConcurrentHashMap<>(); + private final Object dataDumpParserLock = new Object(); + + private PnwPusherShardManager pusher; + private Guild server; public static synchronized Locutus create() { if (INSTANCE != null) throw new IllegalStateException("Already initialized"); @@ -150,15 +119,10 @@ public static synchronized Locutus create() { private Locutus() throws SQLException, ClassNotFoundException, LoginException, InterruptedException, NoSuchMethodException { Logg.setInfoLogging(); - if (INSTANCE != null) throw new IllegalStateException("Already running."); INSTANCE = this; long start = System.currentTimeMillis(); - - this.proxyHandler = new ProxyHandler(); - - System.out.println("remove:|| proxyhandler " + (((-start)) + (start = System.currentTimeMillis()))); - + this.executor = Executors.newCachedThreadPool(); if (Settings.INSTANCE.ROOT_SERVER <= 0) throw new IllegalStateException("Please set ROOT_SERVER in " + Settings.INSTANCE.getDefaultFile()); if (Settings.INSTANCE.ROOT_COALITION_SERVER <= 0) Settings.INSTANCE.ROOT_COALITION_SERVER = Settings.INSTANCE.ROOT_SERVER; @@ -173,110 +137,29 @@ private Locutus() throws SQLException, ClassNotFoundException, LoginException, I if (Settings.commandPrefix(true).matches("[._~]")) { throw new IllegalStateException("LEGACY_COMMAND_PREFIX cannot be `.` or `_` or `~` in " + Settings.INSTANCE.getDefaultFile()); } - - this.logger = Logger.getLogger("LOCUTUS"); - this.eventBus = new AsyncEventBus("locutus", Runnable::run); - - System.out.println("remove:|| eventbus " + (((-start)) + (start = System.currentTimeMillis()))); - - this.executor = Executors.newCachedThreadPool(); - - System.out.println("remove:|| executor " + (((-start)) + (start = System.currentTimeMillis()))); - this.discordDB = new DiscordDB(); - System.out.println("remove:|| discorddb " + (((-start)) + (start = System.currentTimeMillis()))); - this.nationDB = new NationDB(); - System.out.println("remove:|| nationdb " + (((-start)) + (start = System.currentTimeMillis()))); - this.warDb = new WarDB(); - System.out.println("remove:|| wardb " + (((-start)) + (start = System.currentTimeMillis()))); - this.stockDB = new StockDB(); - System.out.println("remove:|| stockdb " + (((-start)) + (start = System.currentTimeMillis()))); - this.bankDb = new BankDB("bank"); - System.out.println("remove:|| bankdb " + (((-start)) + (start = System.currentTimeMillis()))); - this.tradeManager = new TradeManager(); - System.out.println("remove:|| trademanager " + (((-start)) + (start = System.currentTimeMillis()))); - if (Settings.INSTANCE.FORUM_FEED_SERVER > 0) { - this.forumDb = new ForumDB(Settings.INSTANCE.FORUM_FEED_SERVER); - System.out.println("remove:|| forumfeed " + (((-start)) + (start = System.currentTimeMillis()))); - } - - this.commandManager = new CommandManager(this); - System.out.println("remove:|| commandmanager " + (((-start)) + (start = System.currentTimeMillis()))); if (Settings.INSTANCE.BOT_TOKEN.isEmpty()) { throw new IllegalStateException("Please set BOT_TOKEN in " + Settings.INSTANCE.getDefaultFile()); } - this.discordToken = Settings.INSTANCE.BOT_TOKEN; - if (Settings.INSTANCE.API_KEY_PRIMARY.isEmpty()) { if (Settings.INSTANCE.USERNAME.isEmpty() || Settings.INSTANCE.PASSWORD.isEmpty()) { throw new IllegalStateException("Please set API_KEY_PRIMARY or USERNAME/PASSWORD in " + Settings.INSTANCE.getDefaultFile()); } - Auth auth = new Auth(0, Settings.INSTANCE.USERNAME, Settings.INSTANCE.PASSWORD); - ApiKeyPool.ApiKey key = auth.fetchApiKey(); - Settings.INSTANCE.API_KEY_PRIMARY = key.getKey(); - } - System.out.println("remove:|| apikey " + (((-start)) + (start = System.currentTimeMillis()))); - - if (Settings.INSTANCE.API_KEY_PRIMARY.isEmpty()) { - throw new IllegalStateException("Please set API_KEY_PRIMARY or USERNAME/PASSWORD in " + Settings.INSTANCE.getDefaultFile()); } - if (Settings.INSTANCE.NATION_ID <= 0) { - Settings.INSTANCE.NATION_ID = 0; - Integer nationIdFromKey = Locutus.imp().getDiscordDB().getNationFromApiKey(Settings.INSTANCE.API_KEY_PRIMARY); - if (nationIdFromKey == null) { - throw new IllegalStateException("Could not get NATION_ID from key. Please ensure a valid API_KEY is set in " + Settings.INSTANCE.getDefaultFile()); - } - Settings.INSTANCE.NATION_ID = nationIdFromKey; - } - - System.out.println("remove:|| nationid " + (((-start)) + (start = System.currentTimeMillis()))); - - { - PNWUser adminPnwUser = Locutus.imp().getDiscordDB().getUserFromNationId(Settings.INSTANCE.NATION_ID); - if (adminPnwUser != null) { - Settings.INSTANCE.ADMIN_USER_ID = adminPnwUser.getDiscordId(); - } - } - System.out.println("remove:|| adminuserid " + (((-start)) + (start = System.currentTimeMillis()))); - - List pool = new ArrayList<>(); - pool.addAll(Settings.INSTANCE.API_KEY_POOL); - if (pool.isEmpty()) { - pool.add(Settings.INSTANCE.API_KEY_PRIMARY); - } - - this.pnwApi = new PoliticsAndWarBuilder().addApiKeys(pool.toArray(new String[0])).setEnableCache(false).setTestServerMode(Settings.INSTANCE.TEST).build(); - System.out.println("remove:|| pnwapi " + (((-start)) + (start = System.currentTimeMillis()))); - - ApiKeyPool v3Pool = ApiKeyPool.builder().addKey(Settings.INSTANCE.NATION_ID, Settings.INSTANCE.API_KEY_PRIMARY,Settings.INSTANCE.ACCESS_KEY).build(); - this.v3 = new PoliticsAndWarV3(v3Pool); - System.out.println("remove:|| v3 " + (((-start)) + (start = System.currentTimeMillis()))); - - this.commandManager.registerCommands(discordDB); - System.out.println("remove:|| registercommands " + (((-start)) + (start = System.currentTimeMillis()))); - - if (Settings.INSTANCE.ENABLED_COMPONENTS.EVENTS) { - this.registerEvents(); - } - - System.out.println("remove:|| events " + (((-start)) + (start = System.currentTimeMillis()))); - - this.nationDB.load(); - System.out.println("remove:|| nationdbload " + (((-start)) + (start = System.currentTimeMillis()))); - this.warDb.load(); - System.out.println("remove:|| wardbload " + (((-start)) + (start = System.currentTimeMillis()))); - this.tradeManager.load(); - System.out.println("remove:|| trademanagerload " + (((-start)) + (start = System.currentTimeMillis()))); - } - - public ProxyHandler getProxyHandler() { - return proxyHandler; + this.eventBus = new AsyncEventBus("locutus", Runnable::run); + Logg.text("remove:||PERF eventbus " + (((-start)) + (start = System.currentTimeMillis()))); + this.loader = new PreLoader(this, executor); + Logg.text("remove:||PERF new preloader " + (((-start)) + (start = System.currentTimeMillis()))); } public static void post(Object event) { imp().eventBus.post(event); } + public static ILoader loader() { + return imp().loader; + } + public void registerEvents() { eventBus.register(new TreatyUpdateProcessor()); eventBus.register(new NationUpdateProcessor()); @@ -285,7 +168,9 @@ public void registerEvents() { eventBus.register(new BankUpdateProcessor()); eventBus.register(new WarUpdateProcessor()); eventBus.register(new AllianceListener()); - eventBus.register(new MailListener(commandManager.getV2().getStore(), commandManager.getV2().getValidators(), commandManager.getV2().getPermisser())); + CommandManager cmdManager = loader.getCommandManager(); + eventBus.register(new MailListener(cmdManager.getV2().getStore(), cmdManager.getV2().getValidators(), cmdManager.getV2().getPermisser())); + WarDB warDb = loader.getWarDB(); ConflictManager conflictManager = warDb == null ? null : warDb.getConflicts(); if (conflictManager != null) eventBus.register(conflictManager); } @@ -300,124 +185,55 @@ public GuildShardManager getDiscordApi() { public Locutus start() throws InterruptedException, LoginException, SQLException, ClassNotFoundException { long start = System.currentTimeMillis(); - backup(); - System.out.println("remove:|| backup " + (((-start)) + (start = System.currentTimeMillis()))); + if (loader.getApiKey().isEmpty()) { + throw new IllegalStateException("Please set API_KEY_PRIMARY or USERNAME/PASSWORD in " + Settings.INSTANCE.getDefaultFile()); + } + if (loader.getNationId() <= 0) { + throw new IllegalStateException("Could not get NATION_ID from key. Please ensure a valid API_KEY is set in " + Settings.INSTANCE.getDefaultFile()); + } + Logg.text("remove:||PERF wait for nation id and api key " + (((-start)) + (start = System.currentTimeMillis()))); + if (Settings.INSTANCE.ENABLED_COMPONENTS.EVENTS) { + this.registerEvents(); + } + Logg.text("remove:||PERF register events " + (((-start)) + (start = System.currentTimeMillis()))); + // TODO fixme backup + Logg.text("remove:||PERF backup " + (((-start)) + (start = System.currentTimeMillis()))); if (Settings.INSTANCE.ENABLED_COMPONENTS.DISCORD_BOT) { - JDABuilder builder = JDABuilder.createLight(discordToken, GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGES, GatewayIntent.DIRECT_MESSAGES); - if (Settings.INSTANCE.ENABLED_COMPONENTS.SLASH_COMMANDS) { - this.slashCommands = new SlashCommandManager(this, Settings.INSTANCE.ENABLED_COMPONENTS.REGISTER_ADMIN_SLASH_COMMANDS); - builder.addEventListeners(slashCommands); - } - if (Settings.INSTANCE.ENABLED_COMPONENTS.MESSAGE_COMMANDS) { - builder.addEventListeners(this); - } - builder - .setChunkingFilter(ChunkingFilter.NONE) - .setBulkDeleteSplittingEnabled(false) - .setCompression(Compression.ZLIB) - .setLargeThreshold(250) - .setMemberCachePolicy(MemberCachePolicy.ALL); - if (Settings.INSTANCE.DISCORD.INTENTS.GUILD_MEMBERS) { - builder.enableIntents(GatewayIntent.GUILD_MEMBERS); - } - if (Settings.INSTANCE.DISCORD.INTENTS.MESSAGE_CONTENT) { - builder.enableIntents(GatewayIntent.MESSAGE_CONTENT); - } - if (Settings.INSTANCE.DISCORD.INTENTS.GUILD_PRESENCES) { - builder.enableIntents(GatewayIntent.GUILD_PRESENCES); - } - if (Settings.INSTANCE.DISCORD.INTENTS.GUILD_MESSAGES) { - builder.enableIntents(GatewayIntent.GUILD_MESSAGES); - } - if (Settings.INSTANCE.DISCORD.INTENTS.GUILD_MESSAGE_REACTIONS) { - builder.enableIntents(GatewayIntent.GUILD_MESSAGE_REACTIONS); - } - if (Settings.INSTANCE.DISCORD.INTENTS.DIRECT_MESSAGES) { - builder.enableIntents(GatewayIntent.DIRECT_MESSAGES); - } - if (Settings.INSTANCE.DISCORD.INTENTS.EMOJI) { - builder.enableIntents(GatewayIntent.GUILD_EMOJIS_AND_STICKERS); - } - if (Settings.INSTANCE.DISCORD.CACHE.MEMBER_OVERRIDES) { - builder.enableCache(CacheFlag.MEMBER_OVERRIDES); - } - if (Settings.INSTANCE.DISCORD.CACHE.ONLINE_STATUS) { - builder.enableCache(CacheFlag.ONLINE_STATUS); - } - if (Settings.INSTANCE.DISCORD.CACHE.EMOTE) { - builder.enableCache(CacheFlag.EMOJI); - } -// Set whitelist = Settings.INSTANCE.Discord.Guilds.GET().WHITELIST(); -// long[] whitelistArr = new long[whitelist.size()]; -// int numShards = 10; -// for (int i = 0; i < numShards; i++) { -// long guildId = whitelistArr[i]; -// JDA instance = builder.useSharding(i, numShards).build(); -// manager.put(instance); -// } -// rootInstance = builder.useSharding(whitelistArr.length, whitelistArr.length + 1).build(); - - System.out.println("remove:|| building " + (((-start)) + (start = System.currentTimeMillis()))); - JDA jda = builder.build(); + JDA jda = loader.getJda(); try { + SlashCommandManager slashCommands = loader.getSlashCommandManager(); if (slashCommands != null) slashCommands.registerCommandData(jda); } catch (Throwable e) { // sometimes happen when discord api is spotty / timeout e.printStackTrace(); + Logg.text("Failed to update slash commands: " + e.getMessage()); } - System.out.println(":||Remove build " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); + Logg.text("remove:||PERF build " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); setSelfUser(jda); - System.out.println(":||Remove Setup slash commands " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); + Logg.text("remove:||PERF Setup slash commands " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); manager.put(jda); jda.awaitStatus(JDA.Status.LOADING_SUBSYSTEMS); - System.out.println(":||Remove subsystems " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); + Logg.text("remove:||PERF subsystems " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); jda.awaitReady(); setSelfUser(jda); if (Settings.INSTANCE.ENABLED_COMPONENTS.CREATE_DATABASES_ON_STARTUP) { initDBPartial(true); } - System.out.println(":||Remove init db " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); + Logg.text("Remove:||PERF init db " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); Guild rootGuild = manager.getGuildById(Settings.INSTANCE.ROOT_SERVER); if (rootGuild != null) { - System.out.println(":||Remove get guild " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); + Logg.text("remove:||PERF get guild " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); this.server = rootGuild; - System.out.println("remove:|| init db " + (((-start)) + (start = System.currentTimeMillis()))); + Logg.text("remove:||PERF init db " + (((-start)) + (start = System.currentTimeMillis()))); } else { throw new IllegalStateException("Invalid guild: " + Settings.INSTANCE.ROOT_SERVER + " as `root-server` in " + Settings.INSTANCE.getDefaultFile().getAbsolutePath()); } - System.out.println(":||Remove ready " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); + Logg.text("remove:||PERF ready " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); if (Settings.INSTANCE.ENABLED_COMPONENTS.REPEATING_TASKS) { initRepeatingTasks(); + Logg.text("remove:||PERF init repeating tasks " + (((-start)) + (start = System.currentTimeMillis()))); } - - System.out.println("remove:|| init repeating tasks " + (((-start)) + (start = System.currentTimeMillis()))); - -// for (long guildId : Settings.INSTANCE.MODERATION.BANNED_GUILDS.keySet()) { -// Guild guild = getDiscordApi().getGuildById(guildId); -// if (guild != null) { -// link.locutus.discord.util.RateLimitUtil.queue(guild.leave()); -// } -// } -// -// System.out.println("remove:|| banned guilds " + (((-start)) + (start = System.currentTimeMillis()))); -// -// if (!Settings.INSTANCE.MODERATION.BANNED_ALLIANCES.isEmpty()) { -// for (GuildDB value : getGuildDatabases().values()) { -// Guild guild = value.getGuild(); -// if (!guild.isLoaded()) continue; -// long owner = guild.getOwnerIdLong(); -// DBNation nation = DiscordUtil.getNation(owner); -// if (nation != null) { -// if (Settings.INSTANCE.MODERATION.BANNED_ALLIANCES.containsKey(nation.getAlliance_id())) { -// link.locutus.discord.util.RateLimitUtil.queue(guild.leave()); -// } -// } -// } -// } -// System.out.println("remove:|| banned alliances " + (((-start)) + (start = System.currentTimeMillis()))); - - // load members { List queue = new ArrayList<>(guildDatabases.values()); // sort by GuildDB.getLastModified (highest first) @@ -430,22 +246,23 @@ public Locutus start() throws InterruptedException, LoginException, SQLException public void run() { GuildDB db = queue.size() > index.get() ? queue.get(index.getAndIncrement()) : null; if (db == null || !db.getGuild().isLoaded()) { - System.out.println("Done loading guild members"); + Logg.text("Done loading guild members"); return; } Guild guild = db.getGuild(); - System.out.println(":||Remove Loading members for " + guild); + Logg.text("remove:||PERF Loading members for " + guild); guild.loadMembers().onSuccess(f -> { - System.out.println("Loaded " + f.size() + " members for " + guild); + Logg.text("Loaded " + f.size() + " members for " + guild); queueFunc[0].run(); }).onError(f -> { - System.out.println("Failed to load members for " + guild); + Logg.text("Failed to load members for " + guild); queueFunc[0].run(); }); } }; queueFunc[0].run(); } + Logg.text("remove:||PERF await members " + (((-start)) + (start = System.currentTimeMillis()))); } if (Settings.INSTANCE.ENABLED_COMPONENTS.WEB && Settings.INSTANCE.WEB.PORT > 0) { @@ -454,19 +271,21 @@ public void run() { } catch (Throwable e) { e.printStackTrace(); } + Logg.text("remove:||PERF setup web interface " + (((-start)) + (start = System.currentTimeMillis()))); } if (Settings.INSTANCE.ENABLED_COMPONENTS.REPEATING_TASKS && Settings.INSTANCE.ENABLED_COMPONENTS.SUBSCRIPTIONS) { this.pusher = new PnwPusherShardManager(); executor.submit(new Runnable() { @Override public void run() { - System.out.println("Loading pusher"); + Logg.text("Loading pusher"); pusher.load(); - System.out.println("Loaded pusher"); + Logg.text("Loaded pusher"); pusher.subscribeDefaultEvents(); - System.out.println("Subscribed to default events"); + Logg.text("Subscribed to default events"); } }); + Logg.text("remove:||PERF setup pusher " + (((-start)) + (start = System.currentTimeMillis()))); } if (Settings.INSTANCE.TASKS.CUSTOM_MESSAGE_HANDLER) { @@ -475,8 +294,10 @@ public void run() { addTaskSeconds(() -> { messageHandler.run(); }, 5 * 60); + Logg.text("remove:||PERF setup message handler " + (((-start)) + (start = System.currentTimeMillis()))); } - + loader.resolveFully(); + Logg.text("remove:||PERF resolve loader fully " + (((-start)) + (start = System.currentTimeMillis()))); return this; } @@ -495,16 +316,6 @@ private void setSelfUser(JDA jda) { } } - private void backup() { - int turnsCheck = Settings.INSTANCE.BACKUP.TURNS; - String script = Settings.INSTANCE.BACKUP.SCRIPT; - try { - Backup.backup(script, turnsCheck); - } catch (IOException e) { - e.printStackTrace(); - } - } - public GuildDB getRootCoalitionServer() { GuildDB locutusStats = Locutus.imp().getGuildDB(Settings.INSTANCE.ROOT_COALITION_SERVER); return locutusStats; @@ -522,7 +333,7 @@ public OffshoreInstance getRootBank() { public Auth getRootAuth() { Auth auth = getNationDB().getNation(Settings.INSTANCE.NATION_ID).getAuth(true); - if (auth != null) auth.setApiKey(Settings.INSTANCE.API_KEY_PRIMARY); + if (auth != null) auth.setApiKey(loader.getApiKey()); return auth; } @@ -545,7 +356,7 @@ public GuildDB getGuildDB(Guild guild) { guildDatabases.put(guild.getIdLong(), db); return db; } catch (Throwable e) { - System.out.println("Critical error creating GuildDB for " + guild); + Logg.text("Critical error creating GuildDB for " + guild); e.printStackTrace(); throw new RuntimeException(e); } @@ -599,7 +410,7 @@ public static CommandManager cmd() { } public SlashCommandManager getSlashCommands() { - return slashCommands; + return loader.getSlashCommandManager(); } public static Locutus imp() { @@ -613,31 +424,19 @@ public static void main(String[] args) throws InterruptedException, LoginExcepti Settings.INSTANCE.save(Settings.INSTANCE.getDefaultFile()); } public WarDB getWarDb() { - return warDb; + return loader.getWarDB(); } public BaseballDB getBaseballDB() { - if (this.baseBallDB == null) { - synchronized (this) { - if (this.baseBallDB == null) { - try { - baseBallDB = new BaseballDB(Settings.INSTANCE.DATABASE); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - } - } - return this.baseBallDB; + return loader.getBaseballDB(); } public TradeManager getTradeManager() { - this.tradeManager.load(); - return tradeManager; + return loader.getTradeManager(); } public CommandManager getCommandManager() { - return commandManager; + return loader.getCommandManager(); } public void autoRole(DBNation nation) { @@ -663,25 +462,12 @@ public void autoRole(DBNation nation) { } public StockDB getStockDB() { - return stockDB; + return loader.getStockDB(); } public ForumDB getForumDb() { - return forumDb; - } - -// public Set getDatabases() { -// Set databases = new HashSet<>(); -// databases.add(tradeManager.getTradeDb()); -// databases.add(forumDb); -// databases.add(discordDB); -// databases.add(nationDB); -// databases.add(warDb); -// databases.add(bankDb); -// databases.add(stockDB); -// databases.addAll(guildDatabases.values()); -// return databases; -// } + return loader.getForumDB(); + } public ScheduledFuture addTaskSeconds(CaughtTask task, long interval) { return addTask(CaughtRunnable.wrap(task), interval, TimeUnit.SECONDS); @@ -697,7 +483,7 @@ public void runUnsafe() { } }; } - return commandManager.getExecutor().scheduleWithFixedDelay(task, interval, interval, unit); + return loader.getCommandManager().getExecutor().scheduleWithFixedDelay(task, interval, interval, unit); } public void runEventsAsync(ThrowingConsumer> eventHandler) { @@ -722,12 +508,12 @@ public PnwPusherShardManager getPusher() { public void initRepeatingTasks() { Object warUpdateLock = new Object(); - if ((Settings.INSTANCE.TASKS.ACTIVE_NATION_SECONDS > 0 || Settings.INSTANCE.TASKS.COLORED_NATIONS_SECONDS > 0 || Settings.INSTANCE.TASKS.ALL_NON_VM_NATIONS_SECONDS > 0) && nationDB.getNations().isEmpty()) { - logger.info("No nations found. Updating all nations"); + if ((Settings.INSTANCE.TASKS.ACTIVE_NATION_SECONDS > 0 || Settings.INSTANCE.TASKS.COLORED_NATIONS_SECONDS > 0 || Settings.INSTANCE.TASKS.ALL_NON_VM_NATIONS_SECONDS > 0) && getNationDB().getNations().isEmpty()) { + Logg.text("No nations found. Updating all nations"); if (Settings.USE_V2) { - nationDB.updateNationsV2(true, null); + getNationDB().updateNationsV2(true, null); } else { - nationDB.updateAllNations(null); + getNationDB().updateAllNations(null); } } @@ -761,57 +547,57 @@ public void runUnsafe() throws Exception { } if (Settings.USE_V2) { addTaskSeconds(() -> { - runEventsAsync(events -> nationDB.updateNationsV2(false, events)); + runEventsAsync(events -> getNationDB().updateNationsV2(false, events)); }, Settings.INSTANCE.TASKS.COLORED_NATIONS_SECONDS); addTaskSeconds(() -> { - runEventsAsync(events -> nationDB.updateNationsV2(true, events)); + runEventsAsync(events -> getNationDB().updateNationsV2(true, events)); }, Settings.INSTANCE.TASKS.ALL_NON_VM_NATIONS_SECONDS); addTaskSeconds(() -> { - runEventsAsync(events -> nationDB.updateCitiesV2(events)); + runEventsAsync(events -> getNationDB().updateCitiesV2(events)); }, Settings.INSTANCE.TASKS.ALL_NON_VM_NATIONS_SECONDS); addTaskSeconds(() -> { synchronized (warUpdateLock) { - System.out.println("Start update wars 1"); + Logg.text("Start update wars 1"); long start = System.currentTimeMillis(); - runEventsAsync(warDb::updateAllWarsV2); - System.out.println("Update wars 1.1 took " + ( - start + (start = System.currentTimeMillis()))); - runEventsAsync(e -> warDb.updateAttacks(true, e, true)); - System.out.println("Update wars 1.2 took " + ( - start + (start = System.currentTimeMillis()))); + runEventsAsync(getWarDb()::updateAllWarsV2); + Logg.text("Update wars 1.1 took " + ( - start + (start = System.currentTimeMillis()))); + runEventsAsync(e -> getWarDb().updateAttacks(true, e, true)); + Logg.text("Update wars 1.2 took " + ( - start + (start = System.currentTimeMillis()))); } }, Settings.INSTANCE.TASKS.ALL_WAR_SECONDS); } else { addTaskSeconds(() -> { try { - System.out.println("Update most active nations"); - runEventsAsync(events -> nationDB.updateMostActiveNations(490, events)); + Logg.text("Update most active nations"); + runEventsAsync(events -> getNationDB().updateMostActiveNations(490, events)); } catch (Throwable e) { e.printStackTrace(); } }, Settings.INSTANCE.TASKS.ACTIVE_NATION_SECONDS); addTaskSeconds(() -> { - runEventsAsync(nationDB::updateTreaties); + runEventsAsync(getNationDB()::updateTreaties); }, Settings.INSTANCE.TASKS.TREATY_UPDATE_SECONDS); addTaskSeconds(() -> { - runEventsAsync(f -> bankDb.updateBankRecs(false, f)); + runEventsAsync(f -> getBankDB().updateBankRecs(false, f)); }, Settings.INSTANCE.TASKS.BANK_RECORDS_INTERVAL_SECONDS); addTaskSeconds(() -> { - runEventsAsync(nationDB::updateRecentNations); + runEventsAsync(getNationDB()::updateRecentNations); }, Settings.INSTANCE.TASKS.COLORED_NATIONS_SECONDS); addTaskSeconds(() -> { - runEventsAsync(events -> nationDB.updateNonVMNations(events)); + runEventsAsync(events -> getNationDB().updateNonVMNations(events)); }, Settings.INSTANCE.TASKS.ALL_NON_VM_NATIONS_SECONDS); addTaskSeconds(() -> { - runEventsAsync(f -> nationDB.updateDirtyCities(false, f)); + runEventsAsync(f -> getNationDB().updateDirtyCities(false, f)); }, Settings.INSTANCE.TASKS.OUTDATED_CITIES_SECONDS); if (Settings.INSTANCE.TASKS.FETCH_SPIES_INTERVAL_SECONDS > 0) { @@ -823,19 +609,19 @@ public void runUnsafe() throws Exception { addTaskSeconds(() -> { try { - System.out.println("Start update wars 1"); + Logg.text("Start update wars 1"); synchronized (warUpdateLock) { - System.out.println("Start update wars 1.1"); + Logg.text("Start update wars 1.1"); long start = System.currentTimeMillis(); - System.out.println("Start update wars 1.2"); - runEventsAsync(f -> warDb.updateActiveWars(f, false)); - System.out.println("Start update wars 1.3"); - runEventsAsync(warDb::fetchNewWars); - System.out.println("Start update wars 1.4"); - runEventsAsync(warDb::updateAttacks); - System.out.println("Start update wars 1.5"); + Logg.text("Start update wars 1.2"); + runEventsAsync(f -> getWarDb().updateActiveWars(f, false)); + Logg.text("Start update wars 1.3"); + runEventsAsync(getWarDb()::fetchNewWars); + Logg.text("Start update wars 1.4"); + runEventsAsync(getWarDb()::updateAttacks); + Logg.text("Start update wars 1.5"); } - System.out.println("End update wars 1.5"); + Logg.text("End update wars 1.5"); } catch (Throwable e) { e.printStackTrace(); } @@ -844,13 +630,13 @@ public void runUnsafe() throws Exception { // addTaskSeconds(() -> { // synchronized (warUpdateLock) { -// System.out.println("Start update wars"); +// Logg.text("Start update wars"); // long start1 = System.currentTimeMillis(); // runEventsAsync(warDb::updateAllWars); // runEventsAsync(warDb::updateAttacks); // long diff1 = System.currentTimeMillis() - start1; // { -// System.out.println("Update wars took " + diff1); +// Logg.text("Update wars took " + diff1); // } // // if (Settings.INSTANCE.TASKS.ESCALATION_ALERTS) { @@ -901,8 +687,8 @@ public void runUnsafe() throws Exception { addTaskSeconds(beigeAlerter::run, Settings.INSTANCE.TASKS.BEIGE_REMINDER_SECONDS); } - if (forumDb != null && Settings.INSTANCE.TASKS.FORUM_UPDATE_INTERVAL_SECONDS > 0) { - addTaskSeconds(forumDb::update, Settings.INSTANCE.TASKS.FORUM_UPDATE_INTERVAL_SECONDS); + if (getForumDb() != null && Settings.INSTANCE.TASKS.FORUM_UPDATE_INTERVAL_SECONDS > 0) { + addTaskSeconds(getForumDb()::update, Settings.INSTANCE.TASKS.FORUM_UPDATE_INTERVAL_SECONDS); } } @@ -910,7 +696,7 @@ private void runTurnTasks(long lastTurn, long currentTurn) { try { new TurnChangeEvent(lastTurn, currentTurn).post(); - for (DBNation nation : nationDB.getNations().values()) { + for (DBNation nation : getNationDB().getNations().values()) { nation.processTurnChange(lastTurn, currentTurn, Event::post); } @@ -923,27 +709,26 @@ private void runTurnTasks(long lastTurn, long currentTurn) { // Update all nations { - runEventsAsync(events -> nationDB.updateNonVMNations(events)); + runEventsAsync(events -> getNationDB().updateNonVMNations(events)); } { - runEventsAsync(events -> nationDB.updateMostActiveNations(490, events)); + runEventsAsync(events -> getNationDB().updateMostActiveNations(490, events)); } { - runEventsAsync(events -> nationDB.updateAlliances(null, events)); + runEventsAsync(events -> getNationDB().updateAlliances(null, events)); } - runEventsAsync(nationDB::deleteExpiredTreaties); - runEventsAsync(nationDB::updateTreaties); + runEventsAsync(getNationDB()::deleteExpiredTreaties); + runEventsAsync(getNationDB()::updateTreaties); try { - runEventsAsync(nationDB::updateBans); + runEventsAsync(getNationDB()::updateBans); } catch (Throwable e) { e.printStackTrace(); } - nationDB.saveAllCities(); // TODO save all cities + getNationDB().saveAllCities(); // TODO save all cities - - tradeManager.updateColorBlocs(); // TODO move to configurable task + getTradeManager().updateColorBlocs(); // TODO move to configurable task } if (Settings.INSTANCE.TASKS.TURN_TASKS.ALLIANCE_METRICS) { @@ -975,7 +760,7 @@ private void checkMailTasks() { try { Auth auth = nation.getAuth(true); AlertMailTask alertMailTask = new AlertMailTask(auth, channelId); - commandManager.getExecutor().scheduleWithFixedDelay(alertMailTask, 60, task.FETCH_INTERVAL_SECONDS, TimeUnit.SECONDS); + getCommandManager().getExecutor().scheduleWithFixedDelay(alertMailTask, 60, task.FETCH_INTERVAL_SECONDS, TimeUnit.SECONDS); } catch (IllegalArgumentException e) { AlertUtil.error("Mail error", "Cannot check mail for " + section + "(nation=" + nationId + "): They are not authenticated (user/pass)"); } @@ -987,11 +772,11 @@ public Guild getServer() { } public DiscordDB getDiscordDB() { - return discordDB; + return loader.getDiscordDB(); } public NationDB getNationDB() { - return nationDB; + return loader.getNationDB(); } public JDA getDiscordApi(long guildId) { @@ -999,11 +784,11 @@ public JDA getDiscordApi(long guildId) { } public PoliticsAndWarV3 getV3() { - return v3; + return loader.getApiV3(); } public PoliticsAndWarV2 getPnwApiV2() { - return pnwApi; + return loader.getApiV2(); } @Override @@ -1029,13 +814,13 @@ public void run() { @Override public void onGuildJoin(@Nonnull GuildJoinEvent event) { manager.put(event.getGuild().getIdLong(), event.getJDA()); - System.out.println(":||Remove load members guild join"); + Logg.text("remove:||PERF load members guild join"); event.getGuild().loadMembers(); } @Override public void onGuildAvailable(@NotNull GuildAvailableEvent event) { - System.out.println(":||Remove load members guild available"); + Logg.text("remove:||PERF load members guild available"); event.getGuild().loadMembers(); } @@ -1050,7 +835,7 @@ public void onGuildInviteCreate(@Nonnull GuildInviteCreateEvent event) { @Override public void onGuildMemberJoin(@Nonnull GuildMemberJoinEvent event) { - System.out.println(":||Remove Guild member join debug| " + event.getGuild() + " | " + event.getUser()); + Logg.text("remove:||PERF Guild member join debug| " + event.getGuild() + " | " + event.getUser()); executor.submit(() -> { try { Guild guild = event.getGuild(); @@ -1131,7 +916,7 @@ public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { Message message = event.getMessage(); Button button = event.getButton(); - System.out.println("Button press " + button.getId() + " | " + button.getLabel()); + Logg.text("Button press " + button.getId() + " | " + button.getLabel()); if (button.getId().equalsIgnoreCase("")) { RateLimitUtil.queue(message.delete()); @@ -1139,7 +924,7 @@ public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { } if (message.getAuthor().getIdLong() != Settings.INSTANCE.APPLICATION_ID) { - System.out.println("Author not application"); + Logg.text("Author not application"); return; } @@ -1203,7 +988,7 @@ public void onButtonInteraction(@NotNull ButtonInteractionEvent event) { hookIO.setIsModal(event); } - if (!id.isEmpty() && (id.startsWith(Settings.commandPrefix(true)) || commandManager.isModernPrefix(id.charAt(0)))) { + if (!id.isEmpty() && (id.startsWith(Settings.commandPrefix(true)) || getCommandManager().isModernPrefix(id.charAt(0)))) { success |= handleCommandReaction(id, message, ioToUse, user, true); hasLegacyCommand = true; } else if (id.startsWith("{")) { @@ -1274,7 +1059,7 @@ public void onMessageReceived(@NotNull MessageReceivedEvent event) { String message = event.getMessage().getContentRaw(); DiscordChannelIO io = new DiscordChannelIO(event.getChannel(), () -> event.getMessage()); - commandManager.run(guild, io, author, message, true, true); + getCommandManager().run(guild, io, author, message, true, true); long diff = System.currentTimeMillis() - start; if (diff > 1000) { StringBuilder response = new StringBuilder("## Long action: " + event.getAuthor().getIdLong() + " | " + event.getAuthor().getName() + ": " + DiscordUtil.trimContent(event.getMessage().getContentRaw())); @@ -1338,12 +1123,12 @@ private boolean handleCommandReaction(String cmd, Message message, IMessageIO io boolean legacy = cmd.charAt(0) == Settings.commandPrefix(true).charAt(0); if (legacy) { String cmdLabel = cmd.split(" ")[0].substring(1); - cmdObject = commandManager.getCommandMap().get(cmdLabel.toLowerCase()); + cmdObject = getCommandManager().getCommandMap().get(cmdLabel.toLowerCase()); if (cmdObject == null) { return false; } } - System.out.println("CMD1 " + cmd); + Logg.text("CMD1 " + cmd); if (!(cmdObject instanceof Noformat)) { DBNation nation = DiscordUtil.getNation(user); NationPlaceholders formatter = Locutus.imp().getCommandManager().getV2().getNationPlaceholders(); @@ -1360,8 +1145,8 @@ private boolean handleCommandReaction(String cmd, Message message, IMessageIO io return false; } } - System.out.println("Run " + io.getClass()); - commandManager.run(guild, io, user, cmd, async, false); + Logg.text("Run " + io.getClass()); + getCommandManager().run(guild, io, user, cmd, async, false); return true; } @@ -1421,8 +1206,8 @@ public void onMessageReact(Message message, User user, EmojiUnion emote, long re DiscordChannelIO io = new DiscordChannelIO(channel, () -> message); - String[] split = raw.split("\\r?\\n(?=[" + StringMan.join(commandManager.getAllPrefixes(), "|") + "|{])"); - System.out.println("Split " + StringMan.getString(split)); + String[] split = raw.split("\\r?\\n(?=[" + StringMan.join(getCommandManager().getAllPrefixes(), "|") + "|{])"); + Logg.text("Split " + StringMan.getString(split)); for (String cmd : split) { success |= handleCommandReaction(cmd, message, io, user, async); } @@ -1442,7 +1227,7 @@ public void onMessageReact(Message message, User user, EmojiUnion emote, long re } public BankDB getBankDB() { - return this.bankDb; + return loader.getBankDB(); } public ExecutorService getExecutor() { @@ -1461,7 +1246,8 @@ public void stop() { // close pusher subscriptions executor.shutdownNow(); - if (commandManager != null) commandManager.getExecutor().shutdownNow(); + CommandManager cmdManager = getCommandManager(); + if (cmdManager != null) cmdManager.getExecutor().shutdownNow(); // join all threads for (Thread thread : Thread.getAllStackTraces().keySet()) { @@ -1476,9 +1262,9 @@ public void stop() { Thread.sleep(5000); } catch (InterruptedException e) {} - System.out.println("\n == Ignore the following if the thread doesn't relate to anything modifying persistent data"); + Logg.text("\n == Ignore the following if the thread doesn't relate to anything modifying persistent data"); for (Map.Entry thread : Thread.getAllStackTraces().entrySet()) { - System.out.println("Thread did not close after 5s: " + thread.getKey() + "\n- " + StringMan.stacktraceToString(thread.getValue())); + Logg.text("Thread did not close after 5s: " + thread.getKey() + "\n- " + StringMan.stacktraceToString(thread.getValue())); } System.exit(1); @@ -1509,4 +1295,8 @@ public DataDumpParser getDataDumper(boolean throwError) { } return dataDumpParser; } + + public void setLoader(ILoader loader) { + this.loader = loader; + } } diff --git a/src/main/java/link/locutus/discord/Logg.java b/src/main/java/link/locutus/discord/Logg.java index 49ebe205..f950c316 100644 --- a/src/main/java/link/locutus/discord/Logg.java +++ b/src/main/java/link/locutus/discord/Logg.java @@ -30,7 +30,13 @@ public static void text(String msg, Object... obj) { LOGGER.error(msg, obj); } + private static volatile boolean setInfoLogging = false; + public static void setInfoLogging() { + if (setInfoLogging) { + return; + } + setInfoLogging = true; // org.apache.log4j.Logger.getRootLogger().setLevel(Level.INFO); // Configurator.setRootLevel(org.apache.logging.log4j.Level.INFO); System.setProperty("Log4jContextSelector", AsyncLoggerContextSelector.class.getName()); diff --git a/src/main/java/link/locutus/discord/Backup.java b/src/main/java/link/locutus/discord/_main/Backup.java similarity index 97% rename from src/main/java/link/locutus/discord/Backup.java rename to src/main/java/link/locutus/discord/_main/Backup.java index 89cffadc..85d9d8ae 100644 --- a/src/main/java/link/locutus/discord/Backup.java +++ b/src/main/java/link/locutus/discord/_main/Backup.java @@ -1,4 +1,4 @@ -package link.locutus.discord; +package link.locutus.discord._main; import link.locutus.discord.config.Settings; import link.locutus.discord.util.TimeUtil; @@ -11,8 +11,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.util.Scanner; public class Backup { diff --git a/src/main/java/link/locutus/discord/_main/FinalizedLoader.java b/src/main/java/link/locutus/discord/_main/FinalizedLoader.java new file mode 100644 index 00000000..027cb2de --- /dev/null +++ b/src/main/java/link/locutus/discord/_main/FinalizedLoader.java @@ -0,0 +1,30 @@ +package link.locutus.discord._main; + +import link.locutus.discord.config.Settings; +import link.locutus.discord.db.BaseballDB; + +import java.sql.SQLException; + +public class FinalizedLoader implements ILoader { + private volatile BaseballDB baseBallDB; + + public FinalizedLoader(PreLoader loader) { + + } + + @Override + public BaseballDB getBaseballDB() { + if (this.baseBallDB == null) { + synchronized (this) { + if (this.baseBallDB == null) { + try { + baseBallDB = new BaseballDB(Settings.INSTANCE.DATABASE); + } catch (SQLException e) { + throw new RuntimeException(e); + } + } + } + } + return this.baseBallDB; + } +} diff --git a/src/main/java/link/locutus/discord/_main/ILoader.java b/src/main/java/link/locutus/discord/_main/ILoader.java new file mode 100644 index 00000000..48b9b6a7 --- /dev/null +++ b/src/main/java/link/locutus/discord/_main/ILoader.java @@ -0,0 +1,42 @@ +package link.locutus.discord._main; + +import link.locutus.discord.apiv2.PoliticsAndWarV2; +import link.locutus.discord.apiv3.PoliticsAndWarV3; +import link.locutus.discord.commands.manager.CommandManager; +import link.locutus.discord.commands.manager.v2.impl.SlashCommandManager; +import link.locutus.discord.commands.stock.StockDB; +import link.locutus.discord.config.Settings; +import link.locutus.discord.db.*; +import link.locutus.discord.util.trade.TradeManager; +import net.dv8tion.jda.api.JDA; + +public interface ILoader { + ILoader resolveFully(); + + default String getApiKey() { + return Settings.INSTANCE.API_KEY_PRIMARY; + } + + default int getNationId() { + return Settings.INSTANCE.NATION_ID; + } + + default long getAdminUserId() { + return Settings.INSTANCE.ADMIN_USER_ID; + } + JDA getJda(); + SlashCommandManager getSlashCommandManager(); + CommandManager getCommandManager(); + + NationDB getNationDB(); + DiscordDB getDiscordDB(); + WarDB getWarDB(); + BaseballDB getBaseballDB(); + TradeManager getTradeManager(); + StockDB getStockDB(); + ForumDB getForumDB(); + BankDB getBankDB(); + + PoliticsAndWarV3 getApiV3(); + PoliticsAndWarV2 getApiV2(); +} diff --git a/src/main/java/link/locutus/discord/_main/PreLoader.java b/src/main/java/link/locutus/discord/_main/PreLoader.java new file mode 100644 index 00000000..78901e33 --- /dev/null +++ b/src/main/java/link/locutus/discord/_main/PreLoader.java @@ -0,0 +1,275 @@ +package link.locutus.discord._main; + +import link.locutus.discord.Locutus; +import link.locutus.discord.Logg; +import link.locutus.discord.apiv1.PoliticsAndWarBuilder; +import link.locutus.discord.apiv1.core.ApiKeyPool; +import link.locutus.discord.apiv2.PoliticsAndWarV2; +import link.locutus.discord.apiv3.PoliticsAndWarV3; +import link.locutus.discord.apiv3.subscription.PnwPusherShardManager; +import link.locutus.discord.commands.manager.CommandManager; +import link.locutus.discord.commands.manager.v2.impl.SlashCommandManager; +import link.locutus.discord.commands.manager.v2.impl.pw.CommandManager2; +import link.locutus.discord.commands.stock.StockDB; +import link.locutus.discord.config.Settings; +import link.locutus.discord.db.*; +import link.locutus.discord.db.handlers.GuildCustomMessageHandler; +import link.locutus.discord.pnw.PNWUser; +import link.locutus.discord.util.FileUtil; +import link.locutus.discord.util.MathMan; +import link.locutus.discord.util.offshore.Auth; +import link.locutus.discord.util.scheduler.ThrowingSupplier; +import link.locutus.discord.util.trade.TradeManager; +import link.locutus.discord.web.jooby.WebRoot; +import net.dv8tion.jda.api.JDA; +import net.dv8tion.jda.api.JDABuilder; +import net.dv8tion.jda.api.entities.Guild; +import net.dv8tion.jda.api.requests.GatewayIntent; +import net.dv8tion.jda.api.utils.ChunkingFilter; +import net.dv8tion.jda.api.utils.Compression; +import net.dv8tion.jda.api.utils.MemberCachePolicy; +import net.dv8tion.jda.api.utils.cache.CacheFlag; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; +import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; + +public class PreLoader implements ILoader { + private final ExecutorService executor; + private final Locutus locutus; + private final Future forumDb; + private final Future discordDB; + private final Future nationDB; + private final Future warDb; + private final Future stockDB; + private final Future bankDb; + private final Future tradeManager; + private final Future commandManager; + private final Future> getApiKeyPrimary; + private final Future> getNationId; + private final Future> adminUserId; + private final Future apiV2; + private final Future apiV3; + // futures + private List> resolvers; + private volatile FinalizedLoader finalized; + // fields + private final Future slashCommandManager; + private final Future jda; + + public PreLoader(Locutus locutus, ExecutorService executor) { + this.executor = executor; + this.resolvers = new ArrayList<>(); + this.locutus = locutus; + + // todo fixme remove calls of Locutus.imp() + + this.slashCommandManager = add("Slash Command Manager", new ThrowingSupplier() { + @Override + public SlashCommandManager getThrows() throws Exception { + return new SlashCommandManager(Settings.INSTANCE.ENABLED_COMPONENTS.REGISTER_ADMIN_SLASH_COMMANDS, () -> Locutus.cmd().getV2()); + } + }); + this.jda = add("Discord Hook", this::buildJDA); + this.discordDB = add("Discord Database", () -> new DiscordDB()); + this.nationDB = add("Nation Database", () -> new NationDB().load()); + this.warDb = add("War Database", () -> new WarDB().load()); + this.stockDB = add("Stock Database", () -> new StockDB()); + this.bankDb = add("Bank Database", () -> new BankDB()); + this.tradeManager = add("Trade Database", () -> new TradeManager().load()); + if (Settings.INSTANCE.FORUM_FEED_SERVER > 0) { + this.forumDb = add("Forum Database", () -> new ForumDB(Settings.INSTANCE.FORUM_FEED_SERVER)); + } else { + forumDb = CompletableFuture.completedFuture(null); + } + this.commandManager = add("Command Handler", () -> new CommandManager(locutus)); + + if (Settings.INSTANCE.API_KEY_PRIMARY.isEmpty()) { + Auth auth = new Auth(0, Settings.INSTANCE.USERNAME, Settings.INSTANCE.PASSWORD); + getApiKeyPrimary = add("Fetch API Key", () -> { + ApiKeyPool.ApiKey key = auth.fetchApiKey(); + Settings.INSTANCE.API_KEY_PRIMARY = key.getKey(); + return () -> Settings.INSTANCE.API_KEY_PRIMARY; + }); + } else { + getApiKeyPrimary = CompletableFuture.completedFuture(() -> Settings.INSTANCE.API_KEY_PRIMARY); + } + if (Settings.INSTANCE.NATION_ID <= 0) { + Settings.INSTANCE.NATION_ID = 0; + this.getNationId = add("Fetch Nation ID", new ThrowingSupplier>() { + @Override + public Supplier getThrows() throws Exception { + Integer nationIdFromKey = getDiscordDB().getNationFromApiKey(Settings.INSTANCE.API_KEY_PRIMARY); + if (nationIdFromKey == null) { + Settings.INSTANCE.NATION_ID = -1; + } else { + Settings.INSTANCE.NATION_ID = nationIdFromKey; + } + return () -> Settings.INSTANCE.NATION_ID; + } + }); + } else { + this.getNationId = CompletableFuture.completedFuture(() -> Settings.INSTANCE.NATION_ID); + } + if (Settings.INSTANCE.ADMIN_USER_ID <= 0) { + this.adminUserId = add("Discord Admin User ID", new ThrowingSupplier>() { + @Override + public Supplier getThrows() throws Exception { + PNWUser adminPnwUser = getDiscordDB().getUserFromNationId(Settings.INSTANCE.NATION_ID); + if (adminPnwUser != null) { + Settings.INSTANCE.ADMIN_USER_ID = adminPnwUser.getDiscordId(); + } + return () -> Settings.INSTANCE.ADMIN_USER_ID; + } + }); + } else { + this.adminUserId = CompletableFuture.completedFuture(() -> Settings.INSTANCE.ADMIN_USER_ID); + } + this.apiV2 = add("PW-API V2", () -> { + List pool = new ArrayList<>(); + pool.addAll(Settings.INSTANCE.API_KEY_POOL); + if (pool.isEmpty()) { + pool.add(Settings.INSTANCE.API_KEY_PRIMARY); + } + return new PoliticsAndWarBuilder().addApiKeys(pool.toArray(new String[0])).setEnableCache(false).setTestServerMode(Settings.INSTANCE.TEST).build(); + }); + this.apiV3 = add("PW-API V3", () -> { + ApiKeyPool v3Pool = ApiKeyPool.builder() + .addKey(Settings.INSTANCE.NATION_ID, + Settings.INSTANCE.API_KEY_PRIMARY, + Settings.INSTANCE.ACCESS_KEY) + .build(); + return new PoliticsAndWarV3(v3Pool); + }); + + add("Register Discord Commands", () -> { + CommandManager cmdMan = getCommandManager(); + CommandManager2 v2 = cmdMan.getV2(); + v2.registerDefaults(); + DiscordDB db = getDiscordDB(); + cmdMan.registerCommands(db); + return null; + }); + } + + @Override + public String getApiKey() { + return FileUtil.get(getApiKeyPrimary).get(); + } + + @Override + public int getNationId() { + return FileUtil.get(getNationId).get(); + } + @Override + public long getAdminUserId() { + return FileUtil.get(adminUserId).get(); + } + + @Override + public ILoader resolveFully() { + List> tmp = resolvers; + if (finalized != null) return finalized; + synchronized (this) { + if (finalized != null) { + return finalized; + } + for (Future resolver : tmp) { + try { + resolver.get(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + resolvers = null; + this.finalized = new FinalizedLoader(this); + locutus.setLoader(finalized); + return finalized; + } + } + + private Future add(String taskName, ThrowingSupplier supplier) { + Future future = executor.submit(new Callable() { + @Override + public T call() throws Exception { + try { + Logg.text("Loading `TASK:" + taskName + "`"); + long start = System.currentTimeMillis(); + T result = supplier.get(); + long end = System.currentTimeMillis(); + if (end - start > 15 || true) { + Logg.text("Completed `TASK:" + taskName + "` in " + MathMan.format((end - start) / 1000d) + "s"); + } + + return result; + } catch (Throwable e) { + e.printStackTrace(); + throw e; + } + } + }); + resolvers.add(future); + return future; + } + + private JDA buildJDA() throws ExecutionException, InterruptedException { + JDABuilder builder = JDABuilder.createLight(Settings.INSTANCE.BOT_TOKEN, GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGES, GatewayIntent.DIRECT_MESSAGES); + if (Settings.INSTANCE.ENABLED_COMPONENTS.SLASH_COMMANDS) { + builder.addEventListeners(slashCommandManager.get()); + } + if (Settings.INSTANCE.ENABLED_COMPONENTS.MESSAGE_COMMANDS) { + builder.addEventListeners(this); + } + builder + .setChunkingFilter(ChunkingFilter.NONE) + .setBulkDeleteSplittingEnabled(false) + .setCompression(Compression.ZLIB) + .setLargeThreshold(250) + .setMemberCachePolicy(MemberCachePolicy.ALL); + if (Settings.INSTANCE.DISCORD.INTENTS.GUILD_MEMBERS) { + builder.enableIntents(GatewayIntent.GUILD_MEMBERS); + } + if (Settings.INSTANCE.DISCORD.INTENTS.MESSAGE_CONTENT) { + builder.enableIntents(GatewayIntent.MESSAGE_CONTENT); + } + if (Settings.INSTANCE.DISCORD.INTENTS.GUILD_PRESENCES) { + builder.enableIntents(GatewayIntent.GUILD_PRESENCES); + } + if (Settings.INSTANCE.DISCORD.INTENTS.GUILD_MESSAGES) { + builder.enableIntents(GatewayIntent.GUILD_MESSAGES); + } + if (Settings.INSTANCE.DISCORD.INTENTS.GUILD_MESSAGE_REACTIONS) { + builder.enableIntents(GatewayIntent.GUILD_MESSAGE_REACTIONS); + } + if (Settings.INSTANCE.DISCORD.INTENTS.DIRECT_MESSAGES) { + builder.enableIntents(GatewayIntent.DIRECT_MESSAGES); + } + if (Settings.INSTANCE.DISCORD.INTENTS.EMOJI) { + builder.enableIntents(GatewayIntent.GUILD_EMOJIS_AND_STICKERS); + } + if (Settings.INSTANCE.DISCORD.CACHE.MEMBER_OVERRIDES) { + builder.enableCache(CacheFlag.MEMBER_OVERRIDES); + } + if (Settings.INSTANCE.DISCORD.CACHE.ONLINE_STATUS) { + builder.enableCache(CacheFlag.ONLINE_STATUS); + } + if (Settings.INSTANCE.DISCORD.CACHE.EMOTE) { + builder.enableCache(CacheFlag.EMOJI); + } + return builder.build(); + } + + private void backup() { + int turnsCheck = Settings.INSTANCE.BACKUP.TURNS; + String script = Settings.INSTANCE.BACKUP.SCRIPT; + try { + Backup.backup(script, turnsCheck); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/link/locutus/discord/apiv3/PoliticsAndWarV3.java b/src/main/java/link/locutus/discord/apiv3/PoliticsAndWarV3.java index 675a101f..f2737ab3 100644 --- a/src/main/java/link/locutus/discord/apiv3/PoliticsAndWarV3.java +++ b/src/main/java/link/locutus/discord/apiv3/PoliticsAndWarV3.java @@ -6,7 +6,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import link.locutus.discord.Locutus; -import link.locutus.discord.RequestTracker; import link.locutus.discord.apiv1.enums.Rank; import link.locutus.discord.apiv1.enums.ResourceType; import link.locutus.discord.apiv1.enums.TreatyType; @@ -1932,7 +1931,7 @@ private static HttpHeaders getHttpHeaders(String api, String bot) { if (api != null && bot != null && !bot.isEmpty()) { headers.set("X-Api-Key", api); } else { - headers.set("X-Api-Key", Settings.INSTANCE.API_KEY_PRIMARY); + headers.set("X-Api-Key", Locutus.loader().getApiKey()); } if (bot != null && !bot.isEmpty()) { headers.set("X-Bot-Key", bot); diff --git a/src/main/java/link/locutus/discord/apiv3/README.md b/src/main/java/link/locutus/discord/apiv3/README.md index 99249653..ef4af4e1 100644 --- a/src/main/java/link/locutus/discord/apiv3/README.md +++ b/src/main/java/link/locutus/discord/apiv3/README.md @@ -1,6 +1,9 @@ # About this directory - This reuses the pool from previous API versions - - All java classes are generated from the schema file (see resources directory) + - All type classes are generated from the schema file (see resources directory) + - The csv directory handles parsing of the PW nation and city data csv files - See the build.gradle for the task compiling the schema to java class + - The main handler for queries is PoliticsAndWarV3 + - The RequestTracker handles rate limiting and request prioritization PWAPIV3 is not used. Ignore it. \ No newline at end of file diff --git a/src/main/java/link/locutus/discord/RequestTracker.java b/src/main/java/link/locutus/discord/apiv3/RequestTracker.java similarity index 98% rename from src/main/java/link/locutus/discord/RequestTracker.java rename to src/main/java/link/locutus/discord/apiv3/RequestTracker.java index a64570dd..04e4603a 100644 --- a/src/main/java/link/locutus/discord/RequestTracker.java +++ b/src/main/java/link/locutus/discord/apiv3/RequestTracker.java @@ -1,7 +1,6 @@ -package link.locutus.discord; +package link.locutus.discord.apiv3; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.objects.Object2IntLinkedOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import link.locutus.discord.util.FileUtil; @@ -13,8 +12,6 @@ import org.springframework.web.client.HttpClientErrorException; import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; diff --git a/src/main/java/link/locutus/discord/commands/README.md b/src/main/java/link/locutus/discord/commands/README.md new file mode 100644 index 00000000..46ed6bcd --- /dev/null +++ b/src/main/java/link/locutus/discord/commands/README.md @@ -0,0 +1,2 @@ +This directory contains files relating to commands +See manager/v2 for the newer commands, the other directories are deprecated \ No newline at end of file diff --git a/src/main/java/link/locutus/discord/commands/manager/CommandManager.java b/src/main/java/link/locutus/discord/commands/manager/CommandManager.java index 6d25e2b5..fbb35a3e 100644 --- a/src/main/java/link/locutus/discord/commands/manager/CommandManager.java +++ b/src/main/java/link/locutus/discord/commands/manager/CommandManager.java @@ -2,6 +2,7 @@ import it.unimi.dsi.fastutil.chars.CharOpenHashSet; import link.locutus.discord.Locutus; +import link.locutus.discord.Logg; import link.locutus.discord.apiv1.enums.ResourceType; import link.locutus.discord.apiv3.enums.NationLootType; import link.locutus.discord.commands.account.*; @@ -154,8 +155,9 @@ public CommandManager(Locutus locutus) { } this.commandMap = new LinkedHashMap<>(); this.executor = new ScheduledThreadPoolExecutor(256); - + Logg.text("remove:||PERF commandmanager executor " + (-start + (start = System.currentTimeMillis())) + "ms"); modernized = new CommandManager2(); + Logg.text("remove:||PERF commandmanager modernized " + (-start + (start = System.currentTimeMillis())) + "ms"); } public boolean isModernPrefix(char prefix) { @@ -560,9 +562,6 @@ private void threadDump() { } public void registerCommands(DiscordDB db) { - if (modernized != null) { - modernized.registerDefaults(); - } this.register(new RaidCommand()); /// not useful // this.register(new Kev()); diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/impl/SlashCommandManager.java b/src/main/java/link/locutus/discord/commands/manager/v2/impl/SlashCommandManager.java index 7ae928c2..d04770c4 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/impl/SlashCommandManager.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/impl/SlashCommandManager.java @@ -59,6 +59,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; public class SlashCommandManager extends ListenerAdapter { private static final Map> CHANNEL_TYPES = new ConcurrentHashMap<>(); @@ -121,20 +122,31 @@ public class SlashCommandManager extends ListenerAdapter { OPTION_TYPES.put(Object.class, OptionType.STRING); } - private final Locutus root; - private final CommandManager2 commands; + private final Supplier provider; + + private CommandManager2 commandsOrNull; + private Set ephemeralOrNull; private final Map commandIds = new HashMap<>(); private final Set bindingKeys = new HashSet<>(); private final boolean registerAdminCmds; - private Set ephemeral; private Map commandNames = new HashMap<>(); - public SlashCommandManager(Locutus locutus, boolean registerAdminCmds) { - this.root = locutus; - this.commands = root.getCommandManager().getV2(); - this.ephemeral = generateEphemeral(commands.getCommands()); + public SlashCommandManager(boolean registerAdminCmds, Supplier provider) { this.registerAdminCmds = registerAdminCmds; + this.provider = provider; + } + + private CommandManager2 getCommands() { + if (commandsOrNull == null) { + synchronized (this) { + if (commandsOrNull == null) { + commandsOrNull = provider.get(); + this.ephemeralOrNull = generateEphemeral(commandsOrNull.getCommands()); + } + } + } + return commandsOrNull; } private Set generateEphemeral(CommandGroup group) { @@ -239,6 +251,7 @@ public void printSize(OptionData option, StringBuilder response, int indent) { } public List generateCommandData() { + CommandManager2 commands = getCommands(); new PrimitiveCompleter().register(commands.getStore()); new DiscordCompleter().register(commands.getStore()); new PWCompleter().register(commands.getStore()); @@ -515,12 +528,12 @@ public List createOptions(ParametricCallable cmd, int maxOption, boo Key emptyKey = Key.of(String.class); if (!binding.getKey().equals(emptyKey)) { Key parserKey = binding.getKey().append(Autoparse.class); - Parser parser = commands.getStore().get(parserKey); + Parser parser = getCommands().getStore().get(parserKey); if (parser != null && !parser.getKey().equals(emptyKey)) { option.setAutoComplete(true); } else { Key completerKey = binding.getKey().append(Autocomplete.class); - parser = commands.getStore().get(completerKey); + parser = getCommands().getStore().get(completerKey); if (parser != null && !parser.getKey().equals(emptyKey)) { option.setAutoComplete(true); } else { @@ -589,6 +602,7 @@ public OptionType createType(Type type) { @Override public void onCommandAutoCompleteInteraction(@Nonnull CommandAutoCompleteInteractionEvent event) { + CommandManager2 commands = getCommands(); long startNanos = System.nanoTime(); User user = event.getUser(); userIdToAutoCompleteTimeNs.put(user.getIdLong(), startNanos); @@ -706,6 +720,7 @@ public void run() { @Override public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent event) { + CommandManager2 commands = getCommands(); try { long start = System.currentTimeMillis(); userIdToAutoCompleteTimeNs.put(event.getUser().getIdLong(), System.nanoTime()); @@ -719,7 +734,7 @@ public void onSlashCommandInteraction(@NotNull SlashCommandInteractionEvent even if (!path.contains("modal")) { isModal = false; System.out.println("Path " + path); - if (ephemeral.contains(path)) { + if (ephemeralOrNull.contains(path)) { RateLimitUtil.complete(event.deferReply(true)); hook.setEphemeral(true); } else { diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/CommandManager2.java b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/CommandManager2.java index 407f72ae..1e8315a2 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/CommandManager2.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/CommandManager2.java @@ -6,6 +6,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import link.locutus.discord.Locutus; +import link.locutus.discord.Logg; import link.locutus.discord.commands.manager.v2.binding.*; import link.locutus.discord.commands.manager.v2.binding.annotation.*; import link.locutus.discord.commands.manager.v2.binding.bindings.Placeholders; @@ -147,34 +148,49 @@ public JsonObject toJson(ValueStore htmlOptionsStore, PermissionHandler permHand } public CommandManager2() { + long start = System.currentTimeMillis(); this.store = new SimpleValueStore<>(); + Logg.text("remove:||PERF CM2 store" + (-start + (start = System.currentTimeMillis()))); new PrimitiveBindings().register(store); + Logg.text("remove:||PERF CM2 primtive bindings" + (-start + (start = System.currentTimeMillis()))); new DiscordBindings().register(store); + Logg.text("remove:||PERF CM2 discord bindings" + (-start + (start = System.currentTimeMillis()))); + new PWBindings().register(store); + Logg.text("remove:||PERF CM2 pw bindings" + (-start + (start = System.currentTimeMillis()))); new GPTBindings().register(store); + Logg.text("remove:||PERF CM2 gpt bindings" + (-start + (start = System.currentTimeMillis()))); new SheetBindings().register(store); + Logg.text("remove:||PERF CM2 sheet bindings" + (-start + (start = System.currentTimeMillis()))); // new StockBinding().register(store); new NewsletterBindings().register(store); + Logg.text("remove:||PERF CM2 newsletter bindings" + (-start + (start = System.currentTimeMillis()))); this.validators = new ValidatorStore(); new PrimitiveValidators().register(validators); + Logg.text("remove:||PERF CM2 primitive validators" + (-start + (start = System.currentTimeMillis()))); this.permisser = new PermissionHandler(); new PermissionBinding().register(permisser); + Logg.text("remove:||PERF CM2 permission binding" + (-start + (start = System.currentTimeMillis()))); this.placeholders = new PlaceholdersMap(store, validators, permisser); + Logg.text("remove:||PERF CM2 placeholders" + (-start + (start = System.currentTimeMillis()))); // Register bindings for (Class type : placeholders.getTypes()) { Placeholders ph = placeholders.get(type); System.out.println("Type " + type); ph.register(store); } + Logg.text("remove:||PERF CM2 register placeholders" + (-start + (start = System.currentTimeMillis()))); // Initialize commands (staged after bindings as there might be cross dependency) for (Class type : placeholders.getTypes()) { placeholders.get(type).init(); } + Logg.text("remove:||PERF CM2 init placeholders" + (-start + (start = System.currentTimeMillis()))); this.commands = CommandGroup.createRoot(store, validators); + Logg.text("remove:||PERF CM2 create root" + (-start + (start = System.currentTimeMillis()))); if (!Settings.INSTANCE.ARTIFICIAL_INTELLIGENCE.OPENAI.API_KEY.isEmpty()) { try { @@ -183,6 +199,7 @@ public CommandManager2() { IOException e) { throw new RuntimeException(e); } + Logg.text("remove:||PERF CM2 init gpt handler" + (-start + (start = System.currentTimeMillis()))); } } diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/AdminCommands.java b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/AdminCommands.java index 80f07698..3a300aaf 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/AdminCommands.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/AdminCommands.java @@ -1,7 +1,5 @@ package link.locutus.discord.commands.manager.v2.impl.pw.commands; -import link.locutus.discord.commands.bank.SyncBanks; -import link.locutus.discord.commands.external.guild.SyncBounties; import link.locutus.discord.commands.manager.v2.binding.Key; import link.locutus.discord.commands.manager.v2.binding.LocalValueStore; import link.locutus.discord.commands.manager.v2.binding.ValueStore; @@ -16,12 +14,11 @@ import link.locutus.discord.web.jooby.handler.CommandResult; import link.locutus.wiki.WikiGenHandler; import link.locutus.discord.Locutus; -import link.locutus.discord.RequestTracker; +import link.locutus.discord.apiv3.RequestTracker; import link.locutus.discord.apiv1.core.ApiKeyPool; import link.locutus.discord.apiv1.domains.subdomains.attack.v3.AbstractCursor; import link.locutus.discord.apiv1.enums.AttackType; import link.locutus.discord.apiv1.enums.ResourceType; -import link.locutus.discord.apiv1.enums.city.JavaCity; import link.locutus.discord.apiv3.PoliticsAndWarV3; import link.locutus.discord.apiv3.enums.AlliancePermission; import link.locutus.discord.apiv3.enums.NationLootType; @@ -77,12 +74,9 @@ import net.dv8tion.jda.api.entities.channel.Channel; import net.dv8tion.jda.api.entities.channel.concrete.Category; import net.dv8tion.jda.api.entities.channel.concrete.NewsChannel; -import net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel; import net.dv8tion.jda.api.entities.channel.concrete.TextChannel; import net.dv8tion.jda.api.entities.channel.middleman.GuildMessageChannel; import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel; -import net.dv8tion.jda.api.entities.channel.unions.DefaultGuildChannelUnion; -import net.dv8tion.jda.api.exceptions.InsufficientPermissionException; import org.json.JSONObject; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; @@ -100,7 +94,6 @@ import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Consumer; diff --git a/src/main/java/link/locutus/discord/config/GuildIds.java b/src/main/java/link/locutus/discord/config/GuildIds.java deleted file mode 100644 index 38a1ce9b..00000000 --- a/src/main/java/link/locutus/discord/config/GuildIds.java +++ /dev/null @@ -1,61 +0,0 @@ -package link.locutus.discord.config; - -public class GuildIds { - public static final long GRUMPY = 228679457370669058L; - public static final long COTL = 668493631229001739L; - public static final long TGR = 837816298905141258L; - public static final long PNW_DISCORD = 216800987002699787L; - public static final long PNW_STATS = 672481909887991818L; - - public static final long NUKA = 773291596673581077L; - public static final long NUKA2 = 764907973825921054L; - public static final long NUKA3 = 811781749411151882L; - public static final long NUKA4 = 764907973825921054L; - public static final long NUKA5 = 468711012057481217L; - - public static final long NUKA6 = 735386552800116807L; - public static final long NUKA7 = 753862283171594290L; - public static final long NUKA8 = 796609435975942174L; - public static final long NUKA9 = 773291667263586365L; - public static final long NUKA10 = 851640609181925398L; - public static final long NUKA11 = 748030393717882950L; - - public static final long TAITH = 235107763825410049L; - - public static final long APOPHIS = 748669114469449798L; - public static final long UMMAH = 744820671850217522L; - public static final long ARKBOOM = 931390872346591312L; - public static final long UMMAH_TRAIN = 751769262124695563L; - - public static final long TFP = 759780513501675600L; - public static final long TFP2 = 324332037676728321L; - public static final long FARK = 245270591689457665L; - - public static final long OASIS = 785612850646220822L; - public static final long CLOCK = 868559248156655636L; - public static final long CLOCKWATER = 918182346803535883L; - - public static final long ARSENAL = 790253684537688086L; - public static final long ARSENA_MILCOM = 929407358600359996L; - - public static final long SWING = 722227730438946847L; - - public static final long WAFFLE_HOUSE = 876630992000024596L; - - public static final long CAMELOT = 465573583532589058L; - - public static final long GENESIS = 835529307954085928L; - public static final long THE_GREATER_UNITARY_REPUBLIC = 690559049657483264L; - public static final long DELTA = 834486462614732840L; - - public static final long ROSE_LOCUTUS = 849062824352415784L; - public static final long SANCTUARY = 779785574369329163L; - public static final long INFERNO = 899348292960395296L; - public static final long HAND_OF_FATE = 882831852396748820L; - - public static final long THE_FEAR = 937145937950806016L; - - public static final long AYSLAMIC = 938857118252032010L; - - public static final long SRI = 941548620988178442L; -} diff --git a/src/main/java/link/locutus/discord/config/README.md b/src/main/java/link/locutus/discord/config/README.md new file mode 100644 index 00000000..1d55cd4c --- /dev/null +++ b/src/main/java/link/locutus/discord/config/README.md @@ -0,0 +1 @@ +This directory contains classes relating to Locutus bot configuration files (on disk) \ No newline at end of file diff --git a/src/main/java/link/locutus/discord/config/Settings.java b/src/main/java/link/locutus/discord/config/Settings.java index a294a109..f2975cf6 100644 --- a/src/main/java/link/locutus/discord/config/Settings.java +++ b/src/main/java/link/locutus/discord/config/Settings.java @@ -1,6 +1,7 @@ package link.locutus.discord.config; import link.locutus.discord.Locutus; +import link.locutus.discord.Logg; import link.locutus.discord.config.yaml.Config; import java.io.File; diff --git a/src/main/java/link/locutus/discord/config/yaml/file/FileConfiguration.java b/src/main/java/link/locutus/discord/config/yaml/file/FileConfiguration.java index e13ecaa4..5a80ce9e 100644 --- a/src/main/java/link/locutus/discord/config/yaml/file/FileConfiguration.java +++ b/src/main/java/link/locutus/discord/config/yaml/file/FileConfiguration.java @@ -122,7 +122,6 @@ public void load(File file) throws IOException, InvalidConfigurationException { if (file == null) { throw new NullPointerException("File cannot be null"); } - long start = System.currentTimeMillis(); try (FileInputStream stream = new FileInputStream(file); InputStreamReader reader = new InputStreamReader(new FastBufferedInputStream(stream), StandardCharsets.UTF_8); BufferedReader input = new BufferedReader(reader); diff --git a/src/main/java/link/locutus/discord/config/yaml/file/YamlConfiguration.java b/src/main/java/link/locutus/discord/config/yaml/file/YamlConfiguration.java index 29a9490d..a06272bd 100644 --- a/src/main/java/link/locutus/discord/config/yaml/file/YamlConfiguration.java +++ b/src/main/java/link/locutus/discord/config/yaml/file/YamlConfiguration.java @@ -136,7 +136,6 @@ public void loadFromString(final String contents) throws InvalidConfigurationExc if (contents == null) { throw new NullPointerException("Contents cannot be null"); } - Map input; try { input = yaml.load(contents); @@ -145,19 +144,13 @@ public void loadFromString(final String contents) throws InvalidConfigurationExc } catch (final ClassCastException e) { throw new InvalidConfigurationException("Top level is not a Map."); } - final String header = parseHeader(contents); if (!header.isEmpty()) { options().header(header); } - - Logg.text("remove:||PERF set header " + (-start + (start = System.currentTimeMillis())) + "ms"); - if (input != null) { convertMapsToSections(input, this); } - - Logg.text("remove:||PERF convert maps to sections " + (-start + (start = System.currentTimeMillis())) + "ms"); } protected void convertMapsToSections(final Map input, final ConfigurationSection section) { diff --git a/src/main/java/link/locutus/discord/db/AEmbeddingDatabase.java b/src/main/java/link/locutus/discord/db/AEmbeddingDatabase.java index 93c90d46..8e8452c1 100644 --- a/src/main/java/link/locutus/discord/db/AEmbeddingDatabase.java +++ b/src/main/java/link/locutus/discord/db/AEmbeddingDatabase.java @@ -6,6 +6,7 @@ import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import link.locutus.discord.Logg; import link.locutus.discord.db.entities.EmbeddingSource; import link.locutus.discord.gpt.IEmbeddingDatabase; import link.locutus.discord.gpt.imps.ConvertingDocument; @@ -45,6 +46,7 @@ public abstract class AEmbeddingDatabase implements IEmbeddingDatabase, Closeable { + private volatile boolean loaded = false; private final Long2ObjectOpenHashMap vectors; private final Map> textHashBySource; private final Map> expandedTextHashBySource; @@ -63,16 +65,27 @@ public AEmbeddingDatabase(String name, GptDatabase database) throws SQLException this.embeddingSources = new ConcurrentHashMap<>(); this.unconvertedDocuments = new ConcurrentHashMap<>(); this.documentChunks = new ConcurrentHashMap<>(); + } + public T load() { + if (loaded) return (T) this; + loaded = true; + long start = System.currentTimeMillis(); createTables(); - - // import old data + Logg.text("remove:|| aedb create tables " + (-start + (start = System.currentTimeMillis()))); importLegacyDate(); + Logg.text("remove:|| aedb import legacy data " + (-start + (start = System.currentTimeMillis()))); loadVectors(); + Logg.text("remove:|| aedb load vectors " + (-start + (start = System.currentTimeMillis()))); loadHashesBySource(); + Logg.text("remove:|| aedb load hashes by source " + (-start + (start = System.currentTimeMillis()))); loadSources(); + Logg.text("remove:|| aedb load sources " + (-start + (start = System.currentTimeMillis()))); loadExpandedTextMeta(); + Logg.text("remove:|| aedb load expanded text meta " + (-start + (start = System.currentTimeMillis()))); loadUnconvertedDocuments(); + Logg.text("remove:|| aedb load unconverted documents " + (-start + (start = System.currentTimeMillis()))); + return (T) this; } public GptDatabase getDatabase() { @@ -86,6 +99,7 @@ public void close() { @Override public void registerHashes(EmbeddingSource source, Set hashes, boolean deleteAbsent) { + load(); checkNotNull(source); if (hashes.isEmpty()) { if (deleteAbsent) { @@ -147,6 +161,7 @@ private void createVectorsTable() { } public synchronized void saveVector(long hash, float[] vector) { + load(); byte[] data = ArrayUtil.toByteArray(vector); vectors.put(hash, vector); String table = "vectors_" + vectorName; @@ -176,6 +191,7 @@ private void createExpandedTextTable() { } public synchronized boolean saveExpandedText(long embedding_hash, int source_id, String body) { + load(); long body_hash = getHash(body); Map hashesBySource = expandedTextHashBySource.computeIfAbsent(source_id, k -> new Long2LongOpenHashMap()); // if changed @@ -189,6 +205,7 @@ public synchronized boolean saveExpandedText(long embedding_hash, int source_id, } public boolean hasExpandedText(int source_id, long embedding_hash) { + load(); Map hashesBySource = expandedTextHashBySource.get(source_id); if (hashesBySource == null) { return false; @@ -201,6 +218,7 @@ public String getText(long hash) { } public String getExpandedText(int source_id, long embedding_hash) { + load(); Map hashesBySource = expandedTextHashBySource.get(source_id); if (hashesBySource == null) { return null; @@ -221,6 +239,7 @@ private void createVectorSourcesTable() { } public synchronized void saveVectorSources(long hash, int source_id) { + load(); textHashBySource.computeIfAbsent(source_id, k -> new LongOpenHashSet()).add(hash); ctx().execute("INSERT INTO vector_sources (source_id, hash) VALUES (?, ?)", source_id, hash); } @@ -252,7 +271,7 @@ private void createChunksTable() { "output VARCHAR, PRIMARY KEY (source_id, chunk_index))"); } - public void loadUnconvertedDocuments() { + private void loadUnconvertedDocuments() { ctx().execute("DELETE FROM document_queue WHERE converted = ?", true); ctx().execute("DELETE FROM document_chunks WHERE converted = ?", true); // delete where source_id not in sources @@ -270,15 +289,18 @@ public void loadUnconvertedDocuments() { } public List getUnconvertedDocuments() { + load(); return new ArrayList<>(this.unconvertedDocuments.values()); } @Override public ConvertingDocument getConvertingDocument(int source_id) { + load(); return unconvertedDocuments.get(source_id); } public void addConvertingDocument(List documents) { + load(); for (ConvertingDocument document : documents) { unconvertedDocuments.put(document.source_id, document); } @@ -291,6 +313,7 @@ public void addConvertingDocument(List documents) { } public void addChunks(List chunks) { + load(); for (DocumentChunk chunk : chunks) { documentChunks.computeIfAbsent(chunk.source_id, k -> new ConcurrentHashMap<>()).put(chunk.chunk_index, chunk); } @@ -303,6 +326,7 @@ public void addChunks(List chunks) { } public List getChunks(int source_id) { + load(); ArrayList result = new ArrayList<>(documentChunks.getOrDefault(source_id, Collections.emptyMap()).values()); result.sort(Comparator.comparingInt(o -> o.chunk_index)); return result; @@ -310,6 +334,7 @@ public List getChunks(int source_id) { @Override public void deleteDocumentAndChunks(int sourceId) { + load(); documentChunks.remove(sourceId); unconvertedDocuments.remove(sourceId); ctx().transaction((TransactionalRunnable) -> { @@ -320,11 +345,13 @@ public void deleteDocumentAndChunks(int sourceId) { @Override public EmbeddingSource getEmbeddingSource(int source_id) { + load(); return embeddingSources.get(source_id); } @Override public synchronized EmbeddingSource getOrCreateSource(String name, long guild_id) { + load(); name = name.toLowerCase(); EmbeddingSource source = this.getSource(name, guild_id); @@ -348,6 +375,7 @@ public synchronized EmbeddingSource getOrCreateSource(String name, long guild_id @Override public void updateSources(List sources) { + load(); ctx().transaction((TransactionalRunnable) -> { for (EmbeddingSource source : sources) { ctx().execute("UPDATE sources SET source_name = ?, date_added = ?, guild_id = ? WHERE source_id = ?", @@ -370,7 +398,7 @@ private void importLegacyDate() { } catch (DataAccessException ignore) {} } - public void loadVectors() { + private void loadVectors() { String table = "vectors_" + vectorName; ctx().select().from(table).fetch().forEach(r -> { long hash = r.get("hash", Long.class); @@ -380,7 +408,7 @@ public void loadVectors() { }); } - public void loadHashesBySource() { + private void loadHashesBySource() { ctx().select().from("vector_sources").fetch().forEach(r -> { long hash = r.get("hash", Long.class); int source_id = r.get("source_id", Integer.class); @@ -393,7 +421,7 @@ public void loadHashesBySource() { }); } - public void loadSources() { + private void loadSources() { ctx().select().from("sources").fetch().forEach(r -> { int source_id = r.get("source_id", Integer.class); String source_name = r.get("source_name", String.class); @@ -424,7 +452,7 @@ public synchronized void createTables() { createChunksTable(); } - public void loadExpandedTextMeta() { + private void loadExpandedTextMeta() { // expandedTextHashBySource ctx().select().from("expanded_text").fetch().forEach(r -> { // .column("embedding_hash", SQLDataType.BIGINT.notNull()) @@ -439,11 +467,13 @@ public void loadExpandedTextMeta() { @Override public float[] getEmbedding(long hash) { + load(); return vectors.get(hash); } @Override public void deleteSource(EmbeddingSource source) { + load(); // delete from expanded_text and sources and vector_sources int source_id = source.source_id; ctx().execute("DELETE FROM expanded_text WHERE source_id = ?", source_id); diff --git a/src/main/java/link/locutus/discord/db/BankDB.java b/src/main/java/link/locutus/discord/db/BankDB.java index a898e204..812360ba 100644 --- a/src/main/java/link/locutus/discord/db/BankDB.java +++ b/src/main/java/link/locutus/discord/db/BankDB.java @@ -74,8 +74,8 @@ public class BankDB extends DBMainV3 { private final Map> transactionCache = new ConcurrentHashMap<>(); - public BankDB(String name) throws SQLException, ClassNotFoundException { - super(Settings.INSTANCE.DATABASE, name, false); + public BankDB() throws SQLException, ClassNotFoundException { + super(Settings.INSTANCE.DATABASE, "bank", false); } public List getTransactions(Condition condition) { diff --git a/src/main/java/link/locutus/discord/db/DBMainV2.java b/src/main/java/link/locutus/discord/db/DBMainV2.java index e6d85835..24b8f4e6 100644 --- a/src/main/java/link/locutus/discord/db/DBMainV2.java +++ b/src/main/java/link/locutus/discord/db/DBMainV2.java @@ -199,17 +199,15 @@ public int[] executeBatch(Collection objects, String query, BiConsumer withStmt, Consumer rsq) { - { - try (PreparedStatement stmt = getConnection().prepareStatement(sql)) { - stmt.setFetchSize(10000); - withStmt.accept(stmt); - ResultSet rs = stmt.executeQuery(); - rsq.accept(rs); - return rs != null; - } catch (SQLException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } + try (PreparedStatement stmt = getConnection().prepareStatement(sql)) { + stmt.setFetchSize(10000); + withStmt.accept(stmt); + ResultSet rs = stmt.executeQuery(); + rsq.accept(rs); + return rs != null; + } catch (SQLException e) { + e.printStackTrace(); + throw new RuntimeException(e); } } diff --git a/src/main/java/link/locutus/discord/db/NationDB.java b/src/main/java/link/locutus/discord/db/NationDB.java index 50c98357..552df6a5 100644 --- a/src/main/java/link/locutus/discord/db/NationDB.java +++ b/src/main/java/link/locutus/discord/db/NationDB.java @@ -123,7 +123,7 @@ private void condenseCities() { } - public void load() throws SQLException { + public NationDB load() throws SQLException { { // Legacy if (tableExists("NATIONS")) { Logg.text("Updating legacy nations"); diff --git a/src/main/java/link/locutus/discord/db/README.md b/src/main/java/link/locutus/discord/db/README.md new file mode 100644 index 00000000..192dc575 --- /dev/null +++ b/src/main/java/link/locutus/discord/db/README.md @@ -0,0 +1 @@ +This directory contains the classes handle databses as well as the types used for database records diff --git a/src/main/java/link/locutus/discord/db/WarDB.java b/src/main/java/link/locutus/discord/db/WarDB.java index a39a606a..fe78f1ac 100644 --- a/src/main/java/link/locutus/discord/db/WarDB.java +++ b/src/main/java/link/locutus/discord/db/WarDB.java @@ -4,12 +4,12 @@ import com.politicsandwar.graphql.model.*; import com.ptsmods.mysqlw.table.ColumnType; import com.ptsmods.mysqlw.table.TablePreset; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.io.FastByteArrayOutputStream; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import link.locutus.discord.Locutus; +import link.locutus.discord.Logg; import link.locutus.discord.apiv1.domains.subdomains.WarAttacksContainer; import link.locutus.discord.apiv1.domains.subdomains.attack.v3.AbstractCursor; import link.locutus.discord.apiv1.domains.subdomains.attack.v3.AttackCursorFactory; @@ -40,10 +40,10 @@ import link.locutus.discord.util.StringMan; import link.locutus.discord.util.TimeUtil; import link.locutus.discord.util.math.ArrayUtil; +import link.locutus.discord.util.scheduler.TriConsumer; import link.locutus.discord.util.update.WarUpdateProcessor; import link.locutus.discord.apiv1.domains.subdomains.attack.DBAttack; import link.locutus.discord.apiv1.domains.subdomains.SWarContainer; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import java.io.IOException; @@ -55,6 +55,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.function.BiConsumer; import java.util.function.BiFunction; @@ -135,7 +136,7 @@ public void testAttackSerializingTime() throws IOException { if ((num_attacks) % 100000 == 0) { // and print % - System.out.println("Loaded " + num_attacks + " attacks | " + skipped + " skipped | " + MathMan.format((num_attacks) / (double) max_attacks * 100) + "%"); + Logg.text("Loaded " + num_attacks + " attacks | " + skipped + " skipped | " + MathMan.format((num_attacks) / (double) max_attacks * 100) + "%"); } // serialize byte[] bytes = cursorManager.toBytes(cursor); @@ -163,13 +164,13 @@ public void testAttackSerializingTime() throws IOException { long diff = System.currentTimeMillis() - start; // print time, num and skipped - System.out.println("Took " + diff + "ms to load " + num_attacks + " attacks (" + skipped + " skipped)"); + Logg.text("Took " + diff + "ms to load " + num_attacks + " attacks (" + skipped + " skipped)"); // print total bytes - System.out.println("Total bytes: " + totalBytes); + Logg.text("Total bytes: " + totalBytes); // Took 54134ms to load 12695101 attacks (228834 skipped) // print total by type for (Map.Entry entry : countByType.entrySet()) { - System.out.println(entry.getKey() + ": " + entry.getValue()); + Logg.text(entry.getKey() + ": " + entry.getValue()); } } @@ -197,8 +198,8 @@ private void validateAttack(DBWar war, DBAttack legacy, AbstractCursor cursor) { // private int attacker_nation_id; if (legacy.getAttacker_id() != cursor.getAttacker_id() && (war == null || war.getAttacker_id() != cursor.getAttacker_id())) { // print att/def of legacy and cursor - System.out.println("Legacy att/def: " + legacy.getAttacker_id() + " | " + legacy.getDefender_id()); - System.out.println("Cursor att/def: " + cursor.getAttacker_id() + " | " + cursor.getDefender_id()); + Logg.text("Legacy att/def: " + legacy.getAttacker_id() + " | " + legacy.getDefender_id()); + Logg.text("Cursor att/def: " + cursor.getAttacker_id() + " | " + cursor.getDefender_id()); throw new IllegalArgumentException("Attacker nation id mismatch " + cursor.getAttacker_id() + " != " + legacy.getAttacker_id()); } // private int defender_nation_id; @@ -215,25 +216,25 @@ private void validateAttack(DBWar war, DBAttack legacy, AbstractCursor cursor) { // // print type // // print attacker / defender // // print success -// System.out.println("Victor mismatch " + legacy.getVictor() + " | " + newVictor); -// System.out.println("Type: " + cursor.getAttack_type()); -// System.out.println("Attacker: " + legacy.getAttacker_id() + " | " + cursor.getAttacker_id()); -// System.out.println("Defender: " + legacy.getDefender_id() + " | " + cursor.getDefender_id()); -// System.out.println("Success: " + SuccessType.values[legacy.getSuccess()] + " | " + cursor.getSuccess()); +// Logg.text("Victor mismatch " + legacy.getVictor() + " | " + newVictor); +// Logg.text("Type: " + cursor.getAttack_type()); +// Logg.text("Attacker: " + legacy.getAttacker_id() + " | " + cursor.getAttacker_id()); +// Logg.text("Defender: " + legacy.getDefender_id() + " | " + cursor.getDefender_id()); +// Logg.text("Success: " + SuccessType.values[legacy.getSuccess()] + " | " + cursor.getSuccess()); // throw new IllegalArgumentException("Victor mismatch " + legacy.getVictor() + " | " + newVictor); // } // private int success; if (legacy.getSuccess() != cursor.getSuccess().ordinal() && legacy.getAttack_type() != AttackType.PEACE && legacy.getAttack_type() != AttackType.FORTIFY && legacy.getAttack_type() != AttackType.VICTORY) { // print type and success - System.out.println("Success mismatch " + legacy.getSuccess() + " | " + cursor.getSuccess().ordinal()); - System.out.println("Type: " + cursor.getAttack_type()); + Logg.text("Success mismatch " + legacy.getSuccess() + " | " + cursor.getSuccess().ordinal()); + Logg.text("Type: " + cursor.getAttack_type()); throw new IllegalArgumentException("Success mismatch"); } // private int attcas1; if (legacy.getAttcas1() != cursor.getAttcas1()) { if ((legacy.getAttack_type() != AttackType.MISSILE && legacy.getAttack_type() != AttackType.NUKE) || legacy.getAttcas1() != 0) { - System.out.println("Attcas1 mismatch " + legacy.getAttcas1() + " | " + cursor.getAttcas1()); - System.out.println("Type: " + cursor.getAttack_type()); + Logg.text("Attcas1 mismatch " + legacy.getAttcas1() + " | " + cursor.getAttcas1()); + Logg.text("Type: " + cursor.getAttack_type()); throw new IllegalArgumentException("Attcas1 mismatch"); } } @@ -256,7 +257,7 @@ private void validateAttack(DBWar war, DBAttack legacy, AbstractCursor cursor) { // private double infra_destroyed; // if (Math.round(legacy.getInfra_destroyed() * 100) != Math.round(cursor.getInfra_destroyed() * 100)) { // // print type and amounts -// System.out.println("Infra destroyed mismatch " + legacy.getAttack_type() + " " + legacy.getInfra_destroyed() + " | " + cursor.getInfra_destroyed()); +// Logg.text("Infra destroyed mismatch " + legacy.getAttack_type() + " " + legacy.getInfra_destroyed() + " | " + cursor.getInfra_destroyed()); // throw new IllegalArgumentException("Infra destroyed mismatch"); // } // private int improvements_destroyed; @@ -271,13 +272,13 @@ private void validateAttack(DBWar war, DBAttack legacy, AbstractCursor cursor) { } } else if (legacy.getMoney_looted() ==0 || cursor.getLoot() == null || cursor.getLoot()[ResourceType.MONEY.ordinal()] == 0) { // print type and amounts - System.out.println("Money looted mismatch " + legacy.getAttack_type() + " " + legacy.getMoney_looted() + " | " + cursor.getMoney_looted()); - System.out.println("Loot : " + (legacy.loot != null) + " | " + (cursor.getLoot() != null)); + Logg.text("Money looted mismatch " + legacy.getAttack_type() + " " + legacy.getMoney_looted() + " | " + cursor.getMoney_looted()); + Logg.text("Loot : " + (legacy.loot != null) + " | " + (cursor.getLoot() != null)); if (legacy.loot != null) { - System.out.println("loot l " + ResourceType.resourcesToString(legacy.loot)); + Logg.text("loot l " + ResourceType.resourcesToString(legacy.loot)); } if (cursor.getLoot() != null) { - System.out.println("loot c " + ResourceType.resourcesToString(cursor.getLoot())); + Logg.text("loot c " + ResourceType.resourcesToString(cursor.getLoot())); } throw new IllegalArgumentException("Money looted mismatch"); } @@ -295,15 +296,15 @@ private void validateAttack(DBWar war, DBAttack legacy, AbstractCursor cursor) { // private double lootPercent; if (Math.round(legacy.getLootPercent() * 100) != Math.round(cursor.getLootPercent() * 100) && legacy.loot != null && !ResourceType.isZero(legacy.loot)) { // print type, percent and loot amounts - System.out.println("Tyoe " + legacy.getAttack_type() + " | " + cursor.getAttack_type()); - System.out.println("Loot percent mismatch " + legacy.getAttack_type() + " " + legacy.getLootPercent() + " | " + cursor.getLootPercent()); + Logg.text("Tyoe " + legacy.getAttack_type() + " | " + cursor.getAttack_type()); + Logg.text("Loot percent mismatch " + legacy.getAttack_type() + " " + legacy.getLootPercent() + " | " + cursor.getLootPercent()); if (legacy.loot != null) { // print - System.out.println("loot l " + ResourceType.resourcesToString(legacy.loot)); + Logg.text("loot l " + ResourceType.resourcesToString(legacy.loot)); } if (cursor.getLoot() != null) { // print - System.out.println("loot c " + ResourceType.resourcesToString(cursor.getLoot())); + Logg.text("loot c " + ResourceType.resourcesToString(cursor.getLoot())); } // print count by type (or 0) throw new IllegalArgumentException("Loot percent mismatch"); @@ -311,8 +312,8 @@ private void validateAttack(DBWar war, DBAttack legacy, AbstractCursor cursor) { // private double city_infra_before; if (Math.round(legacy.getCity_infra_before() * 100) != Math.round(cursor.getCity_infra_before() * 100) && legacy.getCity_infra_before() > 0 && legacy.getAttack_type() != AttackType.VICTORY) { //print - System.out.println("City infra before mismatch " + legacy.getCity_infra_before() + " | " + cursor.getCity_infra_before()); - System.out.println("Type " + legacy.getAttack_type()); + Logg.text("City infra before mismatch " + legacy.getCity_infra_before() + " | " + cursor.getCity_infra_before()); + Logg.text("Type " + legacy.getAttack_type()); throw new IllegalArgumentException("City infra before mismatch"); } // private double infra_destroyed_value; @@ -322,10 +323,10 @@ private void validateAttack(DBWar war, DBAttack legacy, AbstractCursor cursor) { // // if within 10% of each other, ignore // if (Math.abs(valueLegacy - valueCursor) > 0.1 * Math.max(valueLegacy, valueCursor) && legacy.getCity_infra_before() > 0) { // // print type and amounts -// System.out.println("final: " + legacy.getCity_infra_before() + " - " + cursor.getCity_infra_before()); +// Logg.text("final: " + legacy.getCity_infra_before() + " - " + cursor.getCity_infra_before()); // // after -// System.out.println("before: " + (legacy.getCity_infra_before() - legacy.getInfra_destroyed()) + " - " + (cursor.getCity_infra_before() - cursor.getInfra_destroyed())); -// System.out.println("Type " + legacy.getAttack_type()); +// Logg.text("before: " + (legacy.getCity_infra_before() - legacy.getInfra_destroyed()) + " - " + (cursor.getCity_infra_before() - cursor.getInfra_destroyed())); +// Logg.text("Type " + legacy.getAttack_type()); //// throw new IllegalArgumentException("Infra destroyed value mismatch " + valueLegacy + " | " + valueCursor); // } // } @@ -339,8 +340,8 @@ private void validateAttack(DBWar war, DBAttack legacy, AbstractCursor cursor) { } // private double def_gas_used; if (Math.round(legacy.getDef_gas_used() * 100) != Math.round(cursor.getDef_gas_used() * 100)) { - System.out.println("Def gas used mismatch " + legacy.getDef_gas_used() + " | " + cursor.getDef_gas_used()); - System.out.println("Type " + legacy.getAttack_type()); + Logg.text("Def gas used mismatch " + legacy.getDef_gas_used() + " | " + cursor.getDef_gas_used()); + Logg.text("Type " + legacy.getAttack_type()); throw new IllegalArgumentException("Def gas used mismatch"); } // private double def_mun_used; @@ -430,6 +431,56 @@ private void setWar(DBWar war) { } } + private void setWars(List allWars, boolean clear) { + synchronized (this.warsByAllianceId) { + synchronized (this.warsByNationId) { + synchronized (warsById) { + if (clear) { + warsById.clear(); + warsByAllianceId.clear(); + warsByNationId.clear(); + } + long start = System.currentTimeMillis(); + Int2IntOpenHashMap numWarsByAlliance = new Int2IntOpenHashMap(); + Int2IntOpenHashMap numWarsByNation = new Int2IntOpenHashMap(); + for (DBWar war : allWars) { + if (war.getAttacker_aa() != 0) numWarsByAlliance.addTo(war.getAttacker_aa(), 1); + if (war.getDefender_aa() != 0) numWarsByAlliance.addTo(war.getDefender_aa(), 1); + numWarsByNation.addTo(war.getAttacker_id(), 1); + numWarsByNation.addTo(war.getDefender_id(), 1); + } + Logg.text("remove:||Perf count wars " + (-start + (start = System.currentTimeMillis()))); + warsById.addAll(allWars); + Logg.text("remove:||Perf add wars " + (-start + (start = System.currentTimeMillis()))); + for (DBWar war : allWars) { + if (war.getAttacker_aa() != 0) setWar(war, war.getAttacker_aa(), numWarsByAlliance.addTo(war.getAttacker_aa(), -1) + 1, this.warsByAllianceId); + if (war.getDefender_aa() != 0) setWar(war, war.getDefender_aa(), numWarsByAlliance.addTo(war.getDefender_aa(), -1) + 1, this.warsByAllianceId); + setWar(war, war.getAttacker_id(), numWarsByNation.addTo(war.getAttacker_id(), -1) + 1, this.warsByNationId); + setWar(war, war.getDefender_id(), numWarsByNation.addTo(war.getDefender_id(), -1) + 1, this.warsByNationId); + } + Logg.text("remove:||Perf set wars " + (-start + (start = System.currentTimeMillis()))); + } + } + } + } + + private void setWar(DBWar war, int id, int remaining, Int2ObjectOpenHashMap map) { + map.merge(id, war, (o, o2) -> { + if (o == null) { + return remaining > 1 ? new Object[remaining] : o2; + } else if (o instanceof DBWar oldWar) { + Object[] array = new Object[remaining + 1]; + array[0] = oldWar; + array[1] = o2; + return array; + } else { + Object[] array = (Object[]) o; + array[array.length - remaining] = o2; + return array; + } + }); + } + public void loadWarCityCountsLegacy() throws IOException, ParseException { DataDumpParser parser = Locutus.imp().getDataDumper(true); Map> counts = parser.getUtil().backCalculateCityCounts(); @@ -464,24 +515,24 @@ public void loadWarCityCountsLegacy() throws IOException, ParseException { } }); } - System.out.println("Saving " + toSave.size() + " wars"); - System.out.println("Failed to find " + failed.get() + " wars"); - saveWars(toSave); + Logg.text("Saving " + toSave.size() + " wars"); + Logg.text("Failed to find " + failed.get() + " wars"); + saveWars(toSave, false); } - public void load() { - System.out.println("Loading wars and attacks"); + public WarDB load() { + Logg.text("remove:||PERF Loading wars and attacks"); + long start = System.currentTimeMillis(); loadWars(Settings.INSTANCE.TASKS.UNLOAD_WARS_AFTER_TURNS); - System.out.println("Loaded wars"); + Logg.text("remove:||PERF Loaded wars " + (-start + (start = System.currentTimeMillis()))); if (Settings.INSTANCE.TASKS.LOAD_ACTIVE_ATTACKS) { - System.out.println("Loading attacks"); + Logg.text("remove:||PERF Loading attacks " + (-start + (start = System.currentTimeMillis()))); importLegacyAttacks(); - System.out.println("Loaded legacy attacks"); - long start = System.currentTimeMillis(); + Logg.text("remove:||PERF Loaded legacy attacks " + (-start + (start = System.currentTimeMillis()))); loadAttacks(Settings.INSTANCE.TASKS.LOAD_INACTIVE_ATTACKS, Settings.INSTANCE.TASKS.LOAD_ACTIVE_ATTACKS); - System.out.println("Loaded wardb attacks in " + (System.currentTimeMillis() - start) + "ms"); + Logg.text("remove:||PERF Loaded wardb attacks in " + (-start + (start = System.currentTimeMillis()))); - System.out.println("Updating attacks"); + Logg.text("remove:||PERF Updating attacks " + (-start + (start = System.currentTimeMillis()))); { // get attacks by id 20071530 @@ -492,7 +543,7 @@ public void load() { // // get last // AbstractCursor attack = attacks.stream().max(Comparator.comparing(AbstractCursor::getWar_attack_id)).orElse(null); // if (attack == null) { -// System.out.println("No attacks found"); +// Logg.text("No attacks found"); // } else { // updateAttacks(attack, false, null, false); // } @@ -500,8 +551,10 @@ public void load() { } activeWars.syncBlockades(); + Logg.text("remove:||PERF Loaded wars and attacks " + (-start + (start = System.currentTimeMillis()))); if (conflictManager != null) { conflictManager.loadConflicts(); + Logg.text("remove:||PERF Loaded conflicts " + (-start + (start = System.currentTimeMillis()))); } } @@ -517,21 +570,35 @@ public void loadWars(int turns) { if (turns > 0 && turns < 120) turns = 120; long currentTurn = TimeUtil.getTurn(); long date = TimeUtil.getTimeFromTurn(currentTurn - turns); + long activeWarCutoff = TimeUtil.getTimeFromTurn(currentTurn - 60); String whereClause = turns > 0 ? " WHERE date > " + date : ""; - query("SELECT * FROM wars" + whereClause, f -> { + + AtomicInteger setStatusCount = new AtomicInteger(); + + List wars = new ObjectArrayList<>(); + List saveWars = new ObjectArrayList<>(); + query("SELECT id, attacker_id, defender_id, attacker_aa, defender_aa, war_type, status, date, attCities, defCities FROM wars " + whereClause, f -> { }, (ThrowingConsumer) rs -> { while (rs.next()) { DBWar war = create(rs); - setWar(war); - - long warTurn = TimeUtil.getTurn(war.getDate()); - if (currentTurn - warTurn < 60) { + wars.add(war); +// setWar(war); + if (war.getDate() > activeWarCutoff) { activeWars.addActiveWar(war); } else if (war.isActive()) { war.setStatus(WarStatus.EXPIRED); + saveWars.add(war); + setStatusCount.incrementAndGet(); } } }); + if (!wars.isEmpty()) { + setWars(wars, false); + } + if (!saveWars.isEmpty()) { + saveWars(saveWars, false); + } + System.out.println("Set " + setStatusCount.get() + " wars to expired"); } public List getAttacks(Collection wars, Predicate attackTypeFilter, Predicate preliminaryFilter, Predicate attackFilter) { @@ -1656,7 +1723,7 @@ public boolean updateAllWarsV2(Consumer eventConsumer) throws IOException // Find deleted wars for (int id = minId; id <= maxId; id++) { if (fetchedWarIds.contains(id)) continue; - DBWar war = activeWarsById.get(new ArrayUtil.IntKey(id)); + DBWar war = activeWarsById.get(new DBWar.DBWarKey(id)); if (war == null) continue; DBWar newWar = new DBWar(war); @@ -1714,11 +1781,11 @@ public void fetchWarsById(Collection ids, Consumer eventConsumer public void fetchNewWars(Consumer eventConsumer) { int maxId = activeWars.getActiveWars().stream().mapToInt(f -> f.warId).max().orElse(0); if (maxId == 0) { - System.out.println("No active wars"); + Logg.text("No active wars"); return; } PoliticsAndWarV3 api = Locutus.imp().getV3(); - System.out.println("Fetch new wars " + maxId); + Logg.text("Fetch new wars " + maxId); List warsQl = api.fetchWarsWithInfo(r -> { r.setMin_id(maxId + 1); r.setActive(false); @@ -1819,7 +1886,7 @@ public boolean updateWars(List dbWars, Collection expectedIds, C } } - saveWars(newWars); + saveWars(newWars, true); List> warUpdatePreviousNow = new ArrayList<>(); @@ -1857,22 +1924,24 @@ public boolean updateWars(List dbWars, Collection expectedIds, C return true; } - public void saveWars(Collection values) { + public void saveWars(Collection values, boolean addToMap) { if (values.isEmpty()) return; - for (DBWar war : values) { - setWar(war); - } - List> nationSnapshots = new ArrayList<>(); - for (DBWar war : values) { - DBNation attacker = war.getNation(true); - DBNation defender = war.getNation(false); - if (attacker != null) { - nationSnapshots.add(Map.entry(war.getWarId(), attacker)); - } - if (defender != null) { - nationSnapshots.add(Map.entry(war.getWarId(), defender)); + if (addToMap) { + for (DBWar war : values) { + setWar(war); } } +// List> nationSnapshots = new ArrayList<>(); +// for (DBWar war : values) { +// DBNation attacker = war.getNation(true); +// DBNation defender = war.getNation(false); +// if (attacker != null) { +// nationSnapshots.add(Map.entry(war.getWarId(), attacker)); +// } +// if (defender != null) { +// nationSnapshots.add(Map.entry(war.getWarId(), defender)); +// } +// } String query = "INSERT OR REPLACE INTO `wars`(`id`, `attacker_id`, `defender_id`, `attacker_aa`, `defender_aa`, `war_type`, `status`, `date`, `attCities`, `defCities`) VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; @@ -1894,7 +1963,7 @@ public void saveWars(Collection values) { } else { executeBatch(values, query, setStmt); } - System.out.println("Done save war"); + Logg.text("Done save war"); } public Map getWars(WarStatus status) { @@ -1929,23 +1998,21 @@ public boolean test(DBWar war) { } private DBWar create(ResultSet rs) throws SQLException { - int warId = rs.getInt("id"); - // `attacker_id`, `defender_id`, `attacker_aa`, `defender_aa`, `war_type`, `status`, `date` - int attacker_id = rs.getInt("attacker_id"); - int defender_id = rs.getInt("defender_id"); - int attacker_aa = rs.getInt("attacker_aa"); - int defender_aa = rs.getInt("defender_aa"); - WarType war_type = WarType.values[rs.getInt("war_type")]; - WarStatus status = WarStatus.values[rs.getInt("status")]; - long date = rs.getLong("date"); - int attCities = rs.getInt("attCities"); - int defCities = rs.getInt("defCities"); - + int warId = rs.getInt(1); + int attacker_id = rs.getInt(2); + int defender_id = rs.getInt(3); + int attacker_aa = rs.getInt(4); + int defender_aa = rs.getInt(5); + WarType war_type = WarType.values[rs.getInt(6)]; + WarStatus status = WarStatus.values[rs.getInt(7)]; + long date = rs.getLong(8); + int attCities = rs.getInt(9); + int defCities = rs.getInt(10); return new DBWar(warId, attacker_id, defender_id, attacker_aa, defender_aa, war_type, status, date, attCities, defCities); } public DBWar getWar(int warId) { - return warsById.get(new ArrayUtil.IntKey(warId)); + return warsById.get(new DBWar.DBWarKey(warId)); } public List getWars(int nation1, int nation2, long start, long end) { @@ -2099,7 +2166,7 @@ public Set getWarsById(Set warIds) { Set result = new ObjectOpenHashSet<>(); synchronized (warsById) { for (Integer id : warIds) { - DBWar war = warsById.get(new ArrayUtil.IntKey(id)); + DBWar war = warsById.get(new DBWar.DBWarKey(id)); if (war != null) result.add(war); } } @@ -2347,7 +2414,7 @@ private boolean updateAttacks(AbstractCursor latest, boolean runAlerts, Consumer // Dont run events if attacks are > 1 day old if (!v2 && (latest == null || latest.getDate() < System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1))) { PoliticsAndWarV3 v3 = Locutus.imp().getV3(); - System.out.println("No recent attack data in DB. Updating attacks without event handling: " + maxId); + Logg.text("No recent attack data in DB. Updating attacks without event handling: " + maxId); List attackList = new ArrayList<>(); v3.fetchAttacksSince(maxId, new Predicate() { @Override @@ -2468,7 +2535,7 @@ public boolean test(WarAttack v3Attack) { } - saveWars(warsToSave); + saveWars(warsToSave, true); if (runAlerts && dirtyCities.size() > 0) { for (AbstractCursor attack : dirtyCities) { // check improvements and modify city @@ -2507,7 +2574,7 @@ public boolean test(WarAttack v3Attack) { public void loadAttacks(boolean loadInactive, boolean loadActive) { if (!loadActive) return; - + long start = System.currentTimeMillis(); String whereClause; if (!loadInactive) { long dateCutoff = TimeUtil.getTimeFromTurn(TimeUtil.getTurn() - 120); @@ -2523,29 +2590,39 @@ public void loadAttacks(boolean loadInactive, boolean loadActive) { } else { whereClause = ""; } - String query = "SELECT * FROM `attacks3` " + whereClause + " ORDER BY `id` ASC"; - AttackCursorFactory factory = new AttackCursorFactory(); + String query = "SELECT war_id, data FROM `attacks3` " + whereClause + " ORDER BY `id` ASC"; + + IntArrayList warIds = new IntArrayList(); + List attacks = new ObjectArrayList<>(); + Int2IntOpenHashMap numAttacksByWarId = new Int2IntOpenHashMap(); + + Logg.text("remove:||PERF loadAttacks: " + (-start + (start = System.currentTimeMillis()))); + try (PreparedStatement stmt = prepareQuery(query)) { try (ResultSet rs = stmt.executeQuery()) { while (rs.next()) { - int warId = rs.getInt("war_id"); - DBWar war = getWar(warId); - if (war == null) { - continue; - } - List list = attacksByWarId2.get(warId); - if (list == null) { - // use fastUtil - list = new ObjectArrayList<>(); - attacksByWarId2.put(warId, list); - } - byte[] bytes = rs.getBytes("data"); - list.add(bytes); + int warId = rs.getInt(1); + if (!warsById.contains(new DBWar.DBWarKey(warId))) continue; + byte[] bytes = rs.getBytes(2); + warIds.add(warId); + attacks.add(bytes); + numAttacksByWarId.addTo(warId, 1); } } } catch (SQLException e) { e.printStackTrace(); } + + Logg.text("remove:||PERF loadAttacks2: " + (-start + (start = System.currentTimeMillis()))); + + for (int i = 0; i < attacks.size(); i++) { + byte[] data = attacks.get(i); + int warId = warIds.getInt(i); + int size = numAttacksByWarId.get(warId); + attacksByWarId2.computeIfAbsent(warId, _ -> new ObjectArrayList<>(size)).add(data); + } + + Logg.text("remove:||PERF loadAttacks3: " + (-start + (start = System.currentTimeMillis()))); } // public Map> getAttacksByNationGroupWar2(int nationId, long startDate) { diff --git a/src/main/java/link/locutus/discord/db/entities/DBNation.java b/src/main/java/link/locutus/discord/db/entities/DBNation.java index 0a03bc80..c25dc07c 100644 --- a/src/main/java/link/locutus/discord/db/entities/DBNation.java +++ b/src/main/java/link/locutus/discord/db/entities/DBNation.java @@ -5369,7 +5369,7 @@ public Set getActiveWars() { } Locutus.imp().getWarDb().getAttacksByWar(wars, f -> f == AttackType.VICTORY || f == AttackType.PEACE, f -> { if (f.getDate() <= end) { - wars.remove(new ArrayUtil.IntKey(f.getWar_id())); + wars.remove(new DBWar.DBWarKey(f.getWar_id())); } return false; }, f -> false); diff --git a/src/main/java/link/locutus/discord/db/entities/DBWar.java b/src/main/java/link/locutus/discord/db/entities/DBWar.java index f1d1d206..30fb5146 100644 --- a/src/main/java/link/locutus/discord/db/entities/DBWar.java +++ b/src/main/java/link/locutus/discord/db/entities/DBWar.java @@ -34,6 +34,23 @@ public class DBWar { private final long date; private char attDefCities; + public static final class DBWarKey { + public final int id; + public DBWarKey(int id) { + this.id = id; + } + + @Override + public boolean equals(Object o) { + return ((DBWar) o).warId == id; + } + + @Override + public int hashCode() { + return id; + } + } + public int getTurnsLeft() { return (int) (TimeUtil.getTurn() - TimeUtil.getTurn(getDate()) + 60); } diff --git a/src/main/java/link/locutus/discord/db/handlers/ActiveWarHandler.java b/src/main/java/link/locutus/discord/db/handlers/ActiveWarHandler.java index 3242bc74..637f6d9f 100644 --- a/src/main/java/link/locutus/discord/db/handlers/ActiveWarHandler.java +++ b/src/main/java/link/locutus/discord/db/handlers/ActiveWarHandler.java @@ -288,7 +288,7 @@ public void syncBlockades() { for (AbstractCursor attack : attacks) { if (attack.getAttack_type() != AttackType.NAVAL) continue; - boolean isWarActive = activeWars2.contains(new ArrayUtil.IntKey(attack.getWar_id())); + boolean isWarActive = activeWars2.contains(new DBWar.DBWarKey(attack.getWar_id())); if (attack.getSuccess() == SuccessType.IMMENSE_TRIUMPH) { if (isWarActive) { diff --git a/src/main/java/link/locutus/discord/db/handlers/AttackQuery.java b/src/main/java/link/locutus/discord/db/handlers/AttackQuery.java index 8d3136c1..f8aa6c84 100644 --- a/src/main/java/link/locutus/discord/db/handlers/AttackQuery.java +++ b/src/main/java/link/locutus/discord/db/handlers/AttackQuery.java @@ -202,7 +202,7 @@ public void accept(AbstractCursor attack) { if (!attackFilterFinal.test(attack)) { return; } - DBWar war = wars.get(new ArrayUtil.IntKey(attack.getWar_id())); + DBWar war = wars.get(new DBWar.DBWarKey(attack.getWar_id())); cost.addCost(attack, isPrimary.test(war, attack)); } }); diff --git a/src/main/java/link/locutus/discord/event/README.md b/src/main/java/link/locutus/discord/event/README.md new file mode 100644 index 00000000..f8ac1539 --- /dev/null +++ b/src/main/java/link/locutus/discord/event/README.md @@ -0,0 +1,5 @@ +This directory contains all internal locutus events +These events are passed to the Locutus#eventBus + +To listen to an event, you must register your class with Locutus#eventBus +and have the @subscribe annotation on your methods \ No newline at end of file diff --git a/src/main/java/link/locutus/discord/gpt/GptHandler.java b/src/main/java/link/locutus/discord/gpt/GptHandler.java index 2a44d396..d294e991 100644 --- a/src/main/java/link/locutus/discord/gpt/GptHandler.java +++ b/src/main/java/link/locutus/discord/gpt/GptHandler.java @@ -10,6 +10,7 @@ import com.theokanning.openai.service.OpenAiService; import it.unimi.dsi.fastutil.longs.LongArrayList; import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet; +import link.locutus.discord.Logg; import link.locutus.discord.config.Settings; import link.locutus.discord.db.entities.EmbeddingSource; import link.locutus.discord.gpt.copilot.CopilotDeviceAuthenticationData; @@ -40,23 +41,25 @@ import static com.pusher.client.util.internal.Preconditions.checkNotNull; public class GptHandler { - private final EncodingRegistry registry; private final OpenAiService service; - private final Platform platform; public final IEmbeddingDatabase embeddingDatabase; private final IModerator moderator; private final ProcessText2Text processT2; public GptHandler(GptDatabase database) throws SQLException, ClassNotFoundException, ModelNotFoundException, MalformedModelException, IOException { - this.registry = Encodings.newDefaultEncodingRegistry(); + long start = System.currentTimeMillis(); + Logg.text("remove:|| gpthandler1 new registry " + (-start + (start = System.currentTimeMillis()))); this.service = new OpenAiService(Settings.INSTANCE.ARTIFICIAL_INTELLIGENCE.OPENAI.API_KEY, Duration.ofSeconds(120)); - - this.platform = Platform.detectPlatform("pytorch"); + Logg.text("remove:|| gpthandler1 new service " + (-start + (start = System.currentTimeMillis()))); + Logg.text("remove:|| gpthandler1 new platform " + (-start + (start = System.currentTimeMillis()))); this.moderator = new GPTModerator(service); + Logg.text("remove:|| gpthandler1 new moderator " + (-start + (start = System.currentTimeMillis()))); // this.embeddingDatabase = new AdaEmbedding(registry, service); // TODO change ^ that to mini - this.embeddingDatabase = new MiniEmbedding(platform, database); + this.embeddingDatabase = new MiniEmbedding(database); + Logg.text("remove:|| gpthandler1 new embeddingDatabase " + (-start + (start = System.currentTimeMillis()))); + File scriptPath = new File("../gpt4free/my_project/gpt3_5_turbo.py"); File venvExe = new File("../gpt4free/venv/Scripts/python.exe"); @@ -70,8 +73,10 @@ public GptHandler(GptDatabase database) throws SQLException, ClassNotFoundExcept } // this.summarizer = new ProcessSummarizer(venvExe, gpt4freePath, ModelType.GPT_3_5_TURBO, 8192); this.processT2 = new ProcessText2Text(venvExe, "my_project.gpt3_5_turbo", workingDirectory); + Logg.text("remove:|| gpthandler1 new processT2 " + (-start + (start = System.currentTimeMillis()))); } else { processT2 = null; + Logg.text("remove:|| gpthandler1 new processT2 null " + (-start + (start = System.currentTimeMillis()))); } } diff --git a/src/main/java/link/locutus/discord/gpt/imps/MiniEmbedding.java b/src/main/java/link/locutus/discord/gpt/imps/MiniEmbedding.java index 4b09b8fe..07ea5dc4 100644 --- a/src/main/java/link/locutus/discord/gpt/imps/MiniEmbedding.java +++ b/src/main/java/link/locutus/discord/gpt/imps/MiniEmbedding.java @@ -8,6 +8,7 @@ import ai.djl.repository.zoo.ZooModel; import ai.djl.translate.TranslateException; import ai.djl.util.Platform; +import link.locutus.discord.Logg; import link.locutus.discord.db.AEmbeddingDatabase; import link.locutus.discord.gpt.pw.GptDatabase; @@ -15,27 +16,42 @@ import java.sql.SQLException; public class MiniEmbedding extends AEmbeddingDatabase { - private final Platform platform; - private final Criteria criteria; - private final ZooModel model; - private final Predictor predictor; + private Criteria criteria; + private ZooModel model; + private Predictor predictor; - public MiniEmbedding(Platform platform, GptDatabase database) throws SQLException, ClassNotFoundException, ModelNotFoundException, MalformedModelException, IOException { + public MiniEmbedding(GptDatabase database) throws SQLException, ClassNotFoundException, ModelNotFoundException, MalformedModelException, IOException { super("minilm", database); - this.platform = platform; - criteria = Criteria.builder() - .setTypes(String.class, float[].class) - .optModelUrls("djl://ai.djl.huggingface.pytorch/sentence-transformers/all-MiniLM-L6-v2") - .optEngine("PyTorch") - .optTranslatorFactory(new TextEmbeddingTranslatorFactory()) - .build(); - this.model = criteria.loadModel(); - predictor = model.newPredictor(); + } + + private void init() { + if (criteria == null) { + synchronized (this) { + if (criteria == null) { + try { + long start = System.currentTimeMillis(); + criteria = Criteria.builder() + .setTypes(String.class, float[].class) + .optModelUrls("djl://ai.djl.huggingface.pytorch/sentence-transformers/all-MiniLM-L6-v2") + .optEngine("PyTorch") + .optTranslatorFactory(new TextEmbeddingTranslatorFactory()) + .build(); + Logg.text("remove:||PERF Mini embedding " + (-start + (start = System.currentTimeMillis()))); + this.model = criteria.loadModel(); + Logg.text("remove:||PERF Mini embedding load " + (-start + (start = System.currentTimeMillis()))); + predictor = model.newPredictor(); + Logg.text("remove:||PERF Mini embedding predictor " + (-start + (start = System.currentTimeMillis()))); + } catch (ModelNotFoundException | MalformedModelException | IOException e) { + throw new RuntimeException(e); + } + } + } + } } @Override public float[] fetchEmbedding(String text) { - System.out.println("fetchEmbedding: " + text); + init(); try { return predictor.predict(text); } catch (TranslateException e) { @@ -45,7 +61,9 @@ public float[] fetchEmbedding(String text) { @Override public synchronized void close() { - this.model.close(); + if (model != null) { + this.model.close(); + } super.close(); } } diff --git a/src/main/java/link/locutus/discord/gpt/pw/PWGPTHandler.java b/src/main/java/link/locutus/discord/gpt/pw/PWGPTHandler.java index 11aa0a20..2452ca31 100644 --- a/src/main/java/link/locutus/discord/gpt/pw/PWGPTHandler.java +++ b/src/main/java/link/locutus/discord/gpt/pw/PWGPTHandler.java @@ -6,6 +6,7 @@ import com.google.common.collect.HashBiMap; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; +import link.locutus.discord.Logg; import link.locutus.discord.commands.manager.v2.binding.Key; import link.locutus.discord.commands.manager.v2.binding.Parser; import link.locutus.discord.commands.manager.v2.binding.ValueStore; @@ -52,14 +53,20 @@ public class PWGPTHandler { private final WikiManager wikiManager; public PWGPTHandler(CommandManager2 manager) throws SQLException, ClassNotFoundException, ModelNotFoundException, MalformedModelException, IOException { + long start = System.currentTimeMillis(); this.database = new GptDatabase(); - + Logg.text("remove:||PERF gpt db" + (-start + (start = System.currentTimeMillis()))); this.cmdManager = manager; this.handler = new GptHandler(database); + Logg.text("remove:||PERF gpt new handler " + (-start + (start = System.currentTimeMillis()))); this.providerManager = new ProviderManager(handler); + Logg.text("remove:||PERF gpt provider manager " + (-start + (start = System.currentTimeMillis()))); this.PlayerGPTConfig = new PlayerGPTConfig(); + Logg.text("remove:||PERF gpt player gpt config " + (-start + (start = System.currentTimeMillis()))); this.converter = new DocumentConverter(getEmbeddings(), providerManager, handler.getModerator(), handler); + Logg.text("remove:||PERF gpt document converter " + (-start + (start = System.currentTimeMillis()))); this.wikiManager = new WikiManager(database, handler.getEmbeddings(), handler); + Logg.text("remove:||PERF gpt wiki manager " + (-start + (start = System.currentTimeMillis()))); } public WikiManager getWikiManager() { diff --git a/src/main/java/link/locutus/discord/network/README.md b/src/main/java/link/locutus/discord/network/README.md new file mode 100644 index 00000000..e48e3683 --- /dev/null +++ b/src/main/java/link/locutus/discord/network/README.md @@ -0,0 +1,4 @@ +UNUSED +These classes are not used at the moment + +TODO: Add handling for proxy connections to Locutus \ No newline at end of file diff --git a/src/main/java/link/locutus/discord/util/README.md b/src/main/java/link/locutus/discord/util/README.md new file mode 100644 index 00000000..5a91fc69 --- /dev/null +++ b/src/main/java/link/locutus/discord/util/README.md @@ -0,0 +1,2 @@ +This directory contains various classes and utilities for Locutus +They are not organized or documented well atm \ No newline at end of file diff --git a/src/main/java/link/locutus/discord/util/io/PageRequestQueue.java b/src/main/java/link/locutus/discord/util/io/PageRequestQueue.java index a54ff298..3ec61bcd 100644 --- a/src/main/java/link/locutus/discord/util/io/PageRequestQueue.java +++ b/src/main/java/link/locutus/discord/util/io/PageRequestQueue.java @@ -1,14 +1,9 @@ package link.locutus.discord.util.io; -import link.locutus.discord.RequestTracker; -import org.springframework.http.HttpHeaders; -import org.springframework.web.client.HttpClientErrorException; +import link.locutus.discord.apiv3.RequestTracker; -import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; @@ -17,7 +12,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; diff --git a/src/main/java/link/locutus/discord/util/trade/TradeManager.java b/src/main/java/link/locutus/discord/util/trade/TradeManager.java index ba4e4a80..ba9a2995 100644 --- a/src/main/java/link/locutus/discord/util/trade/TradeManager.java +++ b/src/main/java/link/locutus/discord/util/trade/TradeManager.java @@ -211,8 +211,8 @@ private void loadActiveTrades() { updateLowHighCache(); } - public synchronized void load() { - if (lowAvg != null) return; + public synchronized TradeManager load() { + if (lowAvg != null) return this; long cutOff = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7); List trades = getTradeDb().getTrades(cutOff); if (trades.isEmpty() && Settings.INSTANCE.TASKS.COMPLETED_TRADES_SECONDS > 0) { @@ -229,6 +229,7 @@ public synchronized void load() { highAvg[ResourceType.CREDITS.ordinal()] = 25_000_000; loadActiveTrades(); + return this; } public Collection toTransfers(Collection offers, boolean onlyMoneyTrades) { diff --git a/src/main/java/link/locutus/discord/web/README.md b/src/main/java/link/locutus/discord/web/README.md new file mode 100644 index 00000000..8f7cc23e --- /dev/null +++ b/src/main/java/link/locutus/discord/web/README.md @@ -0,0 +1 @@ +This directory contains the classes relating to the Locutus web interface \ No newline at end of file From 4855e06914f08fe9ecd9c5a95401dc77df8ebb36 Mon Sep 17 00:00:00 2001 From: test Date: Fri, 23 Aug 2024 19:02:12 +1000 Subject: [PATCH 02/27] Update CommandManager.java --- .../link/locutus/discord/commands/manager/CommandManager.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/link/locutus/discord/commands/manager/CommandManager.java b/src/main/java/link/locutus/discord/commands/manager/CommandManager.java index fbb35a3e..bbef8a83 100644 --- a/src/main/java/link/locutus/discord/commands/manager/CommandManager.java +++ b/src/main/java/link/locutus/discord/commands/manager/CommandManager.java @@ -147,13 +147,17 @@ public class CommandManager { private final CharOpenHashSet modernPrefixes; public CommandManager(Locutus locutus) { + long start = System.currentTimeMillis(); this.prefix1 = Settings.commandPrefix(true).charAt(0); + Logg.text("remove:||PERF commandmanager prefix " + (-start + (start = System.currentTimeMillis())) + "ms"); this.modernPrefixes = new CharOpenHashSet(); modernPrefixes.add(Settings.commandPrefix(false).charAt(0)); for (String prefix : Settings.INSTANCE.DISCORD.COMMAND.ALTERNATE_COMMAND_PREFIX) { modernPrefixes.add(prefix.charAt(0)); } + Logg.text("remove:||PERF commandmanager prefixes " + (-start + (start = System.currentTimeMillis())) + "ms"); this.commandMap = new LinkedHashMap<>(); + Logg.text("remove:||PERF commandmanager commandMap " + (-start + (start = System.currentTimeMillis())) + "ms"); this.executor = new ScheduledThreadPoolExecutor(256); Logg.text("remove:||PERF commandmanager executor " + (-start + (start = System.currentTimeMillis())) + "ms"); modernized = new CommandManager2(); From 54c8532c3e1dfda0317c7ae3ffa18f3b97e106b7 Mon Sep 17 00:00:00 2001 From: test Date: Fri, 23 Aug 2024 20:49:58 +1000 Subject: [PATCH 03/27] wip --- .../java/link/locutus/discord/Locutus.java | 42 +++- .../discord/_main/FinalizedLoader.java | 109 ++++++++++- .../link/locutus/discord/_main/ILoader.java | 7 +- .../link/locutus/discord/_main/PreLoader.java | 182 +++++++++++++----- .../discord/apiv2/PoliticsAndWarV2.java | 3 +- .../commands/manager/CommandManager.java | 2 +- .../v2/impl/pw/commands/AdminCommands.java | 2 +- .../v2/impl/pw/commands/BankCommands.java | 2 +- .../v2/impl/pw/commands/EmbedCommands.java | 3 +- .../link/locutus/discord/config/Settings.java | 2 +- .../link/locutus/discord/db/NationDB.java | 7 +- .../java/link/locutus/discord/db/WarDB.java | 8 +- .../locutus/discord/db/entities/DBNation.java | 22 +-- .../discord/db/guild/GuildSetting.java | 24 +-- .../discord/db/handlers/ActiveWarHandler.java | 16 +- .../discord/db/handlers/AttackQuery.java | 7 +- .../java/link/locutus/discord/util/PW.java | 40 +++- 17 files changed, 369 insertions(+), 109 deletions(-) diff --git a/src/main/java/link/locutus/discord/Locutus.java b/src/main/java/link/locutus/discord/Locutus.java index e43d9bb1..71a6ec45 100644 --- a/src/main/java/link/locutus/discord/Locutus.java +++ b/src/main/java/link/locutus/discord/Locutus.java @@ -1,6 +1,7 @@ package link.locutus.discord; import com.google.common.eventbus.AsyncEventBus; +import link.locutus.discord._main.Backup; import link.locutus.discord._main.FinalizedLoader; import link.locutus.discord._main.ILoader; import link.locutus.discord._main.PreLoader; @@ -82,6 +83,7 @@ import javax.annotation.Nonnull; import javax.security.auth.login.LoginException; +import java.io.IOException; import java.nio.ByteBuffer; import java.sql.SQLException; import java.util.*; @@ -94,7 +96,7 @@ public final class Locutus extends ListenerAdapter { private static Locutus INSTANCE; private ILoader loader; - private final ExecutorService executor; + private final ThreadPoolExecutor executor; private final EventBus eventBus; @@ -122,7 +124,7 @@ private Locutus() throws SQLException, ClassNotFoundException, LoginException, I if (INSTANCE != null) throw new IllegalStateException("Already running."); INSTANCE = this; long start = System.currentTimeMillis(); - this.executor = Executors.newCachedThreadPool(); + this.executor = (ThreadPoolExecutor) Executors.newCachedThreadPool(); if (Settings.INSTANCE.ROOT_SERVER <= 0) throw new IllegalStateException("Please set ROOT_SERVER in " + Settings.INSTANCE.getDefaultFile()); if (Settings.INSTANCE.ROOT_COALITION_SERVER <= 0) Settings.INSTANCE.ROOT_COALITION_SERVER = Settings.INSTANCE.ROOT_SERVER; @@ -149,6 +151,7 @@ private Locutus() throws SQLException, ClassNotFoundException, LoginException, I this.eventBus = new AsyncEventBus("locutus", Runnable::run); Logg.text("remove:||PERF eventbus " + (((-start)) + (start = System.currentTimeMillis()))); this.loader = new PreLoader(this, executor); + this.loader.initialize(); Logg.text("remove:||PERF new preloader " + (((-start)) + (start = System.currentTimeMillis()))); } @@ -161,18 +164,31 @@ public static ILoader loader() { } public void registerEvents() { + System.out.println("Registering events"); eventBus.register(new TreatyUpdateProcessor()); + System.out.println("Registered TreatyUpdateProcessor"); eventBus.register(new NationUpdateProcessor()); + System.out.println("Registered NationUpdateProcessor"); eventBus.register(new TradeListener()); + System.out.println("Registered TradeListener"); eventBus.register(new CityUpdateProcessor()); + System.out.println("Registered CityUpdateProcessor"); eventBus.register(new BankUpdateProcessor()); + System.out.println("Registered BankUpdateProcessor"); eventBus.register(new WarUpdateProcessor()); + System.out.println("Registered WarUpdateProcessor"); eventBus.register(new AllianceListener()); + System.out.println("Registered AllianceListener"); CommandManager cmdManager = loader.getCommandManager(); + System.out.println("Get CommandManager"); eventBus.register(new MailListener(cmdManager.getV2().getStore(), cmdManager.getV2().getValidators(), cmdManager.getV2().getPermisser())); + System.out.println("Registered MailListener"); WarDB warDb = loader.getWarDB(); + System.out.println("Get WarDB"); ConflictManager conflictManager = warDb == null ? null : warDb.getConflicts(); + System.out.println("Get ConflictManager"); if (conflictManager != null) eventBus.register(conflictManager); + System.out.println("Registered ConflictManager"); } public EventBus getEventBus() { @@ -200,8 +216,10 @@ public Locutus start() throws InterruptedException, LoginException, SQLException Logg.text("remove:||PERF backup " + (((-start)) + (start = System.currentTimeMillis()))); if (Settings.INSTANCE.ENABLED_COMPONENTS.DISCORD_BOT) { JDA jda = loader.getJda(); + Logg.text("remove:||PERF get jda " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); try { SlashCommandManager slashCommands = loader.getSlashCommandManager(); + Logg.text("remove:||PERF get slash commands " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); if (slashCommands != null) slashCommands.registerCommandData(jda); } catch (Throwable e) { // sometimes happen when discord api is spotty / timeout @@ -215,6 +233,7 @@ public Locutus start() throws InterruptedException, LoginException, SQLException jda.awaitStatus(JDA.Status.LOADING_SUBSYSTEMS); Logg.text("remove:||PERF subsystems " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); jda.awaitReady(); + Logg.text("remove:||PERF awaitready " + jda.getStatus() + " " + (((-start)) + (start = System.currentTimeMillis()))); setSelfUser(jda); if (Settings.INSTANCE.ENABLED_COMPONENTS.CREATE_DATABASES_ON_STARTUP) { initDBPartial(true); @@ -296,7 +315,12 @@ public void run() { }, 5 * 60); Logg.text("remove:||PERF setup message handler " + (((-start)) + (start = System.currentTimeMillis()))); } - loader.resolveFully(); + System.out.println("Start resolve fully"); + try { + loader.resolveFully(TimeUnit.MINUTES.toMillis(15)); + } catch (Throwable e) { + throw new IllegalStateException("Failed to start locutus in 15 minutes.\n\n" + loader.printStacktrace()); + } Logg.text("remove:||PERF resolve loader fully " + (((-start)) + (start = System.currentTimeMillis()))); return this; } @@ -332,7 +356,7 @@ public OffshoreInstance getRootBank() { } public Auth getRootAuth() { - Auth auth = getNationDB().getNation(Settings.INSTANCE.NATION_ID).getAuth(true); + Auth auth = getNationDB().getNation(loader.getNationId()).getAuth(true); if (auth != null) auth.setApiKey(loader.getApiKey()); return auth; } @@ -1271,6 +1295,16 @@ public void stop() { } } + private void backup() { + int turnsCheck = Settings.INSTANCE.BACKUP.TURNS; + String script = Settings.INSTANCE.BACKUP.SCRIPT; + try { + Backup.backup(script, turnsCheck); + } catch (IOException e) { + e.printStackTrace(); + } + } + public GuildCustomMessageHandler getMessageHandler() { return messageHandler; } diff --git a/src/main/java/link/locutus/discord/_main/FinalizedLoader.java b/src/main/java/link/locutus/discord/_main/FinalizedLoader.java index 027cb2de..dba2a0d5 100644 --- a/src/main/java/link/locutus/discord/_main/FinalizedLoader.java +++ b/src/main/java/link/locutus/discord/_main/FinalizedLoader.java @@ -1,15 +1,48 @@ package link.locutus.discord._main; +import link.locutus.discord.apiv2.PoliticsAndWarV2; +import link.locutus.discord.apiv3.PoliticsAndWarV3; +import link.locutus.discord.commands.manager.CommandManager; +import link.locutus.discord.commands.manager.v2.impl.SlashCommandManager; +import link.locutus.discord.commands.stock.StockDB; import link.locutus.discord.config.Settings; -import link.locutus.discord.db.BaseballDB; +import link.locutus.discord.db.*; +import link.locutus.discord.util.trade.TradeManager; +import net.dv8tion.jda.api.JDA; import java.sql.SQLException; +import java.util.concurrent.Future; +import java.util.function.Supplier; public class FinalizedLoader implements ILoader { private volatile BaseballDB baseBallDB; - public FinalizedLoader(PreLoader loader) { + private final SlashCommandManager slashCommandManager; + private final JDA jda; + private final ForumDB forumDb; + private final DiscordDB discordDB; + private final NationDB nationDB; + private final WarDB warDb; + private final StockDB stockDB; + private final BankDB bankDb; + private final TradeManager tradeManager; + private final CommandManager commandManager; + private final PoliticsAndWarV2 apiV2; + private final PoliticsAndWarV3 apiV3; + public FinalizedLoader(PreLoader loader) { + this.slashCommandManager = loader.getSlashCommandManager(); + this.jda = loader.getJda(); + this.forumDb = loader.getForumDB(); + this.discordDB = loader.getDiscordDB(); + this.nationDB = loader.getNationDB(); + this.warDb = loader.getWarDB(); + this.stockDB = loader.getStockDB(); + this.bankDb = loader.getBankDB(); + this.tradeManager = loader.getTradeManager(); + this.commandManager = loader.getCommandManager(); + this.apiV2 = loader.getApiV2(); + this.apiV3 = loader.getApiV3(); } @Override @@ -27,4 +60,76 @@ public BaseballDB getBaseballDB() { } return this.baseBallDB; } + + @Override + public SlashCommandManager getSlashCommandManager() { + return slashCommandManager; + } + + @Override + public ILoader resolveFully(long timeout) { + return this; + } + + @Override + public void initialize() { + // Do nothing + } + + @Override + public JDA getJda() { + return jda; + } + + @Override + public ForumDB getForumDB() { + return forumDb; + } + + @Override + public DiscordDB getDiscordDB() { + return discordDB; + } + + @Override + public NationDB getNationDB() { + return nationDB; + } + + @Override + public WarDB getWarDB() { + return warDb; + } + + @Override + public StockDB getStockDB() { + return stockDB; + } + + @Override + public BankDB getBankDB() { + return bankDb; + } + + @Override + public TradeManager getTradeManager() { + return tradeManager; + } + + @Override + public CommandManager getCommandManager() { + return commandManager; + } + + @Override + public PoliticsAndWarV2 getApiV2() { + return apiV2; + } + + @Override + public PoliticsAndWarV3 getApiV3() { + return apiV3; + } + + } diff --git a/src/main/java/link/locutus/discord/_main/ILoader.java b/src/main/java/link/locutus/discord/_main/ILoader.java index 48b9b6a7..555fe77a 100644 --- a/src/main/java/link/locutus/discord/_main/ILoader.java +++ b/src/main/java/link/locutus/discord/_main/ILoader.java @@ -11,7 +11,8 @@ import net.dv8tion.jda.api.JDA; public interface ILoader { - ILoader resolveFully(); + ILoader resolveFully(long timeout); + void initialize(); default String getApiKey() { return Settings.INSTANCE.API_KEY_PRIMARY; @@ -39,4 +40,8 @@ default long getAdminUserId() { PoliticsAndWarV3 getApiV3(); PoliticsAndWarV2 getApiV2(); + + default String printStacktrace() { + return ""; + } } diff --git a/src/main/java/link/locutus/discord/_main/PreLoader.java b/src/main/java/link/locutus/discord/_main/PreLoader.java index 78901e33..b6ba0476 100644 --- a/src/main/java/link/locutus/discord/_main/PreLoader.java +++ b/src/main/java/link/locutus/discord/_main/PreLoader.java @@ -31,16 +31,24 @@ import net.dv8tion.jda.api.utils.cache.CacheFlag; import java.io.IOException; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; +import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Supplier; public class PreLoader implements ILoader { - private final ExecutorService executor; + private final ThreadPoolExecutor executor; + private final Semaphore semaphore; private final Locutus locutus; + // futures + private final Map> resolvers; + private final Map resolverThreads; + + private volatile FinalizedLoader finalized; + // fields + private final Future slashCommandManager; + private final Future jda; + private final Future forumDb; private final Future discordDB; private final Future nationDB; @@ -54,19 +62,14 @@ public class PreLoader implements ILoader { private final Future> adminUserId; private final Future apiV2; private final Future apiV3; - // futures - private List> resolvers; - private volatile FinalizedLoader finalized; - // fields - private final Future slashCommandManager; - private final Future jda; - public PreLoader(Locutus locutus, ExecutorService executor) { + public PreLoader(Locutus locutus, ThreadPoolExecutor executor) { this.executor = executor; - this.resolvers = new ArrayList<>(); - this.locutus = locutus; + this.semaphore = new Semaphore(0); - // todo fixme remove calls of Locutus.imp() + this.resolvers = new ConcurrentHashMap<>(); + this.resolverThreads = new ConcurrentHashMap<>(); + this.locutus = locutus; this.slashCommandManager = add("Slash Command Manager", new ThrowingSupplier() { @Override @@ -86,7 +89,7 @@ public SlashCommandManager getThrows() throws Exception { } else { forumDb = CompletableFuture.completedFuture(null); } - this.commandManager = add("Command Handler", () -> new CommandManager(locutus)); + this.commandManager = add("Command Handler", () -> new CommandManager()); if (Settings.INSTANCE.API_KEY_PRIMARY.isEmpty()) { Auth auth = new Auth(0, Settings.INSTANCE.USERNAME, Settings.INSTANCE.PASSWORD); @@ -171,21 +174,24 @@ public long getAdminUserId() { } @Override - public ILoader resolveFully() { - List> tmp = resolvers; + public ILoader resolveFully(long timeout) { + Set>> tmp = resolvers.entrySet(); if (finalized != null) return finalized; synchronized (this) { if (finalized != null) { return finalized; } - for (Future resolver : tmp) { + for (Map.Entry> resolver : tmp) { + String taskName = resolver.getKey(); + Future future = resolver.getValue(); try { - resolver.get(); + future.get(timeout, TimeUnit.MILLISECONDS); } catch (Exception e) { + Logg.text("Failed to resolve `TASK:" + taskName + "`: " + e.getMessage()); throw new RuntimeException(e); } } - resolvers = null; + resolvers.clear(); this.finalized = new FinalizedLoader(this); locutus.setLoader(finalized); return finalized; @@ -193,36 +199,63 @@ public ILoader resolveFully() { } private Future add(String taskName, ThrowingSupplier supplier) { - Future future = executor.submit(new Callable() { - @Override - public T call() throws Exception { - try { - Logg.text("Loading `TASK:" + taskName + "`"); - long start = System.currentTimeMillis(); - T result = supplier.get(); - long end = System.currentTimeMillis(); - if (end - start > 15 || true) { - Logg.text("Completed `TASK:" + taskName + "` in " + MathMan.format((end - start) / 1000d) + "s"); - } - - return result; - } catch (Throwable e) { - e.printStackTrace(); - throw e; + if (resolvers.containsKey(taskName)) { + throw new IllegalArgumentException("Duplicate task: " + taskName); + } + Future future = executor.submit(() -> { + try { + Thread thread = Thread.currentThread(); + thread.setName("Load-" + taskName); + resolverThreads.put(taskName, thread); + semaphore.acquire(); + Logg.text("Loading `TASK:" + taskName + "`"); + long start = System.currentTimeMillis(); + T result = supplier.get(); + long end = System.currentTimeMillis(); + if (end - start > 15 || true) { + Logg.text("Completed `TASK:" + taskName + "` in " + MathMan.format((end - start) / 1000d) + "s"); } + return result; + } catch (Throwable e) { + e.printStackTrace(); + Logg.text("Failed to load `TASK:" + taskName + "`: " + e.getMessage()); + throw e; + } finally { + resolverThreads.remove(taskName); } }); - resolvers.add(future); + resolvers.put(taskName, future); return future; } + @Override + public void initialize() { + semaphore.release(Integer.MAX_VALUE); + } + + @Override + public String printStacktrace() { + StringBuilder builder = new StringBuilder(); + for (Map.Entry entry : resolverThreads.entrySet()) { + Thread thread = entry.getValue(); + builder.append("Thread ").append(thread.getName()).append("/").append(thread.getState()).append("\n"); + for (StackTraceElement element : thread.getStackTrace()) { + builder.append("\tat ").append(element).append("\n"); + } + } + return builder.toString(); + } + private JDA buildJDA() throws ExecutionException, InterruptedException { JDABuilder builder = JDABuilder.createLight(Settings.INSTANCE.BOT_TOKEN, GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGES, GatewayIntent.DIRECT_MESSAGES); if (Settings.INSTANCE.ENABLED_COMPONENTS.SLASH_COMMANDS) { - builder.addEventListeners(slashCommandManager.get()); + SlashCommandManager slash = getSlashCommandManager(); + if (slash != null) { + builder.addEventListeners(slash); + } } if (Settings.INSTANCE.ENABLED_COMPONENTS.MESSAGE_COMMANDS) { - builder.addEventListeners(this); + builder.addEventListeners(locutus); } builder .setChunkingFilter(ChunkingFilter.NONE) @@ -263,13 +296,68 @@ private JDA buildJDA() throws ExecutionException, InterruptedException { return builder.build(); } - private void backup() { - int turnsCheck = Settings.INSTANCE.BACKUP.TURNS; - String script = Settings.INSTANCE.BACKUP.SCRIPT; - try { - Backup.backup(script, turnsCheck); - } catch (IOException e) { - e.printStackTrace(); - } + @Override + public SlashCommandManager getSlashCommandManager() { + return FileUtil.get(slashCommandManager); + } + + @Override + public JDA getJda() { + return FileUtil.get(jda); + } + + @Override + public ForumDB getForumDB() { + return FileUtil.get(forumDb); + } + + @Override + public DiscordDB getDiscordDB() { + return FileUtil.get(discordDB); + } + + @Override + public NationDB getNationDB() { + return FileUtil.get(nationDB); + } + + @Override + public WarDB getWarDB() { + return FileUtil.get(warDb); + } + + @Override + public BaseballDB getBaseballDB() { + return resolveFully(Long.MAX_VALUE).getBaseballDB(); + } + + @Override + public StockDB getStockDB() { + return FileUtil.get(stockDB); + } + + @Override + public BankDB getBankDB() { + return FileUtil.get(bankDb); + } + + @Override + public TradeManager getTradeManager() { + return FileUtil.get(tradeManager); + } + + @Override + public CommandManager getCommandManager() { + return FileUtil.get(commandManager); + } + + @Override + public PoliticsAndWarV2 getApiV2() { + return FileUtil.get(apiV2); + } + + @Override + public PoliticsAndWarV3 getApiV3() { + return FileUtil.get(apiV3); } } diff --git a/src/main/java/link/locutus/discord/apiv2/PoliticsAndWarV2.java b/src/main/java/link/locutus/discord/apiv2/PoliticsAndWarV2.java index 5a1f62a2..61ea6a99 100644 --- a/src/main/java/link/locutus/discord/apiv2/PoliticsAndWarV2.java +++ b/src/main/java/link/locutus/discord/apiv2/PoliticsAndWarV2.java @@ -4,6 +4,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.reflect.TypeToken; +import link.locutus.discord.Locutus; import link.locutus.discord.apiv1.IPoliticsAndWar; import link.locutus.discord.apiv1.core.ApiKeyPool; import link.locutus.discord.apiv1.core.CacheClient; @@ -116,7 +117,7 @@ public String read(PagePriority priority, QueryURLV2 url, String arg, String que } public ApiRecord getApiRecord() { - String json = read(PagePriority.API_KEY_STATS, QueryURLV2.BANK_RECORDS, Settings.INSTANCE.NATION_ID + "", null, false); + String json = read(PagePriority.API_KEY_STATS, QueryURLV2.BANK_RECORDS, Locutus.loader().getNationId() + "", null, false); Type type = new TypeToken() { }.getType(); return getGson().fromJson(json, type); diff --git a/src/main/java/link/locutus/discord/commands/manager/CommandManager.java b/src/main/java/link/locutus/discord/commands/manager/CommandManager.java index bbef8a83..c3ee8b06 100644 --- a/src/main/java/link/locutus/discord/commands/manager/CommandManager.java +++ b/src/main/java/link/locutus/discord/commands/manager/CommandManager.java @@ -146,7 +146,7 @@ public class CommandManager { private final CommandManager2 modernized; private final CharOpenHashSet modernPrefixes; - public CommandManager(Locutus locutus) { + public CommandManager() { long start = System.currentTimeMillis(); this.prefix1 = Settings.commandPrefix(true).charAt(0); Logg.text("remove:||PERF commandmanager prefix " + (-start + (start = System.currentTimeMillis())) + "ms"); diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/AdminCommands.java b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/AdminCommands.java index 3a300aaf..23dba3eb 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/AdminCommands.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/AdminCommands.java @@ -1763,7 +1763,7 @@ public String importGuildKeys() { @Command(desc = "Test your alliance recruitment message by sending it to the bot creator's nation") @RolePermission(value = Roles.ADMIN) public String testRecruitMessage(@Me GuildDB db) throws IOException { - JsonObject response = db.sendRecruitMessage(Locutus.imp().getNationDB().getNation(Settings.INSTANCE.NATION_ID)); + JsonObject response = db.sendRecruitMessage(Locutus.imp().getNationDB().getNation(Locutus.loader().getNationId())); return response.toString(); } diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/BankCommands.java b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/BankCommands.java index aad3e7e5..ee516f71 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/BankCommands.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/BankCommands.java @@ -4133,7 +4133,7 @@ public String addOffshore(@Me IMessageIO io, @Me User user, @Me GuildDB root, @M Set announceChannels = new HashSet<>(); Set serverIds = new HashSet<>(); - if (nation.getNation_id() == Settings.INSTANCE.NATION_ID) { + if (nation.getNation_id() == Locutus.loader().getNationId()) { announceChannels.add(Settings.INSTANCE.DISCORD.CHANNEL.ADMIN_ALERTS); } diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/EmbedCommands.java b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/EmbedCommands.java index 96252bac..ae3715e5 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/EmbedCommands.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/EmbedCommands.java @@ -1,5 +1,6 @@ package link.locutus.discord.commands.manager.v2.impl.pw.commands; +import link.locutus.discord.Locutus; import link.locutus.discord.apiv1.enums.DepositType; import link.locutus.discord.apiv1.enums.city.project.Projects; import link.locutus.discord.commands.manager.v2.binding.ValueStore; @@ -983,7 +984,7 @@ public void iaPanel(@Me GuildDB db, @Me IMessageIO io, @Switch("c") MessageChann @HasOffshore @RolePermission(Roles.ADMIN) public void depositsPanel(@Me GuildDB db, @Me IMessageIO io, @Arg("Only applicable to corporate servers. The nation accepting trades for bank deposits. Defaults to the bot owner's nation") @Default DBNation bankerNation, @Switch("c") MessageChannel outputChannel) { - int nationId = Settings.INSTANCE.NATION_ID; + int nationId = Locutus.loader().getNationId(); if (bankerNation != null) { nationId = bankerNation.getId(); } diff --git a/src/main/java/link/locutus/discord/config/Settings.java b/src/main/java/link/locutus/discord/config/Settings.java index f2975cf6..5bbb8eb3 100644 --- a/src/main/java/link/locutus/discord/config/Settings.java +++ b/src/main/java/link/locutus/discord/config/Settings.java @@ -109,7 +109,7 @@ public String PNW_URL() { return "https://" + (TEST ? "test." : "") + "politicsandwar.com"; } public int ALLIANCE_ID() { - return Locutus.imp().getNationDB().getNation(NATION_ID).getAlliance_id(); + return Locutus.imp().getNationDB().getNation(Locutus.loader().getNationId()).getAlliance_id(); } public static class ENABLED_COMPONENTS { diff --git a/src/main/java/link/locutus/discord/db/NationDB.java b/src/main/java/link/locutus/discord/db/NationDB.java index 552df6a5..bb5a77cb 100644 --- a/src/main/java/link/locutus/discord/db/NationDB.java +++ b/src/main/java/link/locutus/discord/db/NationDB.java @@ -170,6 +170,7 @@ public NationDB load() throws SQLException { System.out.println("Done loading nations/meta"); loadTreasures(); + return this; } public void deleteExpiredTreaties(Consumer eventConsumer) { @@ -1837,7 +1838,7 @@ public Set updateAllNations(Consumer eventConsumer) { public void markDirtyIncorrectNations(boolean score, boolean cities) { int originalSize = dirtyNations.size(); for (DBNation nation : getNationsMatching(f -> f.getVm_turns() == 0)) { - if (score && Math.round(100 * (nation.estimateScore() - nation.getScore())) != 0) { + if (score && Math.round(100 * (PW.estimateScore(this, nation) - nation.getScore())) != 0) { dirtyNations.add(nation.getNation_id()); } else { Map cityMap = getCitiesV3(nation.getNation_id()); @@ -1958,11 +1959,11 @@ public void updateNationCitiesAndPositions(Collection allNations, Map< System.out.println("Contains " + allNations.contains(DBNation.getById(10251))); for (DBNation nation : allNations) { if (nation.getId() == 10251) { - System.out.println("Score " + nation.getScore() + " | " + nation.estimateScore()); + System.out.println("Score " + nation.getScore() + " | " + PW.estimateScore(this, nation)); } else if (allNations.size() == 1) { System.out.println("Updated " + nation.getId()); } - if (Math.round(100 * (nation.getScore() - nation.estimateScore())) != 0) { + if (Math.round(100 * (nation.getScore() - PW.estimateScore(this, nation))) != 0) { fetchCitiesOfNations.add(nation.getId()); } } diff --git a/src/main/java/link/locutus/discord/db/WarDB.java b/src/main/java/link/locutus/discord/db/WarDB.java index fe78f1ac..9b22e66e 100644 --- a/src/main/java/link/locutus/discord/db/WarDB.java +++ b/src/main/java/link/locutus/discord/db/WarDB.java @@ -67,7 +67,7 @@ public class WarDB extends DBMainV2 { - private final ActiveWarHandler activeWars = new ActiveWarHandler(); + private final ActiveWarHandler activeWars = new ActiveWarHandler(this); private final ObjectOpenHashSet warsById; private final Int2ObjectOpenHashMap warsByAllianceId; private final Int2ObjectOpenHashMap warsByNationId; @@ -532,8 +532,6 @@ public WarDB load() { loadAttacks(Settings.INSTANCE.TASKS.LOAD_INACTIVE_ATTACKS, Settings.INSTANCE.TASKS.LOAD_ACTIVE_ATTACKS); Logg.text("remove:||PERF Loaded wardb attacks in " + (-start + (start = System.currentTimeMillis()))); - Logg.text("remove:||PERF Updating attacks " + (-start + (start = System.currentTimeMillis()))); - { // get attacks by id 20071530 // Map wars = getWars(f -> f.date > System.currentTimeMillis() - TimeUnit.DAYS.toMillis(20)); @@ -550,12 +548,14 @@ public WarDB load() { } } + System.out.println("Sync blockades??? " + activeWars.getActiveWars().size()); activeWars.syncBlockades(); Logg.text("remove:||PERF Loaded wars and attacks " + (-start + (start = System.currentTimeMillis()))); if (conflictManager != null) { conflictManager.loadConflicts(); Logg.text("remove:||PERF Loaded conflicts " + (-start + (start = System.currentTimeMillis()))); } + return this; } public Set getNationsBlockadedBy(int nationId) { @@ -2919,7 +2919,7 @@ public int countWarsByAlliance(int alliance_id, long date) { } public AttackQuery queryAttacks() { - return new AttackQuery(); + return new AttackQuery(this); } public void syncBlockades() { diff --git a/src/main/java/link/locutus/discord/db/entities/DBNation.java b/src/main/java/link/locutus/discord/db/entities/DBNation.java index c25dc07c..344c87e6 100644 --- a/src/main/java/link/locutus/discord/db/entities/DBNation.java +++ b/src/main/java/link/locutus/discord/db/entities/DBNation.java @@ -2707,27 +2707,7 @@ public double getScore() { } public double estimateScore(MMRDouble mmr, Double infra, Integer projects, Integer cities) { - if (projects == null) projects = getNumProjects(); - if (infra == null) infra = getInfra(); - if (cities == null) cities = this.cities; - - double base = 10; - base += projects * Projects.getScore(); - base += (cities - 1) * 100; - base += infra / 40d; - for (MilitaryUnit unit : MilitaryUnit.values) { - if (unit == MilitaryUnit.INFRASTRUCTURE) continue; - int amt; - if (mmr != null && unit.getBuilding() != null) { - amt = (int) (mmr.getPercent(unit) * unit.getBuilding().getUnitCap() * unit.getBuilding().cap(f -> false) * cities); - } else { - amt = getUnits(unit); - } - if (amt > 0) { - base += unit.getScore(amt); - } - } - return base; + return PW.estimateScore(Locutus.imp().getNationDB(), this, mmr, infra, projects, cities); } public void setScore(double score) { diff --git a/src/main/java/link/locutus/discord/db/guild/GuildSetting.java b/src/main/java/link/locutus/discord/db/guild/GuildSetting.java index 0c06a4a1..950f2c7d 100644 --- a/src/main/java/link/locutus/discord/db/guild/GuildSetting.java +++ b/src/main/java/link/locutus/discord/db/guild/GuildSetting.java @@ -46,6 +46,7 @@ import java.util.concurrent.ConcurrentLinkedQueue; import java.util.function.BiPredicate; import java.util.function.Consumer; +import java.util.function.Supplier; import static com.google.gson.internal.$Gson$Preconditions.checkNotNull; @@ -54,7 +55,7 @@ public abstract class GuildSetting { private final Set requiresCoalitionStr = new LinkedHashSet<>(); private final Set requiresCoalitionRootStr = new LinkedHashSet<>(); - private final Map, String> requiresFunction = new LinkedHashMap<>(); + private final Map, Supplier> requiresFunction = new LinkedHashMap<>(); private final Map requiresRole = new LinkedHashMap<>(); private final Key type; @@ -77,7 +78,8 @@ public List getRequirementDesc() { for (Roles role : requiresRole.keySet()) { reqListStr.add("role:" + role.name()); } - for (String value : requiresFunction.values()) { + for (Supplier valueSup : requiresFunction.values()) { + String value = valueSup.get(); if (value.isEmpty()) continue; reqListStr.add("function:" + value); } @@ -348,10 +350,10 @@ public boolean allowed(GuildDB db, boolean throwException) { } public GuildSetting requiresOffshore() { - String msg = "No bank is setup (see: " + CM.offshore.add.cmd.toSlashCommand() + ")"; + Supplier msg = () -> "No bank is setup (see: " + CM.offshore.add.cmd.toSlashCommand() + ")"; this.requiresFunction.put((db, throwError) -> { if (db.getOffshoreDB() == null) { - throw new IllegalArgumentException(msg); + throw new IllegalArgumentException(msg.get()); } return true; }, msg); @@ -379,7 +381,7 @@ public boolean test(GuildDB db, Boolean throwError) { } return true; } - }, msg); + }, () -> msg); return this; } @@ -392,7 +394,7 @@ public boolean test(GuildDB db, Boolean throwError) { if (db.hasCoalitionPermsOnRoot(Coalition.WHITELISTED)) return true; throw new IllegalArgumentException(msg); } - }, msg); + }, () -> msg); return this; } @@ -424,10 +426,10 @@ public static Category validateCategory(GuildDB db, Category category) { } public GuildSetting requireValidAlliance() { - String msg = "No valid alliance is setup (see: " + GuildKey.ALLIANCE_ID.getCommandMention() + ")"; + Supplier msg = () -> "No valid alliance is setup (see: " + GuildKey.ALLIANCE_ID.getCommandMention() + ")"; requiresFunction.put((db, throwError) -> { if (!db.isValidAlliance()) { - throw new IllegalArgumentException(msg); + throw new IllegalArgumentException(msg.get()); } return true; }, msg); @@ -439,10 +441,10 @@ public GuildSetting requiresNot(GuildSetting setting) { } public GuildSetting requiresNot(GuildSetting setting, boolean checkDelegate) { - String msg = "Cannot be used with " + setting.name() + " set. Unset via " + CM.settings.info.cmd.toSlashMention(); + Supplier msg = () -> "Cannot be used with " + setting.name() + " set. Unset via " + CM.settings.info.cmd.toSlashMention(); requiresFunction.put((db, throwError) -> { if (setting.getOrNull(db, checkDelegate) != null) { - throw new IllegalArgumentException(msg); + throw new IllegalArgumentException(msg.get()); } return true; }, msg); @@ -458,7 +460,7 @@ public GuildSetting requireFunction(Consumer predicate, String msg) return false; } return true; - }, msg); + }, () -> msg); return this; } diff --git a/src/main/java/link/locutus/discord/db/handlers/ActiveWarHandler.java b/src/main/java/link/locutus/discord/db/handlers/ActiveWarHandler.java index 637f6d9f..1b794b41 100644 --- a/src/main/java/link/locutus/discord/db/handlers/ActiveWarHandler.java +++ b/src/main/java/link/locutus/discord/db/handlers/ActiveWarHandler.java @@ -7,6 +7,7 @@ import link.locutus.discord.apiv1.domains.subdomains.attack.v3.AbstractCursor; import link.locutus.discord.apiv1.enums.AttackType; import link.locutus.discord.apiv1.enums.SuccessType; +import link.locutus.discord.db.WarDB; import link.locutus.discord.db.entities.DBWar; import link.locutus.discord.event.Event; import link.locutus.discord.event.nation.NationBlockadedEvent; @@ -20,8 +21,13 @@ public class ActiveWarHandler { private final Map activeWars = new Int2ObjectOpenHashMap<>(); + private final WarDB warDB; private volatile int numActiveWars = 0; + public ActiveWarHandler(WarDB warDB) { + this.warDB = warDB; + } + private void makeWarInactive(int nationId, int warId) { synchronized (activeWars) { DBWar[] wars = activeWars.get(nationId); @@ -276,11 +282,16 @@ public void removeBlockade(int defender, int attacker, long date, Consumer wars = Locutus.imp().getWarDb().getWarsSince(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(10)); - List attacks = Locutus.imp().getWarDb().queryAttacks().withWars(wars).withType(AttackType.NAVAL).afterDate(now - TimeUnit.DAYS.toMillis(10)).getList(); + System.out.println("Get wars"); + Map wars = warDB.getWarsSince(System.currentTimeMillis() - TimeUnit.DAYS.toMillis(10)); + System.out.println("Get attacks"); + List attacks = warDB.queryAttacks().withWars(wars).withType(AttackType.NAVAL).afterDate(now - TimeUnit.DAYS.toMillis(10)).getList(); + System.out.println("query attacks size " + attacks.size()); attacks.sort(Comparator.comparingLong(AbstractCursor::getDate)); + System.out.println("Sort " + attacks.size()); ObjectOpenHashSet activeWars2 = getActiveWarsById(); + System.out.println("Get active wars " + activeWars2.size()); synchronized (blockadeLock) { defenderToBlockader.clear(); @@ -301,5 +312,6 @@ public void syncBlockades() { } } } + System.out.println("Done fetch"); } } diff --git a/src/main/java/link/locutus/discord/db/handlers/AttackQuery.java b/src/main/java/link/locutus/discord/db/handlers/AttackQuery.java index f8aa6c84..a0b2aa4a 100644 --- a/src/main/java/link/locutus/discord/db/handlers/AttackQuery.java +++ b/src/main/java/link/locutus/discord/db/handlers/AttackQuery.java @@ -24,13 +24,14 @@ public class AttackQuery { + private final WarDB warDb; public ObjectOpenHashSet wars; public Predicate attackTypeFilter; public Predicate preliminaryFilter; public Predicate attackFilter; - public AttackQuery() { - + public AttackQuery(WarDB warDb) { + this.warDb = warDb; } public Set getWars() { @@ -38,7 +39,7 @@ public Set getWars() { } public WarDB getDb() { - return Locutus.imp().getWarDb(); + return warDb; } public AttackQuery withWars(Collection wars) { diff --git a/src/main/java/link/locutus/discord/util/PW.java b/src/main/java/link/locutus/discord/util/PW.java index 4719b86a..e961c2a1 100644 --- a/src/main/java/link/locutus/discord/util/PW.java +++ b/src/main/java/link/locutus/discord/util/PW.java @@ -29,12 +29,9 @@ import link.locutus.discord.commands.stock.Exchange; import link.locutus.discord.config.Settings; import link.locutus.discord.db.GuildDB; +import link.locutus.discord.db.NationDB; import link.locutus.discord.db.TradeDB; -import link.locutus.discord.db.entities.Coalition; -import link.locutus.discord.db.entities.DBAlliance; -import link.locutus.discord.db.entities.DBNation; -import link.locutus.discord.db.entities.DBTrade; -import link.locutus.discord.db.entities.Transaction2; +import link.locutus.discord.db.entities.*; import link.locutus.discord.db.guild.GuildKey; import link.locutus.discord.pnw.NationOrAllianceOrGuildOrTaxid; import link.locutus.discord.util.discord.DiscordUtil; @@ -1202,6 +1199,39 @@ public Integer apply(Integer min, Integer max) { }; } + public static double estimateScore(NationDB db, DBNation nation) { + return estimateScore(db, nation, null, null, null, null); + } + + public static double estimateScore(NationDB db, DBNation nation, MMRDouble mmr, Double infra, Integer projects, Integer cities) { + if (projects == null) projects = nation.getNumProjects(); + if (infra == null) { + infra = 0d; + for (DBCity city : db.getCitiesV3(nation.getNation_id()).values()) { + infra += city.getInfra(); + } + } + if (cities == null) cities = nation.getCities(); + + double base = 10; + base += projects * Projects.getScore(); + base += (cities - 1) * 100; + base += infra / 40d; + for (MilitaryUnit unit : MilitaryUnit.values) { + if (unit == MilitaryUnit.INFRASTRUCTURE) continue; + int amt; + if (mmr != null && unit.getBuilding() != null) { + amt = (int) (mmr.getPercent(unit) * unit.getBuilding().getUnitCap() * unit.getBuilding().cap(f -> false) * cities); + } else { + amt = nation.getUnits(unit); + } + if (amt > 0) { + base += unit.getScore(amt); + } + } + return base; + } + public static BiFunction getIsNationsInScoreRange(Collection attackers) { int minScore = Integer.MAX_VALUE; int maxScore = 0; From 60ea3fe3114f9bc09c84b169905b7e41832d82ec Mon Sep 17 00:00:00 2001 From: test Date: Sat, 24 Aug 2024 15:39:53 +1000 Subject: [PATCH 04/27] Event post async --- .../java/link/locutus/discord/Locutus.java | 38 +++++--- .../link/locutus/discord/_main/PreLoader.java | 6 +- .../subscription/PnwPusherShardManager.java | 4 +- .../commands/info/optimal/OptimalBuild.java | 2 +- .../discord/commands/manager/Command.java | 2 +- .../commands/manager/CommandManager.java | 2 +- .../manager/v2/impl/SlashCommandManager.java | 2 +- .../v2/impl/pw/binding/PWBindings.java | 3 +- .../pw/binding/autocomplete/PWCompleter.java | 96 +++++++++++++++++-- .../v2/impl/pw/commands/BankCommands.java | 10 +- .../v2/impl/pw/commands/TradeCommands.java | 2 +- .../discord/commands/sheets/ProjectSheet.java | 2 +- .../link/locutus/discord/db/DiscordDB.java | 21 ++-- .../link/locutus/discord/db/NationDB.java | 14 ++- .../java/link/locutus/discord/db/WarDB.java | 29 ++++-- .../discord/db/entities/DBAlliance.java | 45 ++++----- .../locutus/discord/db/entities/DBNation.java | 36 ++++--- .../locutus/discord/db/guild/GuildKey.java | 2 +- .../discord/db/guild/GuildSetting.java | 4 +- .../discord/db/guild/SendInternalTask.java | 3 +- .../locutus/discord/pnw/AllianceList.java | 8 +- .../java/link/locutus/discord/user/Roles.java | 8 +- .../link/locutus/discord/util/SpyCount.java | 5 +- .../link/locutus/discord/util/StringMan.java | 9 +- .../util/offshore/OffshoreInstance.java | 8 +- .../util/offshore/test/IACategory.java | 4 +- .../util/update/LeavingBeigeAlert.java | 2 +- .../util/update/WarUpdateProcessor.java | 2 +- .../web/commands/binding/AuthBindings.java | 2 +- src/main/jte/footer.jte | 5 +- 30 files changed, 243 insertions(+), 133 deletions(-) diff --git a/src/main/java/link/locutus/discord/Locutus.java b/src/main/java/link/locutus/discord/Locutus.java index 71a6ec45..eea2e6f1 100644 --- a/src/main/java/link/locutus/discord/Locutus.java +++ b/src/main/java/link/locutus/discord/Locutus.java @@ -43,6 +43,7 @@ import link.locutus.discord.util.offshore.OffshoreInstance; import link.locutus.discord.util.scheduler.CaughtTask; import link.locutus.discord.util.scheduler.ThrowingConsumer; +import link.locutus.discord.util.scheduler.ThrowingFunction; import link.locutus.discord.util.task.ia.MapFullTask; import link.locutus.discord.util.task.mail.AlertMailTask; import link.locutus.discord.util.task.roles.AutoRoleInfo; @@ -164,31 +165,31 @@ public static ILoader loader() { } public void registerEvents() { - System.out.println("Registering events"); + long start = System.currentTimeMillis(); eventBus.register(new TreatyUpdateProcessor()); - System.out.println("Registered TreatyUpdateProcessor"); + System.out.println("remove:||PERF treaty update processor " + (((-start)) + (start = System.currentTimeMillis()))); eventBus.register(new NationUpdateProcessor()); - System.out.println("Registered NationUpdateProcessor"); + System.out.println("Registered NationUpdateProcessor " + (((-start)) + (start = System.currentTimeMillis()))); eventBus.register(new TradeListener()); - System.out.println("Registered TradeListener"); + System.out.println("Registered TradeListener " + (((-start)) + (start = System.currentTimeMillis()))); eventBus.register(new CityUpdateProcessor()); - System.out.println("Registered CityUpdateProcessor"); + System.out.println("Registered CityUpdateProcessor " + (((-start)) + (start = System.currentTimeMillis()))); eventBus.register(new BankUpdateProcessor()); - System.out.println("Registered BankUpdateProcessor"); + System.out.println("Registered BankUpdateProcessor " + (((-start)) + (start = System.currentTimeMillis()))); eventBus.register(new WarUpdateProcessor()); - System.out.println("Registered WarUpdateProcessor"); + System.out.println("Registered WarUpdateProcessor " + (((-start)) + (start = System.currentTimeMillis()))); eventBus.register(new AllianceListener()); - System.out.println("Registered AllianceListener"); + System.out.println("Registered AllianceListener " + (((-start)) + (start = System.currentTimeMillis()))); CommandManager cmdManager = loader.getCommandManager(); - System.out.println("Get CommandManager"); + System.out.println("Get CommandManager " + (((-start)) + (start = System.currentTimeMillis()))); eventBus.register(new MailListener(cmdManager.getV2().getStore(), cmdManager.getV2().getValidators(), cmdManager.getV2().getPermisser())); - System.out.println("Registered MailListener"); + System.out.println("Registered MailListener " + (((-start)) + (start = System.currentTimeMillis()))); WarDB warDb = loader.getWarDB(); - System.out.println("Get WarDB"); + System.out.println("Get WarDB " + (((-start)) + (start = System.currentTimeMillis()))); ConflictManager conflictManager = warDb == null ? null : warDb.getConflicts(); - System.out.println("Get ConflictManager"); + System.out.println("Get ConflictManager " + (((-start)) + (start = System.currentTimeMillis()))); if (conflictManager != null) eventBus.register(conflictManager); - System.out.println("Registered ConflictManager"); + System.out.println("Registered ConflictManager " + (((-start)) + (start = System.currentTimeMillis()))); } public EventBus getEventBus() { @@ -511,11 +512,18 @@ public void runUnsafe() { } public void runEventsAsync(ThrowingConsumer> eventHandler) { - ArrayDeque events = new ArrayDeque<>(); + ArrayDeque events = new ArrayDeque<>(0); eventHandler.accept(events::add); runEventsAsync(events); } + public T returnEventsAsync(ThrowingFunction, T> eventHandler) { + Collection events = new ArrayDeque<>(0); + T result = eventHandler.apply(events::add); + runEventsAsync(events); + return result; + } + public void runEventsAsync(Collection events) { if (events.isEmpty()) return; getExecutor().submit(new CaughtRunnable() { @@ -1127,7 +1135,7 @@ public void onMessageReactionAdd(@Nonnull MessageReactionAddEvent event) { Message message = isMessageLocutus(event.getMessageIdLong(), event.getGuildChannel()); if (message == null) return; EmojiUnion emote; - if (event.getUser().getIdLong() == Settings.INSTANCE.ADMIN_USER_ID) { + if (event.getUser().getIdLong() == Locutus.loader().getAdminUserId()) { emote = event.getEmoji(); if ("\uD83D\uDEAB".equals(emote.asUnicode().getAsCodepoints())) { link.locutus.discord.util.RateLimitUtil.queue(event.getChannel().deleteMessageById(event.getMessageIdLong())); diff --git a/src/main/java/link/locutus/discord/_main/PreLoader.java b/src/main/java/link/locutus/discord/_main/PreLoader.java index b6ba0476..e96c2b6d 100644 --- a/src/main/java/link/locutus/discord/_main/PreLoader.java +++ b/src/main/java/link/locutus/discord/_main/PreLoader.java @@ -106,7 +106,8 @@ public SlashCommandManager getThrows() throws Exception { this.getNationId = add("Fetch Nation ID", new ThrowingSupplier>() { @Override public Supplier getThrows() throws Exception { - Integer nationIdFromKey = getDiscordDB().getNationFromApiKey(Settings.INSTANCE.API_KEY_PRIMARY); + String apiKey = getApiKey(); + Integer nationIdFromKey = getDiscordDB().getNationFromApiKey(apiKey); if (nationIdFromKey == null) { Settings.INSTANCE.NATION_ID = -1; } else { @@ -122,7 +123,8 @@ public Supplier getThrows() throws Exception { this.adminUserId = add("Discord Admin User ID", new ThrowingSupplier>() { @Override public Supplier getThrows() throws Exception { - PNWUser adminPnwUser = getDiscordDB().getUserFromNationId(Settings.INSTANCE.NATION_ID); + int nationId = getNationId(); + PNWUser adminPnwUser = getDiscordDB().getUserFromNationId(nationId); if (adminPnwUser != null) { Settings.INSTANCE.ADMIN_USER_ID = adminPnwUser.getDiscordId(); } diff --git a/src/main/java/link/locutus/discord/apiv3/subscription/PnwPusherShardManager.java b/src/main/java/link/locutus/discord/apiv3/subscription/PnwPusherShardManager.java index d06d631b..eb3cfdc3 100644 --- a/src/main/java/link/locutus/discord/apiv3/subscription/PnwPusherShardManager.java +++ b/src/main/java/link/locutus/discord/apiv3/subscription/PnwPusherShardManager.java @@ -120,14 +120,14 @@ public void subscribeDefaultEvents() { // root.subscribeBuilder(Nation.class, PnwPusherEvent.DELETE).build(nations -> { // Locutus.imp().runEventsAsync(events -> nationDB.deleteNations(nations.stream().map(Nation::getId).collect(Collectors.toSet()), events)); // }); - root.subscribeBuilder(Settings.INSTANCE.API_KEY_PRIMARY, Bounty.class, PnwPusherEvent.CREATE).build(bounties -> { + root.subscribeBuilder(Locutus.loader().getApiKey(), Bounty.class, PnwPusherEvent.CREATE).build(bounties -> { try { spyTracker.checkBounties(bounties); } catch (IOException e) { e.printStackTrace(); } }); - root.subscribeBuilder(Settings.INSTANCE.API_KEY_PRIMARY, Nation.class, PnwPusherEvent.UPDATE).build(nations -> { + root.subscribeBuilder(Locutus.loader().getApiKey(), Nation.class, PnwPusherEvent.UPDATE).build(nations -> { try { spyTracker.updateCasualties(nations); Locutus.imp().runEventsAsync(f -> Locutus.imp().getNationDB().updateNations(nations, f, -1)); diff --git a/src/main/java/link/locutus/discord/commands/info/optimal/OptimalBuild.java b/src/main/java/link/locutus/discord/commands/info/optimal/OptimalBuild.java index a3a4d24e..6e22f556 100644 --- a/src/main/java/link/locutus/discord/commands/info/optimal/OptimalBuild.java +++ b/src/main/java/link/locutus/discord/commands/info/optimal/OptimalBuild.java @@ -267,7 +267,7 @@ public String onCommand(IMessageIO io, Guild guild, User author, DBNation me, Li cityId = Integer.parseInt(cityArg.split("=")[1]); DBCity cityEntry = Locutus.imp().getNationDB().getCitiesV3ByCityId(cityId); - if (cityEntry == null) Locutus.imp().getNationDB().getCitiesV3ByCityId(cityId, true, f -> f.post()); + if (cityEntry == null) Locutus.imp().runEventsAsync(events -> Locutus.imp().getNationDB().getCitiesV3ByCityId(cityId, true, events)); cityEntry.update(true); me = Locutus.imp().getNationDB().getNation(cityEntry.getNationId()); origin = cityEntry.toJavaCity(me); diff --git a/src/main/java/link/locutus/discord/commands/manager/Command.java b/src/main/java/link/locutus/discord/commands/manager/Command.java index 4d780c9d..59a09b31 100644 --- a/src/main/java/link/locutus/discord/commands/manager/Command.java +++ b/src/main/java/link/locutus/discord/commands/manager/Command.java @@ -144,7 +144,7 @@ public boolean checkPermission(Guild server, User user, boolean checkGuild) { if (user.getIdLong() == Settings.INSTANCE.APPLICATION_ID) { return true; } - if (user.getIdLong() == Settings.INSTANCE.ADMIN_USER_ID) { + if (user.getIdLong() == Locutus.loader().getAdminUserId()) { return true; } if (checkGuild && !checkGuildPermission(server)) { diff --git a/src/main/java/link/locutus/discord/commands/manager/CommandManager.java b/src/main/java/link/locutus/discord/commands/manager/CommandManager.java index c3ee8b06..63a575d9 100644 --- a/src/main/java/link/locutus/discord/commands/manager/CommandManager.java +++ b/src/main/java/link/locutus/discord/commands/manager/CommandManager.java @@ -367,7 +367,7 @@ public boolean run(Guild guild, IMessageIO channel, final User msgUser, String c // return; } if (result != null && !result.isEmpty()) { - result = result.replaceAll("(?i)" + Settings.INSTANCE.API_KEY_PRIMARY, "XXX"); + result = result.replaceAll("(?i)" + Locutus.loader().getApiKey(), "XXX"); // result = result.replaceAll("(?i)(?<=^|[^A-Fa-f0-9])(?:[0-9a-f]{2}){7,}(?=[^A-Fa-f0-9]|$)", "XXX"); channel.send(result); } diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/impl/SlashCommandManager.java b/src/main/java/link/locutus/discord/commands/manager/v2/impl/SlashCommandManager.java index d04770c4..384b18d2 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/impl/SlashCommandManager.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/impl/SlashCommandManager.java @@ -633,7 +633,7 @@ public void onCommandAutoCompleteInteraction(@Nonnull CommandAutoCompleteInterac return; } - if (event.getUser().getIdLong() == Settings.INSTANCE.ADMIN_USER_ID) { + if (event.getUser().getIdLong() == Locutus.loader().getAdminUserId()) { System.out.println("remove:||Admin runs complete " + path + " | " + option.getValue()); } diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/binding/PWBindings.java b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/binding/PWBindings.java index 6e472d99..f9e842de 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/binding/PWBindings.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/binding/PWBindings.java @@ -472,7 +472,8 @@ public CityBuild city(@Default @Me DBNation nation, @TextArea String input) { cityId = Integer.parseInt(input.split("=")[1]); DBCity cityEntry = Locutus.imp().getNationDB().getCitiesV3ByCityId(cityId); if (cityEntry == null) { - cityEntry = Locutus.imp().getNationDB().getCitiesV3ByCityId(cityId, true, f -> f.post()); + final int finalCityId = cityId; + cityEntry = Locutus.imp().returnEventsAsync(f -> Locutus.imp().getNationDB().getCitiesV3ByCityId(finalCityId, true, f)); if (cityEntry == null) { throw new IllegalArgumentException("No city found in cache with id " + cityId + " (expecting city id or url)"); } diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/binding/autocomplete/PWCompleter.java b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/binding/autocomplete/PWCompleter.java index c800c52b..f805380b 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/binding/autocomplete/PWCompleter.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/binding/autocomplete/PWCompleter.java @@ -2,15 +2,7 @@ import com.google.gson.reflect.TypeToken; import link.locutus.discord.Locutus; -import link.locutus.discord.apiv1.enums.AttackType; -import link.locutus.discord.apiv1.enums.Continent; -import link.locutus.discord.apiv1.enums.DepositType; -import link.locutus.discord.apiv1.enums.FlowType; -import link.locutus.discord.apiv1.enums.MilitaryUnit; -import link.locutus.discord.apiv1.enums.ResourceType; -import link.locutus.discord.apiv1.enums.WarCostMode; -import link.locutus.discord.apiv1.enums.WarCostStat; -import link.locutus.discord.apiv1.enums.WarType; +import link.locutus.discord.apiv1.enums.*; import link.locutus.discord.apiv1.enums.city.building.Building; import link.locutus.discord.apiv1.enums.city.building.Buildings; import link.locutus.discord.apiv1.enums.city.project.Project; @@ -27,10 +19,15 @@ import link.locutus.discord.commands.manager.v2.impl.pw.NationPlaceholder; import link.locutus.discord.commands.manager.v2.impl.pw.binding.NationAttribute; import link.locutus.discord.commands.manager.v2.impl.pw.binding.NationAttributeDouble; +import link.locutus.discord.commands.manager.v2.impl.pw.binding.PWBindings; +import link.locutus.discord.commands.manager.v2.impl.pw.binding.SheetBindings; import link.locutus.discord.commands.manager.v2.impl.pw.commands.UnsortedCommands; import link.locutus.discord.commands.manager.v2.impl.pw.filter.NationPlaceholders; +import link.locutus.discord.commands.manager.v2.impl.pw.filter.PlaceholdersMap; import link.locutus.discord.db.GuildDB; import link.locutus.discord.db.ReportManager; +import link.locutus.discord.db.conflict.Conflict; +import link.locutus.discord.db.conflict.ConflictManager; import link.locutus.discord.db.entities.*; import link.locutus.discord.db.entities.DBAlliance; import link.locutus.discord.db.entities.grant.AGrantTemplate; @@ -62,14 +59,95 @@ import net.dv8tion.jda.api.entities.channel.concrete.Category; import net.dv8tion.jda.api.interactions.commands.build.OptionData; +import java.awt.*; import java.lang.reflect.Type; import java.util.*; +import java.util.List; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; public class PWCompleter extends BindingHelper { + @Autocomplete + @PlaceholderType + @Binding(types={Class.class}) + public List PlaceholderType(String input) { + PlaceholdersMap phMap = Locutus.cmd().getV2().getPlaceholders(); + List options = phMap.getTypes().stream().map(f -> PlaceholdersMap.getClassName(f)).collect(Collectors.toList()); + return StringMan.getClosest(input, options, true); + } + @Autocomplete + @Binding(types={NationMeta.class}) + public List NationMeta(String input) { + return StringMan.completeEnum(input, NationMeta.class); + } + @Autocomplete + @Binding(types={Font.class}) + public List Font(String input) { + String[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames(); + return StringMan.getClosest(input, Arrays.asList(fonts), true); + } + @Autocomplete + @Binding(types={Set.class, TreatyType.class}, multiple = true) + public List> TreatyType(String input) { + return StringMan.autocompleteCommaEnum(TreatyType.class, input, OptionData.MAX_CHOICES); + } + @Autocomplete + @Binding(types={Set.class, NationColor.class}, multiple = true) + public List> NationColor(String input) { + return StringMan.autocompleteCommaEnum(NationColor.class, input, OptionData.MAX_CHOICES); + } + @Autocomplete + @Binding(types={Set.class, Conflict.class}, multiple = true) + public List> Conflict(ConflictManager manager, String input) { + List options = new ArrayList<>(manager.getConflictMap().values()); + return StringMan.autocompleteComma(input, options, + f -> PWBindings.conflict(manager, f), + Conflict::getName, + f -> f.getId() + "", + OptionData.MAX_CHOICES); + } + @Autocomplete + @Binding(types={Set.class, SuccessType.class}, multiple = true) + public List> SuccessType(String input) { + return StringMan.autocompleteCommaEnum(SuccessType.class, input, OptionData.MAX_CHOICES); + } + @Autocomplete + @Binding(types={Set.class, ResourceType.class}, multiple = true) + public List> ResourceType(String input) { + return StringMan.autocompleteCommaEnum(ResourceType.class, input, OptionData.MAX_CHOICES); + } + @Autocomplete + @Binding(types={Set.class, GuildDB.class}, multiple = true) + public List> GuildDB(@Me User user, String input) { + List options = user.getMutualGuilds().stream().map(Locutus.imp()::getGuildDB).toList(); + Map byMap = new HashMap<>(); + for (GuildDB db : options) { + byMap.put(db.getGuild().getName().toLowerCase(), db); + } + return StringMan.autocompleteComma(input, options, + f -> f.isEmpty() ? null : byMap.get(f.split("/")[0].toLowerCase()), + GuildDB::getName, + f -> f.getGuild().getId(), + OptionData.MAX_CHOICES); + } + @Autocomplete + @Binding(types={Set.class, GuildSetting.class}, multiple = true) + public List GuildSetting(String input) { + List options = Arrays.stream(GuildKey.values()).map(GuildSetting::name).toList(); + return StringMan.autocompleteComma(input, options, OptionData.MAX_CHOICES); + } + @Autocomplete + @Binding(types={Set.class, AllianceMetric.class}, multiple = true) + public List> AllianceMetrics(String input) { + return StringMan.autocompleteCommaEnum(AllianceMetric.class, input, OptionData.MAX_CHOICES); + } + @Autocomplete + @Binding(types={Set.class, DomesticPolicy.class}, multiple = true) + public List> DomesticPolicy(String input) { + return StringMan.autocompleteCommaEnum(DomesticPolicy.class, input, OptionData.MAX_CHOICES); + } @Autocomplete @Binding(types={CommandCallable.class}) public List command(String input) { diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/BankCommands.java b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/BankCommands.java index ee516f71..8663e74e 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/BankCommands.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/BankCommands.java @@ -2131,7 +2131,7 @@ public static String transfer(@Me IMessageIO channel, @Me JSONObject command, // transfer limit long userId = author.getIdLong(); if (ResourceType.convertedTotal(transfer) > 5000000000L - && userId != Settings.INSTANCE.ADMIN_USER_ID + && userId != Locutus.loader().getAdminUserId() && !Settings.INSTANCE.LEGACY_SETTINGS.WHITELISTED_BANK_USERS.contains(userId) && !isGrant && offshore.getAllianceId() == Settings.INSTANCE.ALLIANCE_ID() ) { @@ -2458,7 +2458,7 @@ public static String depositSheet(@Me IMessageIO channel, @Me Guild guild, @Me G boolean updateBulk = Settings.INSTANCE.TASKS.BANK_RECORDS_INTERVAL_SECONDS > 0; if (updateBulk) { - Locutus.imp().getBankDB().updateBankRecs(false, Event::post); + Locutus.imp().runEventsAsync(events -> Locutus.imp().getBankDB().updateBankRecs(false, events)); } String noteFlowStr = useFlowNote == null ? null : "#" + useFlowNote.name().toLowerCase(Locale.ROOT); @@ -3501,7 +3501,7 @@ public String send(@Me IMessageIO channel, @Me JSONObject command, @Me GuildDB s @Default DBAlliance sender_alliance, @Switch("f") boolean force) throws IOException { - if (OffshoreInstance.DISABLE_TRANSFERS && user.getIdLong() != Settings.INSTANCE.ADMIN_USER_ID) throw new IllegalArgumentException("Error: Maintenance"); + if (OffshoreInstance.DISABLE_TRANSFERS && user.getIdLong() != Locutus.loader().getAdminUserId()) throw new IllegalArgumentException("Error: Maintenance"); return sendAA(channel, command, senderDB, user, me, amount, receiver_account, receiver_nation, sender_alliance, me, force); } @@ -3533,8 +3533,8 @@ public String sendAA(@Me IMessageIO channel, @Me JSONObject command, @Me GuildDB "Defaults to your nation", group = 2) @Default DBNation sender_nation, @Switch("f") boolean force) throws IOException { - if (user.getIdLong() != Settings.INSTANCE.ADMIN_USER_ID) return "WIP"; - if (OffshoreInstance.DISABLE_TRANSFERS && user.getIdLong() != Settings.INSTANCE.ADMIN_USER_ID) throw new IllegalArgumentException("Error: Maintenance"); + if (user.getIdLong() != Locutus.loader().getAdminUserId()) return "WIP"; + if (OffshoreInstance.DISABLE_TRANSFERS && user.getIdLong() != Locutus.loader().getAdminUserId()) throw new IllegalArgumentException("Error: Maintenance"); if (sender_alliance != null && !senderDB.isAllianceId(sender_alliance.getId())) { throw new IllegalArgumentException("Sender alliance is not in this guild"); } diff --git a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/TradeCommands.java b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/TradeCommands.java index 23610d54..25dbe621 100644 --- a/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/TradeCommands.java +++ b/src/main/java/link/locutus/discord/commands/manager/v2/impl/pw/commands/TradeCommands.java @@ -1005,7 +1005,7 @@ public String moneyTrades(TradeManager manager, DBNation nation, @Arg("Return a deposits add command for each grouping") @Switch("a") boolean addBalance) throws IOException { if (forceUpdate) { - manager.updateTradeList(Event::post); + Locutus.imp().runEventsAsync(events -> manager.updateTradeList(events)); } Map> netInflows = new HashMap<>(); diff --git a/src/main/java/link/locutus/discord/commands/sheets/ProjectSheet.java b/src/main/java/link/locutus/discord/commands/sheets/ProjectSheet.java index 261e39cd..06fccad1 100644 --- a/src/main/java/link/locutus/discord/commands/sheets/ProjectSheet.java +++ b/src/main/java/link/locutus/discord/commands/sheets/ProjectSheet.java @@ -76,7 +76,7 @@ public String onCommand(Guild guild, IMessageIO channel, User author, DBNation m if (flags.contains('f')) { List ids = nations.stream().map(f -> f.getNation_id()).collect(Collectors.toList()); - Locutus.imp().getNationDB().updateNations(ids, Event::post); + Locutus.imp().runEventsAsync(events -> Locutus.imp().getNationDB().updateNations(ids, events)); } sheet.setHeader(header); diff --git a/src/main/java/link/locutus/discord/db/DiscordDB.java b/src/main/java/link/locutus/discord/db/DiscordDB.java index 4012a2b6..935af9e1 100644 --- a/src/main/java/link/locutus/discord/db/DiscordDB.java +++ b/src/main/java/link/locutus/discord/db/DiscordDB.java @@ -416,7 +416,7 @@ public Map.Entry getUserPass2(long nationId) { } public Map.Entry getUserPass2(long nationId, String table, EncryptionUtil.Algorithm algorithm) { - if ((nationId == Settings.INSTANCE.ADMIN_USER_ID || nationId == Settings.INSTANCE.NATION_ID) && !Settings.INSTANCE.USERNAME.isEmpty() && !Settings.INSTANCE.PASSWORD.isEmpty()) { + if ((nationId == Settings.INSTANCE.ADMIN_USER_ID || nationId == Settings.INSTANCE.NATION_ID) && nationId > 0 && !Settings.INSTANCE.USERNAME.isEmpty() && !Settings.INSTANCE.PASSWORD.isEmpty()) { return Map.entry(Settings.INSTANCE.USERNAME, Settings.INSTANCE.PASSWORD); } try (PreparedStatement stmt = prepareQuery("select * FROM " + table + " WHERE `discordid` = ?")) { @@ -662,13 +662,14 @@ public Set getMultis(BigInteger uuid) { public int updateUserIdsSince(int minutes, boolean overrideExisting) { List toFetch = Locutus.imp().getNationDB().getNationsMatching(f -> f.getVm_turns() == 0 && f.active_m() < minutes).stream().map(DBNation::getNation_id).collect(Collectors.toList()); - int updated = 0; - - for (int i = 0; i < toFetch.size(); i += 500) { - List subList = toFetch.subList(i, Math.min(i + 500, toFetch.size())); - updated += updateUserIds(overrideExisting, f -> f.setId(subList), Event::post); - } - return updated; + return Locutus.imp().returnEventsAsync(events -> { + int updated = 0; + for (int i = 0; i < toFetch.size(); i += 500) { + List subList = toFetch.subList(i, Math.min(i + 500, toFetch.size())); + updated += updateUserIds(overrideExisting, f -> f.setId(subList), events); + } + return updated; + }); } public int updateUserIds(boolean overrideExisting, Consumer query, Consumer eventConsumer) { @@ -749,7 +750,7 @@ private List getUsersRaw() { } public PNWUser getUserFromNationId(int nationId) { - if (nationId == Settings.INSTANCE.NATION_ID && nationId > 0) { + if (nationId == Settings.INSTANCE.NATION_ID && nationId > 0 && Settings.INSTANCE.ADMIN_USER_ID > 0) { long userId = Settings.INSTANCE.ADMIN_USER_ID; User user = Locutus.imp().getDiscordApi().getUserById(userId); return new PNWUser(nationId, Settings.INSTANCE.ADMIN_USER_ID, user == null ? null : DiscordUtil.getFullUsername(user)); @@ -759,7 +760,7 @@ public PNWUser getUserFromNationId(int nationId) { } public PNWUser getUserFromDiscordId(long discordId) { - if (discordId == Settings.INSTANCE.ADMIN_USER_ID) { + if (discordId == Settings.INSTANCE.ADMIN_USER_ID && Settings.INSTANCE.NATION_ID > 0 && discordId > 0) { User user = Locutus.imp().getDiscordApi().getUserById(discordId); return new PNWUser(Settings.INSTANCE.NATION_ID, Settings.INSTANCE.ADMIN_USER_ID, user == null ? null : DiscordUtil.getFullUsername(user)); } diff --git a/src/main/java/link/locutus/discord/db/NationDB.java b/src/main/java/link/locutus/discord/db/NationDB.java index bb5a77cb..9a530eb8 100644 --- a/src/main/java/link/locutus/discord/db/NationDB.java +++ b/src/main/java/link/locutus/discord/db/NationDB.java @@ -1488,9 +1488,11 @@ public DBAlliance getAllianceByName(String name) { } private int loadTreaties() throws SQLException { + System.out.println("Load treaties"); int total = 0; Set treatiesToDelete = new LinkedHashSet<>(); long currentTurn = TimeUtil.getTurn(); + List postAsync = null; SelectBuilder builder = getDb().selectBuilder("TREATIES2").select("*"); try (ResultSet rs = builder.executeRaw()) { @@ -1504,7 +1506,7 @@ private int loadTreaties() throws SQLException { } if (currentTurn > treaty.getTurnEnds()) { if (Locutus.imp() != null) { - new TreatyExpireEvent(treaty).post(); + ((postAsync == null) ? postAsync = new ArrayList<>() : postAsync).add(new TreatyExpireEvent(treaty)); } treatiesToDelete.add(treaty.getId()); continue; @@ -1515,8 +1517,10 @@ private int loadTreaties() throws SQLException { total++; } } - + if (postAsync != null && Locutus.imp() != null) Locutus.imp().runEventsAsync(postAsync); + System.out.println("Del treaties"); deleteTreatiesInDB(treatiesToDelete); + System.out.println("DOne del treaties"); return total; } @@ -3563,9 +3567,13 @@ private int[] saveNationLoot(List entries) { .putColumn("type", Col */ long cutoff = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(1); + List events = null; for (LootEntry entry : entries) { if (entry.getDate() < cutoff) continue; - new LootInfoEvent(entry).post(); + (events == null ? events = new ArrayList<>() : events).add(new LootInfoEvent(entry)); + } + if (events != null && Locutus.imp() != null) { + Locutus.imp().runEventsAsync(events); } String query = "INSERT OR REPLACE INTO `NATION_LOOT3` (`id`, `total_rss`, `date`, `type`) VALUES(?,?,?,?)"; diff --git a/src/main/java/link/locutus/discord/db/WarDB.java b/src/main/java/link/locutus/discord/db/WarDB.java index 9b22e66e..92fd8e54 100644 --- a/src/main/java/link/locutus/discord/db/WarDB.java +++ b/src/main/java/link/locutus/discord/db/WarDB.java @@ -467,15 +467,20 @@ private void setWars(List allWars, boolean clear) { private void setWar(DBWar war, int id, int remaining, Int2ObjectOpenHashMap map) { map.merge(id, war, (o, o2) -> { if (o == null) { - return remaining > 1 ? new Object[remaining] : o2; + if (remaining <= 1) { + return o2; + } + ObjectOpenHashSet result = new ObjectOpenHashSet<>(); + result.add(o2); + return result; } else if (o instanceof DBWar oldWar) { - Object[] array = new Object[remaining + 1]; - array[0] = oldWar; - array[1] = o2; + ObjectOpenHashSet array = new ObjectOpenHashSet<>(remaining + 1); + array.add(oldWar); + array.add(o2); return array; } else { - Object[] array = (Object[]) o; - array[array.length - remaining] = o2; + ObjectOpenHashSet array = (ObjectOpenHashSet) o; + array.add(o2); return array; } }); @@ -1594,6 +1599,7 @@ public Set getBounties() { private Object bountyLock = new Object(); public void updateBountiesV3() throws IOException { + List events = null; synchronized (bountyLock) { Set removedBounties = getBounties(); Set newBounties = new LinkedHashSet<>(); @@ -1626,16 +1632,23 @@ public void updateBountiesV3() throws IOException { for (DBBounty bounty : removedBounties) { removeBounty(bounty); - if (callEvents) new BountyRemoveEvent(bounty).post(); + if (callEvents) { + (events == null ? (events = new ArrayList<>()) : events).add(new BountyRemoveEvent(bounty)); + } } for (DBBounty bounty : newBounties) { addBounty(bounty); if (Settings.INSTANCE.LEGACY_SETTINGS.DEANONYMIZE_BOUNTIES) { // TODO remove this } - if (callEvents) new BountyCreateEvent(bounty).post(); + if (callEvents) { + (events == null ? (events = new ArrayList<>()) : events).add(new BountyCreateEvent(bounty)); + } } } + if (events != null) { + Locutus.imp().runEventsAsync(events); + } } public void addBounty(DBBounty bounty) { diff --git a/src/main/java/link/locutus/discord/db/entities/DBAlliance.java b/src/main/java/link/locutus/discord/db/entities/DBAlliance.java index 92a8dd09..8a93f64e 100644 --- a/src/main/java/link/locutus/discord/db/entities/DBAlliance.java +++ b/src/main/java/link/locutus/discord/db/entities/DBAlliance.java @@ -811,9 +811,9 @@ public Map getTreaties(Predicate allowedType, boole PoliticsAndWarV3 api = getApi(AlliancePermission.MANAGE_TREATIES); if (api != null) { List treaties = api.fetchTreaties(allianceId); - Locutus.imp().getNationDB().updateTreaties(treaties, Event::post, f -> { - return f.getFromId() == allianceId || f.getToId() == allianceId; - }); + Locutus.imp().runEventsAsync(events -> + Locutus.imp().getNationDB(). + updateTreaties(treaties, events, f -> f.getFromId() == allianceId || f.getToId() == allianceId)); Map result = new HashMap<>(); for (com.politicsandwar.graphql.model.Treaty v3 : treaties) { Treaty treaty = new Treaty(v3); @@ -1222,8 +1222,7 @@ public void updateCities() throws IOException, ParseException { public void updateCities(Predicate fetchNation) throws IOException { Set nationIds = getNations(false, 0, true).stream().filter(fetchNation).map(DBNation::getId).collect(Collectors.toSet()); if (nationIds.isEmpty()) return; - System.out.println("Aa update cities"); - Locutus.imp().getNationDB().updateCitiesOfNations(nationIds, true, true, Event::post); + Locutus.imp().runEventsAsync(events -> Locutus.imp().getNationDB().updateCitiesOfNations(nationIds, true, true, events)); } public DBAlliance getCachedParentOfThisOffshore() { @@ -1636,34 +1635,28 @@ public Map updateOffSpyOps() { Map ops = new HashMap<>(); // get api PoliticsAndWarV3 api = getApiOrThrow(true, AlliancePermission.SEE_SPIES); - for (Nation nation : api.fetchNations(true, new Consumer() { - @Override - public void accept(NationsQueryRequest request) { + Locutus.imp().runEventsAsync(events -> { + for (Nation nation : api.fetchNations(true, request -> { request.setAlliance_id(List.of(allianceId)); request.setVmode(false); - } - }, new Consumer() { - @Override - public void accept(NationResponseProjection proj) { + }, proj -> { proj.id(); proj.spies(); proj.spy_attacks(); proj.espionage_available(); + })) { + DBNation dbNation = DBNation.getById(nation.getId()); + if (dbNation == null) continue; + dbNation.setSpies(nation.getSpies(), events); + if (nation.getEspionage_available() != (dbNation.isEspionageAvailable())) { + dbNation.setEspionageFull(!nation.getEspionage_available()); + } + if (nation.getSpy_attacks() != null) { + nation.setSpy_attacks(nation.getSpy_attacks()); + ops.put(dbNation, nation.getSpy_attacks()); + } } - })) { - DBNation dbNation = DBNation.getById(nation.getId()); - if (dbNation == null) continue; - DBNation copy = new DBNation(dbNation); - - dbNation.setSpies(nation.getSpies(), false); - if (nation.getEspionage_available() != (dbNation.isEspionageAvailable())) { - dbNation.setEspionageFull(!nation.getEspionage_available()); - } - if (nation.getSpy_attacks() != null) { - nation.setSpy_attacks(nation.getSpy_attacks()); - ops.put(dbNation, nation.getSpy_attacks()); - } - } + }); return ops; } diff --git a/src/main/java/link/locutus/discord/db/entities/DBNation.java b/src/main/java/link/locutus/discord/db/entities/DBNation.java index 344c87e6..3a33a469 100644 --- a/src/main/java/link/locutus/discord/db/entities/DBNation.java +++ b/src/main/java/link/locutus/discord/db/entities/DBNation.java @@ -153,25 +153,25 @@ public static DBNation getByUser(User user) { public void processTurnChange(long lastTurn, long turn, Consumer eventConsumer) { if (leaving_vm == turn) { - if (eventConsumer != null) new NationLeaveVacationEvent(this, this).post(); + if (eventConsumer != null) eventConsumer.accept(new NationLeaveVacationEvent(this, this)); } if (beigeTimer == turn) { - if (eventConsumer != null) new NationLeaveBeigeEvent(this, this).post(); + if (eventConsumer != null) eventConsumer.accept(new NationLeaveBeigeEvent(this, this)); } if (colorTimer == turn) { - if (eventConsumer != null) new NationColorTimerEndEvent(this, this).post(); + if (eventConsumer != null) eventConsumer.accept(new NationColorTimerEndEvent(this, this)); } if (warPolicyTimer == turn) { - if (eventConsumer != null) new NationWarPolicyTimerEndEvent(this, this).post(); + if (eventConsumer != null) eventConsumer.accept(new NationWarPolicyTimerEndEvent(this, this)); } if (domesticPolicyTimer == turn) { - if (eventConsumer != null) new NationDomesticPolicyTimerEndEvent(this, this).post(); + if (eventConsumer != null) eventConsumer.accept(new NationDomesticPolicyTimerEndEvent(this, this)); } if (cityTimer == turn) { - if (eventConsumer != null) new NationCityTimerEndEvent(this, this).post(); + if (eventConsumer != null) eventConsumer.accept(new NationCityTimerEndEvent(this, this)); } if (projectTimer == turn) { - if (eventConsumer != null) new NationProjectTimerEndEvent(this, this).post(); + if (eventConsumer != null) eventConsumer.accept(new NationProjectTimerEndEvent(this, this)); } } @@ -360,7 +360,7 @@ public String register(User user, GuildDB db, boolean isNewRegistration) { if (nation_id == Settings.INSTANCE.NATION_ID) { if (Settings.INSTANCE.ADMIN_USER_ID != user.getIdLong()) { if (Settings.INSTANCE.ADMIN_USER_ID > 0) { - throw new IllegalArgumentException("Invalid admin user id in `config.yaml`. Tried to register `" + user.getIdLong() + "` but config has is `" + Settings.INSTANCE.ADMIN_USER_ID + "`"); + throw new IllegalArgumentException("Invalid admin user id in `config.yaml`. Tried to register `" + user.getIdLong() + "` but config has `" + Settings.INSTANCE.ADMIN_USER_ID + "`"); } Settings.INSTANCE.ADMIN_USER_ID = user.getIdLong(); Settings.INSTANCE.save(Settings.INSTANCE.getDefaultFile()); @@ -1024,7 +1024,7 @@ public Auth getAuth(boolean throwError) { if (this.auth != null) return auth; synchronized (this) { if (auth == null) { - if (this.nation_id == Settings.INSTANCE.NATION_ID) { + if (this.nation_id == Locutus.loader().getNationId()) { if (!Settings.INSTANCE.USERNAME.isEmpty() && !Settings.INSTANCE.PASSWORD.isEmpty()) { return auth = new Auth(nation_id, Settings.INSTANCE.USERNAME, Settings.INSTANCE.PASSWORD); } @@ -1395,7 +1395,7 @@ public boolean updateNationInfo(DBNation copyOriginal, com.politicsandwar.graphq } } if (nation.getSpies() != null) { - this.setSpies(nation.getSpies(), false); + this.setSpies(nation.getSpies(), eventConsumer); if (copyOriginal != null && copyOriginal.getSpies() != (nation.getSpies())) { if (eventConsumer != null) eventConsumer.accept(new NationChangeUnitEvent(copyOriginal, this, MilitaryUnit.SPIES)); dirty = true; @@ -1728,15 +1728,13 @@ public int getSpies() { return Math.max(spies, 0); } - public void setSpies(int spies, boolean events) { + public void setSpies(int spies, Consumer eventConsumer) { getCache().processUnitChange(this, MilitaryUnit.SPIES, this.spies, spies); - if (events && this.spies != spies) { + if (eventConsumer != null && this.spies != spies) { DBNation copyOriginal = new DBNation(this); this.spies = spies; - Locutus.imp().getNationDB().saveNation(this); - - new NationChangeUnitEvent(copyOriginal, this, MilitaryUnit.SPIES).post(); + eventConsumer.accept(new NationChangeUnitEvent(copyOriginal, this, MilitaryUnit.SPIES)); } this.spies = spies; } @@ -2514,7 +2512,7 @@ public String commend(boolean isCommend) throws IOException { } else { post.put("action", "denouncement"); } - post.put("account_id", Settings.INSTANCE.NATION_ID + ""); + post.put("account_id", Locutus.loader().getNationId() + ""); post.put("target_id", getNation_id() + ""); post.put("api_key", key.getKey()); Locutus.imp().getRootAuth().readStringFromURL(PagePriority.COMMEND, url, post); @@ -3121,7 +3119,7 @@ public void setUnits(MilitaryUnit unit, int amt) { setNukes(amt); break; case SPIES: - setSpies(amt, false); + setSpies(amt, null); break; default: throw new UnsupportedOperationException("Unit type not implemented"); @@ -3314,7 +3312,7 @@ public Map getCityMap(boolean updateIfOutdated, boolean updat if (updateIfOutdated && estimateScore() != this.score) force = true; if (force) { System.out.println("Fetch cities for " + getNation() + " | " + getNation_id()); - Locutus.imp().getNationDB().updateCitiesOfNations(Collections.singleton(nation_id), true,true, Event::post); + Locutus.imp().runEventsAsync(events -> Locutus.imp().getNationDB().updateCitiesOfNations(Collections.singleton(nation_id), true,true, events)); cityObj = _getCitiesV3(); } } @@ -4652,7 +4650,7 @@ public double maxCityInfra() { } public JsonObject sendMail(ApiKeyPool pool, String subject, String message, boolean priority) throws IOException { - if (pool.size() == 1 && pool.getNextApiKey().getKey().equalsIgnoreCase(Settings.INSTANCE.API_KEY_PRIMARY)) { + if (pool.size() == 1 && pool.getNextApiKey().getKey().equalsIgnoreCase(Locutus.loader().getApiKey())) { Auth auth = Locutus.imp().getRootAuth(); if (auth != null) { String result = new MailTask(auth, priority, this, subject, message, null).call(); diff --git a/src/main/java/link/locutus/discord/db/guild/GuildKey.java b/src/main/java/link/locutus/discord/db/guild/GuildKey.java index f33a1b95..9d934b6f 100644 --- a/src/main/java/link/locutus/discord/db/guild/GuildKey.java +++ b/src/main/java/link/locutus/discord/db/guild/GuildKey.java @@ -127,7 +127,7 @@ public Set validate(GuildDB db, User user, Set aaIds) { DBAlliance alliance = DBAlliance.getOrCreate(aaId); GuildDB otherDb = alliance.getGuildDB(); Member owner = db.getGuild().getOwner(); - if (user == null || user.getIdLong() != Settings.INSTANCE.ADMIN_USER_ID) { + if (user == null || user.getIdLong() != Locutus.loader().getAdminUserId()) { DBNation ownerNation = owner != null ? DiscordUtil.getNation(owner.getUser()) : null; if (ownerNation == null || ownerNation.getAlliance_id() != aaId || ownerNation.getPosition() < Rank.LEADER.id) { Set inviteCodes = new HashSet<>(); diff --git a/src/main/java/link/locutus/discord/db/guild/GuildSetting.java b/src/main/java/link/locutus/discord/db/guild/GuildSetting.java index 950f2c7d..51c92303 100644 --- a/src/main/java/link/locutus/discord/db/guild/GuildSetting.java +++ b/src/main/java/link/locutus/discord/db/guild/GuildSetting.java @@ -500,7 +500,7 @@ private void checkRegisteredOwnerOrActiveAlliance(GuildDB db) { } Member owner = db.getGuild().getOwner(); - if (owner != null && owner.getIdLong() != Settings.INSTANCE.ADMIN_USER_ID) { + if (owner != null && owner.getIdLong() != Locutus.loader().getAdminUserId()) { DBNation ownerNation = DiscordUtil.getNation(owner.getUser()); if (ownerNation == null) { throw new IllegalArgumentException("The owner of this server (" + owner.getEffectiveName() + ") is not registered with the bot (see: " + CM.register.cmd.toSlashMention() + ")"); @@ -539,7 +539,7 @@ public String delete(GuildDB db, User user) { public T allowedAndValidate(GuildDB db, User user, T value) { DBNation nation = DiscordUtil.getNation(user); - if (nation == null && user.getIdLong() != Settings.INSTANCE.ADMIN_USER_ID) { + if (nation == null && user.getIdLong() != Locutus.loader().getAdminUserId()) { throw new IllegalArgumentException("You are not registered with the bot (see: " + CM.register.cmd.toSlashMention() + ")"); } if (!allowed(db, true)) { diff --git a/src/main/java/link/locutus/discord/db/guild/SendInternalTask.java b/src/main/java/link/locutus/discord/db/guild/SendInternalTask.java index 14c33f11..22b9a60c 100644 --- a/src/main/java/link/locutus/discord/db/guild/SendInternalTask.java +++ b/src/main/java/link/locutus/discord/db/guild/SendInternalTask.java @@ -1,6 +1,7 @@ package link.locutus.discord.db.guild; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; +import link.locutus.discord.Locutus; import link.locutus.discord.apiv1.enums.Rank; import link.locutus.discord.apiv1.enums.ResourceType; import link.locutus.discord.commands.manager.v2.binding.annotation.Me; @@ -53,7 +54,7 @@ public class SendInternalTask { private final OffshoreInstance receiverOffshore; public SendInternalTask(@Me User banker, @Me DBNation bankerNation, GuildDB senderDB, DBAlliance senderAlliance, DBNation senderNation, GuildDB receiverDB, DBAlliance receiverAlliance, DBNation receiverNation, double[] amount) throws IOException { - if (OffshoreInstance.DISABLE_TRANSFERS && banker.getIdLong() != Settings.INSTANCE.ADMIN_USER_ID) throw new IllegalArgumentException("Error: Maintenance"); + if (OffshoreInstance.DISABLE_TRANSFERS && banker.getIdLong() != Locutus.loader().getAdminUserId()) throw new IllegalArgumentException("Error: Maintenance"); checkNotNull(bankerNation, "No banker specified. Register with " + CM.register.cmd.toSlashMention()); checkArgsNotNull(senderDB, senderAlliance, senderNation, receiverDB, receiverAlliance, receiverNation); checkNonNegative(amount); diff --git a/src/main/java/link/locutus/discord/pnw/AllianceList.java b/src/main/java/link/locutus/discord/pnw/AllianceList.java index 764e0fb5..354215ea 100644 --- a/src/main/java/link/locutus/discord/pnw/AllianceList.java +++ b/src/main/java/link/locutus/discord/pnw/AllianceList.java @@ -165,8 +165,8 @@ public Map> calcu Map> result = new LinkedHashMap<>(); if (force) { Set nationIds = nations.stream().map(DBNation::getId).collect(Collectors.toSet()); - System.out.println("Aa list update cities for disburse"); - Locutus.imp().getNationDB().updateCitiesOfNations(nationIds, true, true, Event::post); + Locutus.imp().runEventsAsync(events -> + Locutus.imp().getNationDB().updateCitiesOfNations(nationIds, true, true, events)); } for (DBAlliance alliance : getAlliances()) { Set nationsInAA = nations.stream().filter(f -> f.getAlliance_id() == alliance.getAlliance_id()).collect(Collectors.toSet()); @@ -270,8 +270,8 @@ public Map getStockpile() throws IOException { public void updateCities() { Set nationIds = getNations(false, 0, true).stream().map(f -> f.getId()).collect(Collectors.toSet()); - System.out.println("Aa list update cities"); - Locutus.imp().getNationDB().updateCitiesOfNations(nationIds, true, true, Event::post); + Locutus.imp().runEventsAsync(events -> + Locutus.imp().getNationDB().updateCitiesOfNations(nationIds, true, true, events)); } public Set getPositions() { diff --git a/src/main/java/link/locutus/discord/user/Roles.java b/src/main/java/link/locutus/discord/user/Roles.java index 4cc08115..ce37fd84 100644 --- a/src/main/java/link/locutus/discord/user/Roles.java +++ b/src/main/java/link/locutus/discord/user/Roles.java @@ -297,7 +297,7 @@ public Role toRole(GuildDB db) { } public boolean hasOnRoot(User user) { - if (user.getIdLong() == Settings.INSTANCE.ADMIN_USER_ID) return true; + if (user.getIdLong() == Locutus.loader().getAdminUserId()) return true; if (Locutus.imp().getServer() == null) { return false; } @@ -322,8 +322,8 @@ public boolean has(Member member, int alliance) { public boolean has(Member member) { if (member == null) return false; - if (member.getIdLong() == Settings.INSTANCE.APPLICATION_ID) return true; - if (member.getIdLong() == Settings.INSTANCE.ADMIN_USER_ID) return true; + if (member.getIdLong() == Locutus.loader().getAdminUserId()) return true; + if (member.getIdLong() == Locutus.loader().getAdminUserId()) return true; if (member.isOwner()) return true; Role role = toRole(member.getGuild()); @@ -354,7 +354,7 @@ public static Roles parse(String role) { public boolean has(User user, Guild server) { if (user == null) return false; if (user.getIdLong() == Settings.INSTANCE.APPLICATION_ID) return true; - if (user.getIdLong() == Settings.INSTANCE.ADMIN_USER_ID) return true; + if (user.getIdLong() == Locutus.loader().getAdminUserId()) return true; if (server == null) return false; if (!server.isMember(user)) { return false; diff --git a/src/main/java/link/locutus/discord/util/SpyCount.java b/src/main/java/link/locutus/discord/util/SpyCount.java index 16ccb4af..3957907b 100644 --- a/src/main/java/link/locutus/discord/util/SpyCount.java +++ b/src/main/java/link/locutus/discord/util/SpyCount.java @@ -6,6 +6,7 @@ import link.locutus.discord.config.Settings; import link.locutus.discord.db.entities.LootEntry; import link.locutus.discord.db.entities.NationMeta; +import link.locutus.discord.event.Event; import link.locutus.discord.event.game.SpyReportEvent; import link.locutus.discord.db.entities.DBNation; import link.locutus.discord.apiv1.enums.MilitaryUnit; @@ -207,7 +208,7 @@ else if (enemySpiesMin < 0) { result = enemySpiesMin > 2 ? (int) Math.ceil(enemySpiesMin) : (int) enemySpiesMin; } if (current != result) { - nation.setSpies(result, true); + nation.setSpies(result, Event::post); } nation.setMeta(NationMeta.UPDATE_SPIES, TimeUtil.getTurn()); return result; @@ -410,7 +411,7 @@ public static int binarySearchSpies(PagePriority priority, int id, Operation opt public static boolean checkSpiesGreater(PagePriority priority, int id, Operation optype, int safety, int spies) throws IOException { String url = "" + Settings.INSTANCE.PNW_URL() + "/war/espionage_get_odds.php?id1=%s&id2=%s&id3=%s&id4=%s&id5=%s"; - url = String.format(url, Settings.INSTANCE.NATION_ID, id, optype.ordinal(), safety, spies); + url = String.format(url, Locutus.loader().getNationId(), id, optype.ordinal(), safety, spies); String result = FileUtil.readStringFromURL(priority, url).trim(); return result.startsWith("Greater"); } diff --git a/src/main/java/link/locutus/discord/util/StringMan.java b/src/main/java/link/locutus/discord/util/StringMan.java index 0cfac333..0fe54c5f 100644 --- a/src/main/java/link/locutus/discord/util/StringMan.java +++ b/src/main/java/link/locutus/discord/util/StringMan.java @@ -903,18 +903,23 @@ public static T parseUpper(Class emum, String input) { throw new IllegalArgumentException(e.getMessage() + ". Valid options are: " + StringMan.getString(emum.getEnumConstants())); } } - public static > List> autocompleteCommaEnum(Class type, String input, int maxResults) { + public static > List> autocompleteCommaEnum(Class type, String input, int maxResults) { Function parse = f -> parseUpper(type, f); return autocompleteCommaEnum(type, input, parse, maxResults); } public static List> autocompleteCommaEnum(Class type, String input, Function parse, int maxResults) { - List options = Arrays.asList(type.getEnumConstants()); + List options = new ArrayList<>(Arrays.asList(type.getEnumConstants())); Function keyFunc = T::name; Function valueFunc = keyFunc; + Function parent = parse; return autocompleteComma(input, options, parse, keyFunc, valueFunc, maxResults); } + public static List autocompleteComma(String input, List options, int maxResults) { + return autocompleteComma(input, options, f -> f, f -> f, f -> f, maxResults).stream().map(f -> f.getKey()).toList(); + } + public static List> autocompleteComma(String input, List options, Function parse, Function keyFunc, Function valueFunc, int maxResults) { List optionsOriginal = options; diff --git a/src/main/java/link/locutus/discord/util/offshore/OffshoreInstance.java b/src/main/java/link/locutus/discord/util/offshore/OffshoreInstance.java index 34950aea..bc1af4d4 100644 --- a/src/main/java/link/locutus/discord/util/offshore/OffshoreInstance.java +++ b/src/main/java/link/locutus/discord/util/offshore/OffshoreInstance.java @@ -1111,7 +1111,7 @@ public TransferResult transferFromAllianceDeposits(DBNation banker, GuildDB send return new TransferResult(TransferStatus.NOTHING_WITHDRAWN, receiver, amount, note).addMessage("You did not withdraw anything."); } - if (DISABLE_TRANSFERS && (banker == null || banker.getNation_id() != Settings.INSTANCE.NATION_ID)) { + if (DISABLE_TRANSFERS && (banker == null || banker.getNation_id() != Locutus.loader().getNationId())) { // return Map.entry(TransferStatus.AUTHORIZATION, "Error: Maintenance. Transfers are currently disabled"); return new TransferResult(TransferStatus.AUTHORIZATION, receiver, amount, note).addMessage("Error: Maintenance. Transfers are currently disabled"); } @@ -1281,7 +1281,7 @@ public TransferResult transferFromAllianceDeposits(DBNation banker, GuildDB send case CONFIRMATION: default: case OTHER: - log(senderDB, banker, receiver, "Unknown result: " + result + " | <@" + Settings.INSTANCE.ADMIN_USER_ID + ">"); + log(senderDB, banker, receiver, "Unknown result: " + result + " | <@" + Locutus.loader().getAdminUserId() + ">"); case SUCCESS: case SENT_TO_ALLIANCE_BANK: { { @@ -1321,7 +1321,7 @@ public TransferResult transferFromAllianceDeposits(DBNation banker, GuildDB send NationOrAllianceOrGuild account = entry.getKey(); body.append("\n- `!addbalance " + account.getTypePrefix() + ":" + account.getId() + " " + ResourceType.resourcesToString(entry.getValue()) + " #deposit"); } - body.append("\n<@" + Settings.INSTANCE.ADMIN_USER_ID + ">"); + body.append("\n<@" + Locutus.loader().getAdminUserId() + ">"); log(senderDB, banker, receiver, title + ": " + body.toString()); } } @@ -1572,7 +1572,7 @@ public TransferResult transferUnsafe(Auth auth, NationOrAlliance receiver, Map updateChannelMessages() { public void accept(List messages, Throwable throwable) { if (messages == null) { throwable.printStackTrace(); - AlertUtil.error("Cannot fetch message", StringMan.stacktraceToString(throwable) + "<@" + Settings.INSTANCE.ADMIN_USER_ID + ">"); + AlertUtil.error("Cannot fetch message", StringMan.stacktraceToString(throwable) + "<@" + Locutus.loader().getAdminUserId() + ">"); db.updateInterviewMessageDate(channelId); return; } @@ -526,7 +526,7 @@ private Member getOverride(List overrides) { Member member = null; for (PermissionOverride override : overrides) { if (override.getMember() != null) { - if (override.getMember().getIdLong() == Settings.INSTANCE.ADMIN_USER_ID) continue; + if (override.getMember().getIdLong() == Locutus.loader().getAdminUserId()) continue; if (member != null) { return null; } diff --git a/src/main/java/link/locutus/discord/util/update/LeavingBeigeAlert.java b/src/main/java/link/locutus/discord/util/update/LeavingBeigeAlert.java index 1517be96..a3e72794 100644 --- a/src/main/java/link/locutus/discord/util/update/LeavingBeigeAlert.java +++ b/src/main/java/link/locutus/discord/util/update/LeavingBeigeAlert.java @@ -154,7 +154,7 @@ public static boolean testBeigeAlertAuto(GuildDB db, Member member, Role beigeAl NationMeta.BeigeAlertRequiredStatus requiredStatus = attacker.getBeigeRequiredStatus(NationMeta.BeigeAlertRequiredStatus.ONLINE); - if ((attacker.active_m() <= 15 || requiredStatus.getApplies().test(member) || attacker.getNation_id() == Settings.INSTANCE.NATION_ID)) { + if ((attacker.active_m() <= 15 || requiredStatus.getApplies().test(member) || attacker.getNation_id() == Locutus.loader().getNationId())) { NationMeta.BeigeAlertMode mode = attacker.getBeigeAlertMode(NationMeta.BeigeAlertMode.NO_ALERTS); if (mode == NationMeta.BeigeAlertMode.NO_ALERTS) { if (throwError) throw new IllegalArgumentException("You have disabled beige alerts. See " + CM.alerts.beige.beigeAlertMode.cmd.toSlashMention()); diff --git a/src/main/java/link/locutus/discord/util/update/WarUpdateProcessor.java b/src/main/java/link/locutus/discord/util/update/WarUpdateProcessor.java index 5a09e487..b9fdc881 100644 --- a/src/main/java/link/locutus/discord/util/update/WarUpdateProcessor.java +++ b/src/main/java/link/locutus/discord/util/update/WarUpdateProcessor.java @@ -927,7 +927,7 @@ public static void processLegacy(DBWar previous, DBWar current) throws IOExcepti } } - if (current.getDefender_id() == Settings.INSTANCE.NATION_ID) { + if (current.getDefender_id() == Locutus.loader().getNationId()) { String body = "" + Settings.INSTANCE.PNW_URL() + "/alliance/id=" + Settings.INSTANCE.ALLIANCE_ID() + "&display=bank"; AlertUtil.displayTray("" + Settings.INSTANCE.PNW_URL() + "/nation/war/timeline/war=" + current.warId, body); if (Desktop.isDesktopSupported() && Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) { diff --git a/src/main/java/link/locutus/discord/web/commands/binding/AuthBindings.java b/src/main/java/link/locutus/discord/web/commands/binding/AuthBindings.java index 591cd231..07f4a061 100644 --- a/src/main/java/link/locutus/discord/web/commands/binding/AuthBindings.java +++ b/src/main/java/link/locutus/discord/web/commands/binding/AuthBindings.java @@ -490,7 +490,7 @@ public static Auth getAuth(WebStore ws, Context context, boolean allowRedirect, String body = "DO NOT SHARE THIS URL OR OPEN IT IF YOU DID NOT REQUEST IT:
" + MarkupUtil.htmlUrl(WebRoot.REDIRECT + " | Verify Login", authUrl); - ApiKeyPool pool = ApiKeyPool.create(Settings.INSTANCE.NATION_ID, Settings.INSTANCE.API_KEY_PRIMARY); + ApiKeyPool pool = ApiKeyPool.create(Locutus.loader().getNationId(), Locutus.loader().getApiKey()); JsonObject result = nation.sendMail(pool, title, body, true); JsonElement success = result.get("success"); if (success != null && success.getAsBoolean()) { diff --git a/src/main/jte/footer.jte b/src/main/jte/footer.jte index 2a2b92e0..186da015 100644 --- a/src/main/jte/footer.jte +++ b/src/main/jte/footer.jte @@ -1,5 +1,6 @@ @import link.locutus.discord.commands.manager.v2.binding.WebStore @import link.locutus.discord.config.Settings +@import link.locutus.discord.Locutus