mirror of
https://github.com/Melledy/Nebula.git
synced 2025-12-12 12:24:35 +01:00
Compare commits
9 Commits
005f138599
...
e5ce16d6ea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5ce16d6ea | ||
|
|
b92319b4c5 | ||
|
|
1b0b6873b9 | ||
|
|
f542ea7cb4 | ||
|
|
fa08bcebae | ||
|
|
209ce83fc9 | ||
|
|
8e7ef038ea | ||
|
|
90f4be862f | ||
|
|
05e74f4d12 |
@@ -33,7 +33,7 @@ For any extra support, questions, or discussions, check out our [Discord](https:
|
||||
|
||||
Nebula supports the global PC client by default. If you want to switch regions, you need to change the `region` field in the Nebula config.
|
||||
|
||||
Current supported regions (PC): `GLOBAL`, `KR`, `JP`, `TW`
|
||||
Current supported regions (PC): `GLOBAL`, `KR`, `JP`, `TW`, `CN`
|
||||
|
||||
You may need to change the data version when switching regions. The `customDataVersion` field should match the the data version of your client, which is usually the last number of your client's version string (top left of your login screen). Example: 1.0.0.42 = data version 42.
|
||||
|
||||
@@ -66,7 +66,8 @@ class Handlers
|
||||
".stellasora.global",
|
||||
".stellasora.kr",
|
||||
".stellasora.jp",
|
||||
".stargazer-games.com"
|
||||
".stargazer-games.com",
|
||||
".yostar.cn"
|
||||
];
|
||||
|
||||
static function OnBeforeRequest(oS: Session) {
|
||||
|
||||
@@ -101,14 +101,21 @@ public class Config {
|
||||
|
||||
@Getter
|
||||
public static class ServerOptions {
|
||||
// Default permissions for accounts. By default, all commands are allowed. Reccomended to change if making a public server.
|
||||
public Set<String> defaultPermissions = Set.of("*");
|
||||
// Automatically creates an account when a player logs in for the first time on a new email.
|
||||
public boolean autoCreateAccount = true;
|
||||
// Skips the intro cinematics when starting a new account.
|
||||
public boolean skipIntro = false;
|
||||
// Unlocks all instances (Monolith, Bounty Trials, etc) for players to enter without needing to do the previous levels.
|
||||
public boolean unlockInstances = true;
|
||||
public int sessionTimeout = 600; // How long to wait (in seconds) after the last http request from a session
|
||||
// before removing it from the server
|
||||
// How long to wait (in seconds) after the last http request from a session before removing it from the server.
|
||||
public int sessionTimeout = 300;
|
||||
// The offset hour for when daily quests are refreshed in UTC. Example: "dailyResetHour = 4" means dailies will be refreshed at UTC+4 12:00 AM every day.
|
||||
public int dailyResetHour = 0;
|
||||
public int leaderboardRefreshTime = 60; // Leaderboard refresh time in seconds
|
||||
// Leaderboard for Boss Blitz refresh time in seconds.
|
||||
public int leaderboardRefreshTime = 60;
|
||||
// The welcome mail to send when a player is created. Set to null to disable.
|
||||
public WelcomeMail welcomeMail = new WelcomeMail();
|
||||
}
|
||||
|
||||
@@ -121,6 +128,7 @@ public class Config {
|
||||
public static class LogOptions {
|
||||
public boolean commands = true;
|
||||
public boolean packets = false;
|
||||
public boolean httpDebug = false;
|
||||
}
|
||||
|
||||
@Getter
|
||||
|
||||
@@ -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<>();
|
||||
}
|
||||
40
src/main/java/emu/nebula/data/resources/DropPkgDef.java
Normal file
40
src/main/java/emu/nebula/data/resources/DropPkgDef.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package emu.nebula.data.resources;
|
||||
|
||||
import emu.nebula.data.BaseDef;
|
||||
import emu.nebula.data.ResourceType;
|
||||
import emu.nebula.util.Utils;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ResourceType(name = "DropPkg.json")
|
||||
public class DropPkgDef extends BaseDef {
|
||||
private int PkgId;
|
||||
private int ItemId;
|
||||
|
||||
private static Int2ObjectMap<IntList> PACKAGES = new Int2ObjectOpenHashMap<>();
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return PkgId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
var packageList = PACKAGES.computeIfAbsent(this.PkgId, i -> new IntArrayList());
|
||||
packageList.add(this.ItemId);
|
||||
}
|
||||
|
||||
public static int getRandomDrop(int packageId) {
|
||||
var packageList = PACKAGES.get(packageId);
|
||||
|
||||
if (packageList == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Utils.randomElement(packageList);
|
||||
}
|
||||
}
|
||||
20
src/main/java/emu/nebula/data/resources/SignInDef.java
Normal file
20
src/main/java/emu/nebula/data/resources/SignInDef.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -53,11 +53,45 @@ public class AchievementHelper {
|
||||
}
|
||||
|
||||
private static void fixParams() {
|
||||
// Star Tower TODO
|
||||
addParam(78, 0, 2);
|
||||
addParam(79, 0, 4);
|
||||
// Clear "Misstep On One"
|
||||
addParam(56, 401, 0); // Custom trigger
|
||||
|
||||
// Clear "Currents and Shadows"
|
||||
addParam(57, 102, 0);
|
||||
addParam(58, 103, 0);
|
||||
addParam(59, 104, 0);
|
||||
addParam(60, 105, 0);
|
||||
addParam(61, 106, 0);
|
||||
addParam(62, 107, 0);
|
||||
addParam(63, 108, 0);
|
||||
|
||||
// Clear "Dust and Flames"
|
||||
addParam(64, 202, 0);
|
||||
addParam(65, 203, 0);
|
||||
addParam(66, 204, 0);
|
||||
addParam(67, 205, 0);
|
||||
addParam(68, 206, 0);
|
||||
addParam(69, 207, 0);
|
||||
addParam(70, 208, 0);
|
||||
|
||||
// Clear "Storm and Thunder"
|
||||
addParam(71, 302, 0);
|
||||
addParam(72, 303, 0);
|
||||
addParam(73, 304, 0);
|
||||
addParam(74, 305, 0);
|
||||
addParam(75, 306, 0);
|
||||
addParam(76, 307, 0);
|
||||
addParam(77, 308, 0);
|
||||
|
||||
// First Ascension
|
||||
addParam(498, 0, 1);
|
||||
|
||||
// Monolith Conqueror
|
||||
addParam(78, 2, 0);
|
||||
addParam(79, 4, 0);
|
||||
addParam(80, 6, 0);
|
||||
addParam(81, 7, 0);
|
||||
|
||||
// Money
|
||||
addParam(25, GameConstants.GOLD_ITEM_ID, 0);
|
||||
addParam(26, GameConstants.GOLD_ITEM_ID, 0);
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.util.Map;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Id;
|
||||
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.resources.AchievementDef;
|
||||
@@ -16,8 +17,8 @@ import emu.nebula.game.player.PlayerManager;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.Public.Achievements;
|
||||
import emu.nebula.proto.Public.Events;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import us.hebi.quickbuf.RepeatedInt;
|
||||
|
||||
@Getter
|
||||
@@ -29,8 +30,9 @@ public class AchievementManager extends PlayerManager implements GameDatabaseObj
|
||||
// Achievement data
|
||||
private Map<Integer, GameAchievement> achievements;
|
||||
|
||||
@Setter
|
||||
// Flags
|
||||
private transient boolean queueSave;
|
||||
private transient boolean hasCompleted;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public AchievementManager() {
|
||||
@@ -79,9 +81,6 @@ public class AchievementManager extends PlayerManager implements GameDatabaseObj
|
||||
}
|
||||
|
||||
public synchronized void handleClientEvents(Events events) {
|
||||
//
|
||||
boolean hasCompleted = false;
|
||||
|
||||
// Parse events
|
||||
for (var event : events.getList()) {
|
||||
// Check id
|
||||
@@ -117,23 +116,15 @@ public class AchievementManager extends PlayerManager implements GameDatabaseObj
|
||||
// Update achievement
|
||||
boolean changed = achievement.trigger(true, progress, 0, 0);
|
||||
|
||||
// Only save/update on client if achievement was changed
|
||||
// Sync with client if achievement was changed
|
||||
if (changed) {
|
||||
// Sync
|
||||
this.syncAchievement(achievement);
|
||||
|
||||
// Set save flag
|
||||
this.queueSave = true;
|
||||
|
||||
// Check if achievement was completed
|
||||
if (achievement.isComplete()) {
|
||||
hasCompleted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger update
|
||||
if (hasCompleted) {
|
||||
// Update total achievements
|
||||
if (this.hasCompleted) {
|
||||
this.hasCompleted = false;
|
||||
this.getPlayer().trigger(AchievementCondition.AchievementTotal, this.getCompletedAchievementsCount());
|
||||
}
|
||||
}
|
||||
@@ -166,8 +157,7 @@ public class AchievementManager extends PlayerManager implements GameDatabaseObj
|
||||
|
||||
// Check what type of achievement condition this is
|
||||
boolean isTotal = AchievementHelper.isIncrementalAchievement(condition);
|
||||
boolean hasCompleted = false;
|
||||
|
||||
|
||||
// Parse achievements
|
||||
for (var data : triggerList) {
|
||||
// Get achievement
|
||||
@@ -176,23 +166,41 @@ public class AchievementManager extends PlayerManager implements GameDatabaseObj
|
||||
// Update achievement
|
||||
boolean changed = achievement.trigger(isTotal, progress, param1, param2);
|
||||
|
||||
// Only save/update on client if achievement was changed
|
||||
// Sync with client if achievement was changed
|
||||
if (changed) {
|
||||
// Sync
|
||||
this.syncAchievement(achievement);
|
||||
|
||||
// Set save flag
|
||||
this.queueSave = true;
|
||||
|
||||
// Check if achievement was completed
|
||||
if (achievement.isComplete()) {
|
||||
hasCompleted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger update
|
||||
if (hasCompleted) {
|
||||
// Update total achievements
|
||||
if (this.hasCompleted) {
|
||||
this.hasCompleted = false;
|
||||
this.getPlayer().trigger(AchievementCondition.AchievementTotal, this.getCompletedAchievementsCount());
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void triggerOne(int id, int progress, int param1, int param2) {
|
||||
// Get achievement data
|
||||
var data = GameData.getAchievementDataTable().get(id);
|
||||
if (data == null) return;
|
||||
|
||||
// Get achievement
|
||||
var achievement = this.getAchievement(data);
|
||||
|
||||
// Check what type of achievement condition this is
|
||||
boolean isTotal = AchievementHelper.isIncrementalAchievement(data.getCompleteCond());
|
||||
|
||||
// Update achievement
|
||||
boolean changed = achievement.trigger(isTotal, progress, param1, param2);
|
||||
|
||||
// Sync with client if achievement was changed
|
||||
if (changed) {
|
||||
this.syncAchievement(achievement);
|
||||
}
|
||||
|
||||
// Update total achievements
|
||||
if (this.hasCompleted) {
|
||||
this.hasCompleted = false;
|
||||
this.getPlayer().trigger(AchievementCondition.AchievementTotal, this.getCompletedAchievementsCount());
|
||||
}
|
||||
}
|
||||
@@ -205,6 +213,15 @@ public class AchievementManager extends PlayerManager implements GameDatabaseObj
|
||||
return;
|
||||
}
|
||||
|
||||
// Set save flag
|
||||
this.queueSave = true;
|
||||
|
||||
// Check if achievement was completed
|
||||
if (achievement.isComplete()) {
|
||||
this.hasCompleted = true;
|
||||
}
|
||||
|
||||
// Send update to player
|
||||
getPlayer().addNextPackage(
|
||||
NetMsgId.achievement_change_notify,
|
||||
achievement.toProto()
|
||||
|
||||
@@ -58,10 +58,15 @@ public class CharacterStorage extends PlayerManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.addCharacter(GameData.getCharacterDataTable().get(charId));
|
||||
// Get data
|
||||
var data = GameData.getCharacterDataTable().get(charId);
|
||||
if (data == null) return null;
|
||||
|
||||
// Add character
|
||||
return this.addCharacter(data);
|
||||
}
|
||||
|
||||
private GameCharacter addCharacter(CharacterDef data) {
|
||||
public GameCharacter addCharacter(CharacterDef data) {
|
||||
// Sanity check to make sure we dont have this character already
|
||||
if (this.hasCharacter(data.getId())) {
|
||||
return null;
|
||||
@@ -132,10 +137,15 @@ public class CharacterStorage extends PlayerManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.addDisc(GameData.getDiscDataTable().get(discId));
|
||||
// Get data
|
||||
var data = GameData.getDiscDataTable().get(discId);
|
||||
if (data == null) return null;
|
||||
|
||||
// Add disc
|
||||
return this.addDisc(data);
|
||||
}
|
||||
|
||||
private GameDisc addDisc(DiscDef data) {
|
||||
public GameDisc addDisc(DiscDef data) {
|
||||
// Sanity check to make sure we dont have this disc already
|
||||
if (this.hasDisc(data.getId())) {
|
||||
return null;
|
||||
|
||||
@@ -7,6 +7,7 @@ import dev.morphia.annotations.Id;
|
||||
import emu.nebula.GameConstants;
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.resources.DropPkgDef;
|
||||
import emu.nebula.data.resources.MallShopDef;
|
||||
import emu.nebula.data.resources.ResidentGoodsDef;
|
||||
import emu.nebula.database.GameDatabaseObject;
|
||||
@@ -284,8 +285,8 @@ public class Inventory extends PlayerManager implements GameDatabaseObject {
|
||||
change = new PlayerChangeInfo();
|
||||
}
|
||||
|
||||
// Sanity
|
||||
if (count == 0) {
|
||||
// Sanity check
|
||||
if (id <= 0 || count == 0) {
|
||||
return change;
|
||||
}
|
||||
|
||||
@@ -339,11 +340,32 @@ public class Inventory extends PlayerManager implements GameDatabaseObject {
|
||||
}
|
||||
}
|
||||
case Item -> {
|
||||
// Check if item is a random package
|
||||
if (data.getItemSubType() == ItemSubType.RandomPackage && data.getUseParams() != null) {
|
||||
// Cannot remove packages
|
||||
if (count <= 0) break;
|
||||
|
||||
// Add random packages
|
||||
for (var entry : data.getUseParams()) {
|
||||
int pkgId = entry.getIntKey();
|
||||
int pkgCount = entry.getIntValue() * count;
|
||||
|
||||
for (int i = 0; i < pkgCount; i++) {
|
||||
int pkgDropId = DropPkgDef.getRandomDrop(pkgId);
|
||||
this.addItem(pkgDropId, 1, change);
|
||||
}
|
||||
}
|
||||
|
||||
// End early
|
||||
break;
|
||||
}
|
||||
|
||||
// Get item
|
||||
var item = this.items.get(id);
|
||||
int diff = 0;
|
||||
|
||||
if (amount > 0) {
|
||||
// Add resource
|
||||
// Add item
|
||||
if (item == null) {
|
||||
item = new GameItem(this.getPlayer(), id, amount);
|
||||
this.items.put(item.getItemId(), item);
|
||||
@@ -377,12 +399,23 @@ public class Inventory extends PlayerManager implements GameDatabaseObject {
|
||||
}
|
||||
}
|
||||
case Disc -> {
|
||||
if (amount <= 0) {
|
||||
// Cannot remove discs
|
||||
if (amount <= 0) break;
|
||||
|
||||
// Get disc data
|
||||
var discData = GameData.getDiscDataTable().get(id);
|
||||
if (discData == null) break;
|
||||
|
||||
// Add transform item instead if we already have this disc
|
||||
if (getPlayer().getCharacters().hasDisc(id)) {
|
||||
this.addItem(discData.getTransformItemId(), amount, change);
|
||||
break;
|
||||
}
|
||||
|
||||
var disc = getPlayer().getCharacters().addDisc(id);
|
||||
// Add disc
|
||||
var disc = getPlayer().getCharacters().addDisc(discData);
|
||||
|
||||
// Add to change info
|
||||
if (disc != null) {
|
||||
change.add(disc.toProto());
|
||||
} else {
|
||||
@@ -390,12 +423,23 @@ public class Inventory extends PlayerManager implements GameDatabaseObject {
|
||||
}
|
||||
}
|
||||
case Char -> {
|
||||
if (amount <= 0) {
|
||||
// Cannot remove characters
|
||||
if (amount <= 0) break;
|
||||
|
||||
// Get character data
|
||||
var charData = GameData.getCharacterDataTable().get(id);
|
||||
if (charData == null) break;
|
||||
|
||||
// Add transform item instead if we already have this character
|
||||
if (getPlayer().getCharacters().hasCharacter(id)) {
|
||||
this.addItem(charData.getFragmentsId(), charData.getTransformQty(), change);
|
||||
break;
|
||||
}
|
||||
|
||||
var character = getPlayer().getCharacters().addCharacter(id);
|
||||
|
||||
// Add character
|
||||
var character = getPlayer().getCharacters().addCharacter(charData);
|
||||
|
||||
// Add to change info
|
||||
if (character != null) {
|
||||
change.add(character.toProto());
|
||||
} else {
|
||||
@@ -829,6 +873,20 @@ public class Inventory extends PlayerManager implements GameDatabaseObject {
|
||||
return change.setSuccess(true);
|
||||
}
|
||||
|
||||
public void resetShopPurchases() {
|
||||
// Clear shop purchases if it's not empty
|
||||
if (!this.getShopBuyCount().isEmpty()) {
|
||||
this.getShopBuyCount().clear();
|
||||
Nebula.getGameDatabase().update(this, this.getUid(), "shopBuyCount", this.getShopBuyCount());
|
||||
}
|
||||
|
||||
// Clear mall purchases if it's not empty
|
||||
if (!this.getMallBuyCount().isEmpty()) {
|
||||
this.getMallBuyCount().clear();
|
||||
Nebula.getGameDatabase().update(this, this.getUid(), "mallBuyCount", this.getMallBuyCount());
|
||||
}
|
||||
}
|
||||
|
||||
// Database
|
||||
|
||||
public void loadFromDatabase() {
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package emu.nebula.game.player;
|
||||
|
||||
import java.util.Stack;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import dev.morphia.annotations.AlsoLoad;
|
||||
import dev.morphia.annotations.Entity;
|
||||
@@ -36,6 +35,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 +85,8 @@ public class Player implements GameDatabaseObject {
|
||||
private int energy;
|
||||
private long energyLastUpdate;
|
||||
|
||||
private int signInIndex;
|
||||
|
||||
private long lastEpochDay;
|
||||
private long lastLogin;
|
||||
private long createTime;
|
||||
@@ -186,30 +188,26 @@ public class Player implements GameDatabaseObject {
|
||||
}
|
||||
|
||||
public void setSession(GameSession session) {
|
||||
int time = Nebula.getConfig().getServerOptions().sessionTimeout;
|
||||
long timeout = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(time);
|
||||
|
||||
if (this.session == null) {
|
||||
// Set session
|
||||
this.session = session;
|
||||
// Don't set session if it's the same session
|
||||
if (this.session == session) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Sanity check
|
||||
// 2. Prevent incorrect deletion of players when re-logging into the game
|
||||
if (this.session == session || this.lastLogin > timeout) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear player from session
|
||||
this.session.clearPlayer();
|
||||
|
||||
// Cache previous session
|
||||
var prevSession = this.session;
|
||||
|
||||
// Set session
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public void removeSession() {
|
||||
this.session = null;
|
||||
Nebula.getGameContext().getPlayerModule().removeFromCache(this);
|
||||
|
||||
// Clear player reference from the previous session
|
||||
if (prevSession != null) {
|
||||
prevSession.clearPlayer();
|
||||
}
|
||||
|
||||
// We cleared session, now remove player from cache
|
||||
if (this.session == null) {
|
||||
Nebula.getGameContext().getPlayerModule().removeFromCache(this);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasSession() {
|
||||
@@ -234,14 +232,12 @@ public class Player implements GameDatabaseObject {
|
||||
|
||||
public void setRemoteToken(String token) {
|
||||
// Skip if tokens are the same
|
||||
if (this.remoteToken == null) {
|
||||
if (this.getRemoteToken() == null) {
|
||||
if (token == null) {
|
||||
return;
|
||||
}
|
||||
} else if (this.remoteToken != null) {
|
||||
if (this.remoteToken.equals(token)) {
|
||||
return;
|
||||
}
|
||||
} else if (this.getRemoteToken().equals(token)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set remote token
|
||||
@@ -613,6 +609,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 +624,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,15 +640,55 @@ 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);
|
||||
|
||||
// Reset monthly shop purchases
|
||||
if (resetMonthly) {
|
||||
this.getInventory().resetShopPurchases();
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger quests + achievements
|
||||
@@ -767,6 +814,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]);
|
||||
|
||||
|
||||
@@ -769,32 +769,7 @@ public class StarTowerGame {
|
||||
}
|
||||
|
||||
// Refresh secondary skills
|
||||
var newSecondarySkills = SecondarySkillDef.calculateSecondarySkills(this.getDiscIds(), this.getItems());
|
||||
|
||||
// Add any new secondary skills to the data proto
|
||||
for (int id : newSecondarySkills) {
|
||||
if (!this.getSecondarySkills().contains(id)) {
|
||||
var info = ActiveSecondaryChange.newInstance()
|
||||
.setSecondaryId(id)
|
||||
.setActive(true);
|
||||
|
||||
data.addSecondaries(info);
|
||||
}
|
||||
}
|
||||
|
||||
// Inform the client that these skills are no longer active
|
||||
for (int id : this.getSecondarySkills()) {
|
||||
if (!newSecondarySkills.contains(id)) {
|
||||
var info = ActiveSecondaryChange.newInstance()
|
||||
.setSecondaryId(id)
|
||||
.setActive(false);
|
||||
|
||||
data.addSecondaries(info);
|
||||
}
|
||||
}
|
||||
|
||||
// Set new secondary skills
|
||||
this.secondarySkills = newSecondarySkills;
|
||||
this.refreshSecondarySkills(data);
|
||||
|
||||
// Clear new infos
|
||||
this.getNewInfos().clear();
|
||||
@@ -826,6 +801,50 @@ public class StarTowerGame {
|
||||
return rsp;
|
||||
}
|
||||
|
||||
// Etc
|
||||
|
||||
private void refreshSecondarySkills(TowerChangeData data) {
|
||||
// Init
|
||||
var newSecondarySkills = SecondarySkillDef.calculateSecondarySkills(this.getDiscIds(), this.getItems());
|
||||
int newSecondaryCount = 0;
|
||||
|
||||
// Add any new secondary skills to the data proto
|
||||
for (int id : newSecondarySkills) {
|
||||
if (!this.getSecondarySkills().contains(id)) {
|
||||
var info = ActiveSecondaryChange.newInstance()
|
||||
.setSecondaryId(id)
|
||||
.setActive(true);
|
||||
|
||||
data.addSecondaries(info);
|
||||
|
||||
// Counter
|
||||
newSecondaryCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Inform the client that these skills are no longer active
|
||||
for (int id : this.getSecondarySkills()) {
|
||||
if (!newSecondarySkills.contains(id)) {
|
||||
var info = ActiveSecondaryChange.newInstance()
|
||||
.setSecondaryId(id)
|
||||
.setActive(false);
|
||||
|
||||
data.addSecondaries(info);
|
||||
}
|
||||
}
|
||||
|
||||
// Set new secondary skills
|
||||
this.secondarySkills = newSecondarySkills;
|
||||
|
||||
// Achievement trigger
|
||||
if (newSecondaryCount > 0) {
|
||||
this.getAchievementManager().trigger(
|
||||
AchievementCondition.TowerSpecificSecondarySkillActivateTotal,
|
||||
newSecondaryCount
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Proto
|
||||
|
||||
public StarTowerInfo toProto() {
|
||||
|
||||
@@ -12,6 +12,7 @@ import emu.nebula.game.quest.QuestCondition;
|
||||
import emu.nebula.proto.StarTowerApply.StarTowerApplyReq;
|
||||
import emu.nebula.util.Utils;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
|
||||
@@ -34,6 +35,10 @@ public class StarTowerManager extends PlayerManager {
|
||||
return this.getPlayer().getProgress();
|
||||
}
|
||||
|
||||
public IntSet getStarTowerLog() {
|
||||
return this.getProgress().getStarTowerLog();
|
||||
}
|
||||
|
||||
// Growth nodes (talents/research)
|
||||
|
||||
public boolean hasGrowthNode(int id) {
|
||||
@@ -240,23 +245,20 @@ public class StarTowerManager extends PlayerManager {
|
||||
var achievements = this.getPlayer().getAchievementManager();
|
||||
|
||||
achievements.trigger(AchievementCondition.TowerClearTotal, 1);
|
||||
achievements.trigger(
|
||||
AchievementCondition.TowerClearSpecificGroupIdAndDifficulty,
|
||||
1,
|
||||
game.getData().getGroupId(),
|
||||
game.getData().getDifficulty()
|
||||
);
|
||||
achievements.trigger(
|
||||
AchievementCondition.TowerClearSpecificLevelWithDifficultyAndTotal,
|
||||
1,
|
||||
game.getData().getId(),
|
||||
game.getData().getDifficulty()
|
||||
0
|
||||
);
|
||||
|
||||
var elementType = game.getTeamElement();
|
||||
if (elementType != null) {
|
||||
achievements.trigger(AchievementCondition.TowerClearSpecificCharacterTypeWithTotal, 1, elementType.getValue(), 0);
|
||||
}
|
||||
|
||||
// Update tower group achievements
|
||||
this.updateTowerGroupAchievements(game);
|
||||
}
|
||||
|
||||
// Return game
|
||||
@@ -290,6 +292,35 @@ public class StarTowerManager extends PlayerManager {
|
||||
return change;
|
||||
}
|
||||
|
||||
// Achievements
|
||||
|
||||
private void updateTowerGroupAchievements(StarTowerGame game) {
|
||||
// Update "First Ascension" achievement
|
||||
boolean firstAscension = this.getStarTowerLog().contains(401) && this.getStarTowerLog().size() >= 2;
|
||||
if (firstAscension) {
|
||||
this.getPlayer().getAchievementManager().triggerOne(498, 1, 0, 1);
|
||||
}
|
||||
|
||||
// Get total clears on this difficulty
|
||||
int diff = game.getDifficulty();
|
||||
int totalDiffClears = 0;
|
||||
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
int towerId = (i * 100) + 1 + diff;
|
||||
if (this.getStarTowerLog().contains(towerId)) {
|
||||
totalDiffClears++;
|
||||
}
|
||||
}
|
||||
|
||||
// Update "Monolith Conqueror" achievements
|
||||
this.getPlayer().getAchievementManager().trigger(
|
||||
AchievementCondition.TowerClearSpecificGroupIdAndDifficulty,
|
||||
totalDiffClears,
|
||||
diff,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
// Build
|
||||
|
||||
private PlayerChangeInfo dismantleBuild(StarTowerBuild build, PlayerChangeInfo change) {
|
||||
|
||||
@@ -209,9 +209,13 @@ public class StarTowerHawkerCase extends StarTowerBaseCase {
|
||||
// Remove coins
|
||||
this.getGame().addItem(GameConstants.TOWER_COIN_ITEM_ID, -price, change);
|
||||
|
||||
// Achievement
|
||||
// Achievements
|
||||
this.getGame().getAchievementManager().trigger(AchievementCondition.TowerSpecificDifficultyShopBuyTimes, 1);
|
||||
|
||||
if (goods.hasDiscount()) {
|
||||
this.getGame().getAchievementManager().trigger(AchievementCondition.TowerSpecificShopBuyDiscountTotal, 1);
|
||||
}
|
||||
|
||||
// Set change info
|
||||
rsp.setChange(change.toProto());
|
||||
}
|
||||
|
||||
@@ -60,10 +60,12 @@ public class GameSession {
|
||||
var player = this.player;
|
||||
this.player = null;
|
||||
|
||||
// Remove session from player
|
||||
player.removeSession();
|
||||
// Remove session reference from player ONLY if their session wasn't replaced yet
|
||||
if (player.getSession() == this) {
|
||||
player.setSession(null);
|
||||
}
|
||||
|
||||
// Set remove flag
|
||||
// Set session removal flag
|
||||
this.remove = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
package emu.nebula.server;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.SecureRequestCustomizer;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
|
||||
import ch.qos.logback.classic.Level;
|
||||
import ch.qos.logback.classic.Logger;
|
||||
import emu.nebula.Config.HttpServerConfig;
|
||||
import emu.nebula.GameConstants;
|
||||
import emu.nebula.Nebula;
|
||||
@@ -21,6 +14,15 @@ import io.javalin.http.ContentType;
|
||||
import io.javalin.http.Context;
|
||||
import io.javalin.http.staticfiles.Location;
|
||||
import lombok.Getter;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
import org.eclipse.jetty.server.SecureRequestCustomizer;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.util.ssl.SslContextFactory;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
|
||||
@Getter
|
||||
public class HttpServer {
|
||||
@@ -39,6 +41,11 @@ public class HttpServer {
|
||||
if (staticFilesDir.exists()) {
|
||||
javalinConfig.staticFiles.add(staticFilesDir.getPath(), Location.EXTERNAL);
|
||||
}
|
||||
|
||||
if (Nebula.getConfig().getLogOptions().httpDebug) {
|
||||
javalinConfig.plugins.enableDevLogging();
|
||||
((Logger) LoggerFactory.getLogger("io.javalin")).setLevel(Level.DEBUG);
|
||||
}
|
||||
});
|
||||
|
||||
this.loadPatchList();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user