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")
public class GameData {
// Characters
// ===== Characters =====
@Getter private static DataTable<CharacterDef> CharacterDataTable = new DataTable<>();
@Getter private static DataTable<CharacterAdvanceDef> CharacterAdvanceDataTable = 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<TalentDef> TalentDataTable = new DataTable<>();
// Character emblems
// Characters: Emblems
@Getter private static DataTable<CharGemDef> CharGemDataTable = new DataTable<>();
@Getter private static DataTable<CharGemSlotControlDef> CharGemSlotControlDataTable = new DataTable<>();
@Getter private static DataTable<CharGemAttrGroupDef> CharGemAttrGroupDataTable = 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<AffinityGiftDef> AffinityGiftDataTable = new DataTable<>();
@Getter private static DataTable<PlotDef> PlotDataTable = new DataTable<>();
// Characters: Phone
@Getter private static DataTable<ChatDef> ChatDataTable = new DataTable<>();
// Characters: Dating
@Getter private static DataTable<DatingLandmarkDef> DatingLandmarkDataTable = new DataTable<>();
@Getter private static DataTable<DatingLandmarkEventDef> DatingLandmarkEventDataTable = new DataTable<>();
@Getter private static DataTable<DatingCharacterEventDef> DatingCharacterEventDataTable = new DataTable<>();
// Discs
// ===== Discs =====
@Getter private static DataTable<DiscDef> DiscDataTable = new DataTable<>();
@Getter private static DataTable<DiscStrengthenDef> DiscStrengthenDataTable = new DataTable<>();
@Getter private static DataTable<DiscItemExpDef> DiscItemExpDataTable = new DataTable<>();
@Getter private static DataTable<DiscPromoteDef> DiscPromoteDataTable = new DataTable<>();
@Getter private static DataTable<DiscPromoteLimitDef> DiscPromoteLimitDataTable = new DataTable<>();
// Discs: Melody items
@Getter private static DataTable<SecondarySkillDef> SecondarySkillDataTable = new DataTable<>();
// Items
// ===== Items =====
@Getter private static DataTable<ItemDef> ItemDataTable = new DataTable<>();
@Getter private static DataTable<ProductionDef> ProductionDataTable = new DataTable<>();
@Getter private static DataTable<PlayerHeadDef> PlayerHeadDataTable = new DataTable<>();
@Getter private static DataTable<TitleDef> titleDataTable = new DataTable<>();
@Getter private static DataTable<HonorDef> honorDataTable = new DataTable<>();
// Shops
// ===== Shops =====
@Getter private static DataTable<MallMonthlyCardDef> MallMonthlyCardDataTable = new DataTable<>();
@Getter private static DataTable<MallPackageDef> MallPackageDataTable = 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<ResidentGoodsDef> ResidentGoodsDataTable = new DataTable<>();
// Battle Pass
// ===== Battle Pass =====
@Getter private static DataTable<BattlePassDef> BattlePassDataTable = new DataTable<>();
@Getter private static DataTable<BattlePassLevelDef> BattlePassLevelDataTable = new DataTable<>();
@Getter private static DataTable<BattlePassQuestDef> BattlePassQuestDataTable = new DataTable<>();
@Getter private static DataTable<BattlePassRewardDef> BattlePassRewardDataTable = new DataTable<>();
// Commissions
// ===== Commissions =====
@Getter private static DataTable<AgentDef> AgentDataTable = new DataTable<>();
// Dictionary
// ===== Dictionary =====
@Getter private static DataTable<DictionaryTabDef> DictionaryTabDataTable = 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<DailyInstanceRewardGroupDef> DailyInstanceRewardGroupDataTable = 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<WeekBossLevelDef> WeekBossLevelDataTable = new DataTable<>();
@Getter private static DataTable<GachaDef> GachaDataTable = new DataTable<>();
@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
// ===== Star Tower =====
@Getter private static DataTable<StarTowerDef> StarTowerDataTable = new DataTable<>();
@Getter private static DataTable<StarTowerStageDef> StarTowerStageDataTable = 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<StarTowerBookFateCardDef> StarTowerBookFateCardDataTable = new DataTable<>();
@Getter private static DataTable<FateCardDef> FateCardDataTable = new DataTable<>();
// Infinity Tower
// ===== Infinity Tower =====
@Getter private static DataTable<InfinityTowerLevelDef> InfinityTowerLevelDataTable = new DataTable<>();
// Vampire survivor
// ===== Vampire Survivor =====
@Getter private static DataTable<VampireSurvivorDef> VampireSurvivorDataTable = 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<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<>();
// Tower defense
// Activity: Tower Defense
@Getter private static DataTable<TowerDefenseLevelDef> TowerDefenseLevelDataTable = new DataTable<>();
// Activity: Trials
@Getter private static DataTable<TrialControlDef> TrialControlDataTable = 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
private long epochDays;
private int epochWeeks;
private int epochMonths;
public GameContext() {
this.sessions = new Object2ObjectOpenHashMap<>();
@@ -105,12 +106,17 @@ public class GameContext implements Runnable {
var instant = Instant.now().plusSeconds(offset);
var date = LocalDate.ofInstant(instant, GameConstants.UTC_ZONE);
// Update epoch days
long lastEpochDays = this.epochDays;
this.epochDays = date.toEpochDay();
this.epochWeeks = Utils.getWeeks(this.epochDays);
// Check if the day was changed
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();
}

View File

@@ -36,6 +36,7 @@ import emu.nebula.game.vampire.VampireSurvivorManager;
import emu.nebula.net.GameSession;
import emu.nebula.net.NetMsgId;
import emu.nebula.net.NetMsgPacket;
import emu.nebula.proto.Notify.SigninRewardUpdate;
import emu.nebula.proto.PlayerData.DictionaryEntry;
import emu.nebula.proto.PlayerData.DictionaryTab;
import emu.nebula.proto.PlayerData.PlayerInfo;
@@ -85,6 +86,8 @@ public class Player implements GameDatabaseObject {
private int energy;
private long energyLastUpdate;
private int signInIndex;
private long lastEpochDay;
private long lastLogin;
private long createTime;
@@ -613,6 +616,13 @@ public class Player implements GameDatabaseObject {
public void checkResetDailies() {
// Sanity check to make sure daily reset isnt being triggered wrong
if (Nebula.getGameContext().getEpochDays() <= this.getLastEpochDay()) {
// Fix sign-in index
// TODO remove later
if (this.getSignInIndex() <= 0) {
this.getSignInRewards(false);
}
// End
return;
}
@@ -621,8 +631,12 @@ public class Player implements GameDatabaseObject {
int curWeek = Utils.getWeeks(this.getLastEpochDay());
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
this.resetDailies(hasWeekChanged);
this.resetDailies(hasWeekChanged, hasMonthChanged);
// Trigger quest/achievement login
this.trigger(QuestCondition.LoginTotal, 1);
@@ -633,12 +647,47 @@ public class Player implements GameDatabaseObject {
this.getInventory().addItem(GameConstants.WEEKLY_ENTRY_ITEM_ID, 3 - entries);
}
// Give sign-in rewards
this.getSignInRewards(hasMonthChanged);
// Update last epoch day
this.lastEpochDay = Nebula.getGameContext().getEpochDays();
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
this.getQuestManager().resetDailyQuests();
this.getBattlePassManager().getBattlePass().resetDailyQuests(resetWeekly);
@@ -767,6 +816,7 @@ public class Player implements GameDatabaseObject {
public PlayerInfo toProto() {
PlayerInfo proto = PlayerInfo.newInstance()
.setServerTs(Nebula.getCurrentTime())
.setSigninIndex(this.getSignInIndex())
.setDailyShopRewardStatus(this.getQuestManager().hasDailyReward())
.setAchievements(new byte[64]);

View File

@@ -4,6 +4,9 @@ import java.io.File;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.time.LocalDate;
import java.time.YearMonth;
import java.time.temporal.ChronoUnit;
import java.util.Base64;
import java.util.List;
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
* @return
*/
public static int getWeeks(long epochDays) {
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();
}
}