From 2ecc0f28c5472d16d1805cf7378794ee995c7a57 Mon Sep 17 00:00:00 2001 From: Melledy <121644117+Melledy@users.noreply.github.com> Date: Sat, 8 Nov 2025 05:49:20 -0800 Subject: [PATCH] Implement daily reset --- src/main/java/emu/nebula/Config.java | 1 + src/main/java/emu/nebula/GameConstants.java | 4 ++ .../java/emu/nebula/game/GameContext.java | 70 ++++++++++++++----- .../java/emu/nebula/game/player/Player.java | 28 +++++++- 4 files changed, 84 insertions(+), 19 deletions(-) diff --git a/src/main/java/emu/nebula/Config.java b/src/main/java/emu/nebula/Config.java index 561b644..9464322 100644 --- a/src/main/java/emu/nebula/Config.java +++ b/src/main/java/emu/nebula/Config.java @@ -98,6 +98,7 @@ public class Config { public boolean autoCreateAccount = true; public boolean skipIntro = false; public boolean unlockInstances = true; + public int dailyResetHour = 0; } @Getter diff --git a/src/main/java/emu/nebula/GameConstants.java b/src/main/java/emu/nebula/GameConstants.java index b24e6c5..e2c43ee 100644 --- a/src/main/java/emu/nebula/GameConstants.java +++ b/src/main/java/emu/nebula/GameConstants.java @@ -1,9 +1,13 @@ package emu.nebula; +import java.time.ZoneId; + public class GameConstants { public static final int DATA_VERSION = 31; public static final String VERSION = "1.0.0." + DATA_VERSION; + public static final ZoneId UTC_ZONE = ZoneId.of("UTC"); + public static final String PROTO_BASE_TYPE_URL = "type.googleapis.com/proto."; public static final int INTRO_GUIDE_ID = 1; diff --git a/src/main/java/emu/nebula/game/GameContext.java b/src/main/java/emu/nebula/game/GameContext.java index 5e14d40..86c1a2e 100644 --- a/src/main/java/emu/nebula/game/GameContext.java +++ b/src/main/java/emu/nebula/game/GameContext.java @@ -1,35 +1,46 @@ package emu.nebula.game; -import java.util.Timer; -import java.util.TimerTask; +import java.time.Instant; +import java.time.LocalDate; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import emu.nebula.GameConstants; +import emu.nebula.Nebula; import emu.nebula.game.gacha.GachaModule; import emu.nebula.game.player.PlayerModule; import emu.nebula.net.GameSession; + import it.unimi.dsi.fastutil.objects.Object2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; + import lombok.Getter; @Getter -public class GameContext { +public class GameContext implements Runnable { private final Object2ObjectMap sessions; // Modules private final PlayerModule playerModule; private final GachaModule gachaModule; - // Cleanup thread - private final Timer cleanupTimer; + // Game loop + private final ScheduledExecutorService scheduler; + + // Daily + private long epochDays; public GameContext() { this.sessions = new Object2ObjectOpenHashMap<>(); + // Setup game modules this.playerModule = new PlayerModule(this); this.gachaModule = new GachaModule(this); - this.cleanupTimer = new Timer(); - this.cleanupTimer.scheduleAtFixedRate(new CleanupTask(this), 0, TimeUnit.SECONDS.toMillis(60)); + // Run game loop + this.scheduler = Executors.newScheduledThreadPool(1); + this.scheduler.scheduleAtFixedRate(this, 0, 1, TimeUnit.SECONDS); } public synchronized GameSession getSessionByToken(String token) { @@ -74,18 +85,41 @@ public class GameContext { } } } - - @Getter - public static class CleanupTask extends TimerTask { - private GameContext gameContext; - - public CleanupTask(GameContext gameContext) { - this.gameContext = gameContext; - } - @Override - public void run() { - this.getGameContext().cleanupInactiveSessions(); + @Override + public void run() { + // Check daily - Update epoch days + long offset = Nebula.getConfig().getServerOptions().getDailyResetHour() * -3600; + var instant = Instant.now().plusSeconds(offset); + var date = LocalDate.ofInstant(instant, GameConstants.UTC_ZONE); + + long lastEpochDays = this.epochDays; + this.epochDays = date.toEpochDay(); + + // Check if the day was changed + if (this.epochDays > lastEpochDays) { + this.resetDailies(); + } + + // Clean up any inactive sessions + this.cleanupInactiveSessions(); + } + + /** + * Resets the daily missions/etc for all players on the server + */ + public synchronized void resetDailies() { + for (var session : this.getSessions().values()) { + // Cache + var player = session.getPlayer(); + + // Skip if session doesn't have a player + if (player == null) { + continue; + } + + // + player.checkResetDailies(); } } } diff --git a/src/main/java/emu/nebula/game/player/Player.java b/src/main/java/emu/nebula/game/player/Player.java index 6a018c1..4d86aec 100644 --- a/src/main/java/emu/nebula/game/player/Player.java +++ b/src/main/java/emu/nebula/game/player/Player.java @@ -64,6 +64,7 @@ public class Player implements GameDatabaseObject { private int energy; private long energyLastUpdate; + private long lastEpochDay; private long createTime; // Managers @@ -430,6 +431,27 @@ public class Player implements GameDatabaseObject { // Empty } + // Dailies + + public void checkResetDailies() { + // Sanity check to make sure daily reset isnt being triggered wrong + if (Nebula.getGameContext().getEpochDays() <= this.getLastEpochDay()) { + return; + } + + // Reset dailies + this.resetDailies(); + + // Update last epoch day + this.lastEpochDay = Nebula.getGameContext().getEpochDays(); + Nebula.getGameDatabase().update(this, this.getUid(), "lastEpochDay", this.lastEpochDay); + } + + public void resetDailies() { + // Reset daily quests + this.getQuestManager().resetDailyQuests(); + } + // Login private T loadManagerFromDatabase(Class cls) { @@ -471,6 +493,10 @@ public class Player implements GameDatabaseObject { } public void onLogin() { + // See if we need to reset dailies + this.checkResetDailies(); + + // Trigger quest login this.getQuestManager().triggerQuest(QuestCondType.LoginTotal, 1); } @@ -644,5 +670,5 @@ public class Player implements GameDatabaseObject { return proto; } - + }