Implement daily check in

This commit is contained in:
Melledy
2025-12-07 20:00:22 -08:00
parent 05e74f4d12
commit 90f4be862f
5 changed files with 145 additions and 40 deletions

View File

@@ -18,7 +18,7 @@ import lombok.Getter;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class GameData { public class GameData {
// Characters // ===== Characters =====
@Getter private static DataTable<CharacterDef> CharacterDataTable = new DataTable<>(); @Getter private static DataTable<CharacterDef> CharacterDataTable = new DataTable<>();
@Getter private static DataTable<CharacterAdvanceDef> CharacterAdvanceDataTable = new DataTable<>(); @Getter private static DataTable<CharacterAdvanceDef> CharacterAdvanceDataTable = new DataTable<>();
@Getter private static DataTable<CharacterSkillUpgradeDef> CharacterSkillUpgradeDataTable = new DataTable<>(); @Getter private static DataTable<CharacterSkillUpgradeDef> CharacterSkillUpgradeDataTable = new DataTable<>();
@@ -28,40 +28,43 @@ public class GameData {
@Getter private static DataTable<TalentGroupDef> TalentGroupDataTable = new DataTable<>(); @Getter private static DataTable<TalentGroupDef> TalentGroupDataTable = new DataTable<>();
@Getter private static DataTable<TalentDef> TalentDataTable = new DataTable<>(); @Getter private static DataTable<TalentDef> TalentDataTable = new DataTable<>();
// Character emblems // Characters: Emblems
@Getter private static DataTable<CharGemDef> CharGemDataTable = new DataTable<>(); @Getter private static DataTable<CharGemDef> CharGemDataTable = new DataTable<>();
@Getter private static DataTable<CharGemSlotControlDef> CharGemSlotControlDataTable = new DataTable<>(); @Getter private static DataTable<CharGemSlotControlDef> CharGemSlotControlDataTable = new DataTable<>();
@Getter private static DataTable<CharGemAttrGroupDef> CharGemAttrGroupDataTable = new DataTable<>(); @Getter private static DataTable<CharGemAttrGroupDef> CharGemAttrGroupDataTable = new DataTable<>();
@Getter private static DataTable<CharGemAttrValueDef> CharGemAttrValueDataTable = new DataTable<>(); @Getter private static DataTable<CharGemAttrValueDef> CharGemAttrValueDataTable = new DataTable<>();
// Character affinity // Characters: Affinity
@Getter private static DataTable<AffinityLevelDef> AffinityLevelDataTable = new DataTable<>(); @Getter private static DataTable<AffinityLevelDef> AffinityLevelDataTable = new DataTable<>();
@Getter private static DataTable<AffinityGiftDef> AffinityGiftDataTable = new DataTable<>(); @Getter private static DataTable<AffinityGiftDef> AffinityGiftDataTable = new DataTable<>();
@Getter private static DataTable<PlotDef> PlotDataTable = new DataTable<>(); @Getter private static DataTable<PlotDef> PlotDataTable = new DataTable<>();
// Characters: Phone
@Getter private static DataTable<ChatDef> ChatDataTable = new DataTable<>(); @Getter private static DataTable<ChatDef> ChatDataTable = new DataTable<>();
// Characters: Dating
@Getter private static DataTable<DatingLandmarkDef> DatingLandmarkDataTable = new DataTable<>(); @Getter private static DataTable<DatingLandmarkDef> DatingLandmarkDataTable = new DataTable<>();
@Getter private static DataTable<DatingLandmarkEventDef> DatingLandmarkEventDataTable = new DataTable<>(); @Getter private static DataTable<DatingLandmarkEventDef> DatingLandmarkEventDataTable = new DataTable<>();
@Getter private static DataTable<DatingCharacterEventDef> DatingCharacterEventDataTable = new DataTable<>(); @Getter private static DataTable<DatingCharacterEventDef> DatingCharacterEventDataTable = new DataTable<>();
// Discs // ===== Discs =====
@Getter private static DataTable<DiscDef> DiscDataTable = new DataTable<>(); @Getter private static DataTable<DiscDef> DiscDataTable = new DataTable<>();
@Getter private static DataTable<DiscStrengthenDef> DiscStrengthenDataTable = new DataTable<>(); @Getter private static DataTable<DiscStrengthenDef> DiscStrengthenDataTable = new DataTable<>();
@Getter private static DataTable<DiscItemExpDef> DiscItemExpDataTable = new DataTable<>(); @Getter private static DataTable<DiscItemExpDef> DiscItemExpDataTable = new DataTable<>();
@Getter private static DataTable<DiscPromoteDef> DiscPromoteDataTable = new DataTable<>(); @Getter private static DataTable<DiscPromoteDef> DiscPromoteDataTable = new DataTable<>();
@Getter private static DataTable<DiscPromoteLimitDef> DiscPromoteLimitDataTable = new DataTable<>(); @Getter private static DataTable<DiscPromoteLimitDef> DiscPromoteLimitDataTable = new DataTable<>();
// Discs: Melody items
@Getter private static DataTable<SecondarySkillDef> SecondarySkillDataTable = new DataTable<>(); @Getter private static DataTable<SecondarySkillDef> SecondarySkillDataTable = new DataTable<>();
// Items // ===== Items =====
@Getter private static DataTable<ItemDef> ItemDataTable = new DataTable<>(); @Getter private static DataTable<ItemDef> ItemDataTable = new DataTable<>();
@Getter private static DataTable<ProductionDef> ProductionDataTable = new DataTable<>(); @Getter private static DataTable<ProductionDef> ProductionDataTable = new DataTable<>();
@Getter private static DataTable<PlayerHeadDef> PlayerHeadDataTable = new DataTable<>(); @Getter private static DataTable<PlayerHeadDef> PlayerHeadDataTable = new DataTable<>();
@Getter private static DataTable<TitleDef> titleDataTable = new DataTable<>(); @Getter private static DataTable<TitleDef> titleDataTable = new DataTable<>();
@Getter private static DataTable<HonorDef> honorDataTable = new DataTable<>(); @Getter private static DataTable<HonorDef> honorDataTable = new DataTable<>();
// Shops // ===== Shops =====
@Getter private static DataTable<MallMonthlyCardDef> MallMonthlyCardDataTable = new DataTable<>(); @Getter private static DataTable<MallMonthlyCardDef> MallMonthlyCardDataTable = new DataTable<>();
@Getter private static DataTable<MallPackageDef> MallPackageDataTable = new DataTable<>(); @Getter private static DataTable<MallPackageDef> MallPackageDataTable = new DataTable<>();
@Getter private static DataTable<MallShopDef> MallShopDataTable = new DataTable<>(); @Getter private static DataTable<MallShopDef> MallShopDataTable = new DataTable<>();
@@ -70,20 +73,38 @@ public class GameData {
@Getter private static DataTable<ResidentShopDef> ResidentShopDataTable = new DataTable<>(); @Getter private static DataTable<ResidentShopDef> ResidentShopDataTable = new DataTable<>();
@Getter private static DataTable<ResidentGoodsDef> ResidentGoodsDataTable = new DataTable<>(); @Getter private static DataTable<ResidentGoodsDef> ResidentGoodsDataTable = new DataTable<>();
// Battle Pass // ===== Battle Pass =====
@Getter private static DataTable<BattlePassDef> BattlePassDataTable = new DataTable<>(); @Getter private static DataTable<BattlePassDef> BattlePassDataTable = new DataTable<>();
@Getter private static DataTable<BattlePassLevelDef> BattlePassLevelDataTable = new DataTable<>(); @Getter private static DataTable<BattlePassLevelDef> BattlePassLevelDataTable = new DataTable<>();
@Getter private static DataTable<BattlePassQuestDef> BattlePassQuestDataTable = new DataTable<>(); @Getter private static DataTable<BattlePassQuestDef> BattlePassQuestDataTable = new DataTable<>();
@Getter private static DataTable<BattlePassRewardDef> BattlePassRewardDataTable = new DataTable<>(); @Getter private static DataTable<BattlePassRewardDef> BattlePassRewardDataTable = new DataTable<>();
// Commissions // ===== Commissions =====
@Getter private static DataTable<AgentDef> AgentDataTable = new DataTable<>(); @Getter private static DataTable<AgentDef> AgentDataTable = new DataTable<>();
// Dictionary // ===== Dictionary =====
@Getter private static DataTable<DictionaryTabDef> DictionaryTabDataTable = new DataTable<>(); @Getter private static DataTable<DictionaryTabDef> DictionaryTabDataTable = new DataTable<>();
@Getter private static DataTable<DictionaryEntryDef> DictionaryEntryDataTable = new DataTable<>(); @Getter private static DataTable<DictionaryEntryDef> DictionaryEntryDataTable = new DataTable<>();
// Instances // ===== Gacha =====
@Getter private static DataTable<GachaDef> GachaDataTable = new DataTable<>();
@Getter private static DataTable<GachaStorageDef> GachaStorageDataTable = new DataTable<>();
// ===== Story =====
@Getter private static DataTable<StoryDef> StoryDataTable = new DataTable<>();
@Getter private static DataTable<StorySetSectionDef> StorySetSectionDataTable = new DataTable<>();
// ===== Daily Quests =====
@Getter private static DataTable<DailyQuestDef> DailyQuestDataTable = new DataTable<>();
@Getter private static DataTable<DailyQuestActiveDef> DailyQuestActiveDataTable = new DataTable<>();
// ===== Achievements =====
@Getter private static DataTable<AchievementDef> AchievementDataTable = new DataTable<>();
// ===== Tutorials =====
@Getter private static DataTable<TutorialLevelDef> TutorialLevelDataTable = new DataTable<>();
// ===== Instances =====
@Getter private static DataTable<DailyInstanceDef> DailyInstanceDataTable = new DataTable<>(); @Getter private static DataTable<DailyInstanceDef> DailyInstanceDataTable = new DataTable<>();
@Getter private static DataTable<DailyInstanceRewardGroupDef> DailyInstanceRewardGroupDataTable = new DataTable<>(); @Getter private static DataTable<DailyInstanceRewardGroupDef> DailyInstanceRewardGroupDataTable = new DataTable<>();
@Getter private static DataTable<RegionBossLevelDef> RegionBossLevelDataTable = new DataTable<>(); @Getter private static DataTable<RegionBossLevelDef> RegionBossLevelDataTable = new DataTable<>();
@@ -91,26 +112,7 @@ public class GameData {
@Getter private static DataTable<CharGemInstanceDef> CharGemInstanceDataTable = new DataTable<>(); @Getter private static DataTable<CharGemInstanceDef> CharGemInstanceDataTable = new DataTable<>();
@Getter private static DataTable<WeekBossLevelDef> WeekBossLevelDataTable = new DataTable<>(); @Getter private static DataTable<WeekBossLevelDef> WeekBossLevelDataTable = new DataTable<>();
@Getter private static DataTable<GachaDef> GachaDataTable = new DataTable<>(); // ===== Star Tower =====
@Getter private static DataTable<GachaStorageDef> GachaStorageDataTable = new DataTable<>();
@Getter private static DataTable<WorldClassDef> WorldClassDataTable = new DataTable<>();
@Getter private static DataTable<GuideGroupDef> GuideGroupDataTable = new DataTable<>();
@Getter private static DataTable<HandbookDef> HandbookDataTable = new DataTable<>();
@Getter private static DataTable<StoryDef> StoryDataTable = new DataTable<>();
@Getter private static DataTable<StorySetSectionDef> StorySetSectionDataTable = new DataTable<>();
// Daily quests
@Getter private static DataTable<DailyQuestDef> DailyQuestDataTable = new DataTable<>();
@Getter private static DataTable<DailyQuestActiveDef> DailyQuestActiveDataTable = new DataTable<>();
// Achievements
@Getter private static DataTable<AchievementDef> AchievementDataTable = new DataTable<>();
// Tutorial
@Getter private static DataTable<TutorialLevelDef> TutorialLevelDataTable = new DataTable<>();
// Star tower
@Getter private static DataTable<StarTowerDef> StarTowerDataTable = new DataTable<>(); @Getter private static DataTable<StarTowerDef> StarTowerDataTable = new DataTable<>();
@Getter private static DataTable<StarTowerStageDef> StarTowerStageDataTable = new DataTable<>(); @Getter private static DataTable<StarTowerStageDef> StarTowerStageDataTable = new DataTable<>();
@Getter private static DataTable<StarTowerGrowthNodeDef> StarTowerGrowthNodeDataTable = new DataTable<>(); @Getter private static DataTable<StarTowerGrowthNodeDef> StarTowerGrowthNodeDataTable = new DataTable<>();
@@ -126,24 +128,31 @@ public class GameData {
@Getter private static DataTable<StarTowerBookFateCardQuestDef> StarTowerBookFateCardQuestDataTable = new DataTable<>(); @Getter private static DataTable<StarTowerBookFateCardQuestDef> StarTowerBookFateCardQuestDataTable = new DataTable<>();
@Getter private static DataTable<StarTowerBookFateCardDef> StarTowerBookFateCardDataTable = new DataTable<>(); @Getter private static DataTable<StarTowerBookFateCardDef> StarTowerBookFateCardDataTable = new DataTable<>();
@Getter private static DataTable<FateCardDef> FateCardDataTable = new DataTable<>(); @Getter private static DataTable<FateCardDef> FateCardDataTable = new DataTable<>();
// Infinity Tower // ===== Infinity Tower =====
@Getter private static DataTable<InfinityTowerLevelDef> InfinityTowerLevelDataTable = new DataTable<>(); @Getter private static DataTable<InfinityTowerLevelDef> InfinityTowerLevelDataTable = new DataTable<>();
// Vampire survivor // ===== Vampire Survivor =====
@Getter private static DataTable<VampireSurvivorDef> VampireSurvivorDataTable = new DataTable<>(); @Getter private static DataTable<VampireSurvivorDef> VampireSurvivorDataTable = new DataTable<>();
@Getter private static DataTable<VampireTalentDef> VampireTalentDataTable = new DataTable<>(); @Getter private static DataTable<VampireTalentDef> VampireTalentDataTable = new DataTable<>();
// Score boss // ===== Score Boss =====
@Getter private static DataTable<ScoreBossControlDef> ScoreBossControlDataTable = new DataTable<>(); @Getter private static DataTable<ScoreBossControlDef> ScoreBossControlDataTable = new DataTable<>();
@Getter private static DataTable<ScoreBossRewardDef> ScoreBossRewardDataTable = new DataTable<>(); @Getter private static DataTable<ScoreBossRewardDef> ScoreBossRewardDataTable = new DataTable<>();
// Activity // ===== Misc =====
@Getter private static DataTable<WorldClassDef> WorldClassDataTable = new DataTable<>();
@Getter private static DataTable<GuideGroupDef> GuideGroupDataTable = new DataTable<>();
@Getter private static DataTable<HandbookDef> HandbookDataTable = new DataTable<>();
@Getter private static DataTable<SignInDef> SignInDataTable = new DataTable<>();
// ===== Activity =====
@Getter private static DataTable<ActivityDef> ActivityDataTable = new DataTable<>(); @Getter private static DataTable<ActivityDef> ActivityDataTable = new DataTable<>();
// Tower defense // Activity: Tower Defense
@Getter private static DataTable<TowerDefenseLevelDef> TowerDefenseLevelDataTable = new DataTable<>(); @Getter private static DataTable<TowerDefenseLevelDef> TowerDefenseLevelDataTable = new DataTable<>();
// Activity: Trials
@Getter private static DataTable<TrialControlDef> TrialControlDataTable = new DataTable<>(); @Getter private static DataTable<TrialControlDef> TrialControlDataTable = new DataTable<>();
@Getter private static DataTable<TrialGroupDef> TrialGroupDataTable = new DataTable<>(); @Getter private static DataTable<TrialGroupDef> TrialGroupDataTable = new DataTable<>();
} }

View File

@@ -0,0 +1,20 @@
package emu.nebula.data.resources;
import emu.nebula.data.BaseDef;
import emu.nebula.data.ResourceType;
import lombok.Getter;
@Getter
@ResourceType(name = "SignIn.json")
public class SignInDef extends BaseDef {
private int Group;
private int Day;
private int ItemId;
private int ItemQty;
@Override
public int getId() {
return (this.Group << 16) + this.Day;
}
}

View File

@@ -37,6 +37,7 @@ public class GameContext implements Runnable {
// Daily // Daily
private long epochDays; private long epochDays;
private int epochWeeks; private int epochWeeks;
private int epochMonths;
public GameContext() { public GameContext() {
this.sessions = new Object2ObjectOpenHashMap<>(); this.sessions = new Object2ObjectOpenHashMap<>();
@@ -105,12 +106,17 @@ public class GameContext implements Runnable {
var instant = Instant.now().plusSeconds(offset); var instant = Instant.now().plusSeconds(offset);
var date = LocalDate.ofInstant(instant, GameConstants.UTC_ZONE); var date = LocalDate.ofInstant(instant, GameConstants.UTC_ZONE);
// Update epoch days
long lastEpochDays = this.epochDays; long lastEpochDays = this.epochDays;
this.epochDays = date.toEpochDay(); this.epochDays = date.toEpochDay();
this.epochWeeks = Utils.getWeeks(this.epochDays);
// Check if the day was changed // Check if the day was changed
if (this.epochDays > lastEpochDays) { if (this.epochDays > lastEpochDays) {
// Update epoch weeks/months
this.epochWeeks = Utils.getWeeks(this.epochDays);
this.epochMonths = Utils.getMonths(this.epochDays);
// Reset dailies for players
this.resetDailies(); this.resetDailies();
} }

View File

@@ -36,6 +36,7 @@ import emu.nebula.game.vampire.VampireSurvivorManager;
import emu.nebula.net.GameSession; import emu.nebula.net.GameSession;
import emu.nebula.net.NetMsgId; import emu.nebula.net.NetMsgId;
import emu.nebula.net.NetMsgPacket; import emu.nebula.net.NetMsgPacket;
import emu.nebula.proto.Notify.SigninRewardUpdate;
import emu.nebula.proto.PlayerData.DictionaryEntry; import emu.nebula.proto.PlayerData.DictionaryEntry;
import emu.nebula.proto.PlayerData.DictionaryTab; import emu.nebula.proto.PlayerData.DictionaryTab;
import emu.nebula.proto.PlayerData.PlayerInfo; import emu.nebula.proto.PlayerData.PlayerInfo;
@@ -85,6 +86,8 @@ public class Player implements GameDatabaseObject {
private int energy; private int energy;
private long energyLastUpdate; private long energyLastUpdate;
private int signInIndex;
private long lastEpochDay; private long lastEpochDay;
private long lastLogin; private long lastLogin;
private long createTime; private long createTime;
@@ -613,6 +616,13 @@ public class Player implements GameDatabaseObject {
public void checkResetDailies() { public void checkResetDailies() {
// Sanity check to make sure daily reset isnt being triggered wrong // Sanity check to make sure daily reset isnt being triggered wrong
if (Nebula.getGameContext().getEpochDays() <= this.getLastEpochDay()) { if (Nebula.getGameContext().getEpochDays() <= this.getLastEpochDay()) {
// Fix sign-in index
// TODO remove later
if (this.getSignInIndex() <= 0) {
this.getSignInRewards(false);
}
// End
return; return;
} }
@@ -621,8 +631,12 @@ public class Player implements GameDatabaseObject {
int curWeek = Utils.getWeeks(this.getLastEpochDay()); int curWeek = Utils.getWeeks(this.getLastEpochDay());
boolean hasWeekChanged = Nebula.getGameContext().getEpochWeeks() > curWeek; boolean hasWeekChanged = Nebula.getGameContext().getEpochWeeks() > curWeek;
// Check if month was changed
int curMonth = Utils.getMonths(this.getLastEpochDay());
boolean hasMonthChanged = Nebula.getGameContext().getEpochMonths() > curMonth;
// Reset dailies // Reset dailies
this.resetDailies(hasWeekChanged); this.resetDailies(hasWeekChanged, hasMonthChanged);
// Trigger quest/achievement login // Trigger quest/achievement login
this.trigger(QuestCondition.LoginTotal, 1); this.trigger(QuestCondition.LoginTotal, 1);
@@ -633,12 +647,47 @@ public class Player implements GameDatabaseObject {
this.getInventory().addItem(GameConstants.WEEKLY_ENTRY_ITEM_ID, 3 - entries); this.getInventory().addItem(GameConstants.WEEKLY_ENTRY_ITEM_ID, 3 - entries);
} }
// Give sign-in rewards
this.getSignInRewards(hasMonthChanged);
// Update last epoch day // Update last epoch day
this.lastEpochDay = Nebula.getGameContext().getEpochDays(); this.lastEpochDay = Nebula.getGameContext().getEpochDays();
Nebula.getGameDatabase().update(this, this.getUid(), "lastEpochDay", this.lastEpochDay); Nebula.getGameDatabase().update(this, this.getUid(), "lastEpochDay", this.lastEpochDay);
} }
private void getSignInRewards(boolean resetMonthly) {
// Check monthly reset
if (resetMonthly) {
this.signInIndex = 0;
}
// Get next sign-in index
int nextSignIn = this.signInIndex + 1;
int group = Utils.getDaysOfMonth(this.getLastEpochDay());
var data = GameData.getSignInDataTable().get((group << 16) + nextSignIn);
if (data == null) {
return;
}
// Add rewards
var change = this.getInventory().addItem(data.getItemId(), data.getItemQty());
// Add package
this.addNextPackage(
NetMsgId.signin_reward_change_notify,
SigninRewardUpdate.newInstance()
.setIndex(nextSignIn)
.setSwitch(resetMonthly)
.setChange(change.toProto())
);
// Update sign-in index
this.signInIndex = nextSignIn;
Nebula.getGameDatabase().update(this, this.getUid(), "signInIndex", this.signInIndex);
}
public void resetDailies(boolean resetWeekly) { public void resetDailies(boolean resetWeekly, boolean resetMonthly) {
// Reset daily quests // Reset daily quests
this.getQuestManager().resetDailyQuests(); this.getQuestManager().resetDailyQuests();
this.getBattlePassManager().getBattlePass().resetDailyQuests(resetWeekly); this.getBattlePassManager().getBattlePass().resetDailyQuests(resetWeekly);
@@ -767,6 +816,7 @@ public class Player implements GameDatabaseObject {
public PlayerInfo toProto() { public PlayerInfo toProto() {
PlayerInfo proto = PlayerInfo.newInstance() PlayerInfo proto = PlayerInfo.newInstance()
.setServerTs(Nebula.getCurrentTime()) .setServerTs(Nebula.getCurrentTime())
.setSigninIndex(this.getSignInIndex())
.setDailyShopRewardStatus(this.getQuestManager().hasDailyReward()) .setDailyShopRewardStatus(this.getQuestManager().hasDailyReward())
.setAchievements(new byte[64]); .setAchievements(new byte[64]);

View File

@@ -4,6 +4,9 @@ import java.io.File;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.temporal.ChronoUnit;
import java.util.Base64; import java.util.Base64;
import java.util.List; import java.util.List;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@@ -294,11 +297,28 @@ public class Utils {
} }
/** /**
* Get amount weeks since this epoch day. Each week starts on monday. * Get amount of weeks since this epoch day. Each week starts on monday.
* @param epochDays * @param epochDays
* @return * @return
*/ */
public static int getWeeks(long epochDays) { public static int getWeeks(long epochDays) {
return (int) Math.floor((epochDays + 3) / 7D); return (int) Math.floor((epochDays + 3) / 7D);
} }
/**
* Get amount of months since this epoch day.
* @param epochDays
* @return
*/
public static int getMonths(long epochDays) {
var begin = LocalDate.ofEpochDay(0);
var date = LocalDate.ofEpochDay(epochDays);
return (int) ChronoUnit.MONTHS.between(begin, date);
}
public static int getDaysOfMonth(long epochDays) {
var date = LocalDate.ofEpochDay(epochDays);
var month = YearMonth.of(date.getYear(), date.getMonthValue());
return month.lengthOfMonth();
}
} }