mirror of
https://github.com/Melledy/Nebula.git
synced 2025-12-23 09:45:06 +01:00
Compare commits
18 Commits
dfb93cae4b
...
v1.1.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
78d88a87cd | ||
|
|
e5ce16d6ea | ||
|
|
b92319b4c5 | ||
|
|
1b0b6873b9 | ||
|
|
f542ea7cb4 | ||
|
|
fa08bcebae | ||
|
|
209ce83fc9 | ||
|
|
8e7ef038ea | ||
|
|
90f4be862f | ||
|
|
05e74f4d12 | ||
|
|
005f138599 | ||
|
|
be5a6709fd | ||
|
|
c6ac09f112 | ||
|
|
7f0bdb1824 | ||
|
|
f8bd7d5db2 | ||
|
|
a7eddd2ed0 | ||
|
|
467b7443f3 | ||
|
|
2a7817df95 |
20
README.md
20
README.md
@@ -1,6 +1,6 @@
|
||||
# Nebula
|
||||
|
||||
A work in progress game server emulator for a certain anime game.
|
||||
A work in progress game server emulator for a certain anime game. Most features are implemented.
|
||||
|
||||
For any extra support, questions, or discussions, check out our [Discord](https://discord.gg/cskCWBqdJk).
|
||||
|
||||
@@ -19,21 +19,19 @@ For any extra support, questions, or discussions, check out our [Discord](https:
|
||||
- Commissions
|
||||
- Heartlink
|
||||
- Achievements
|
||||
- Monoliths (completeable but many other features missing)
|
||||
- Monoliths (some research nodes not working/research quests not implemented)
|
||||
- Bounty Trials
|
||||
- Menance Arena
|
||||
- Proving grounds
|
||||
- Proving Grounds
|
||||
- Catacylsm Survivor (talents not fully working)
|
||||
- Boss Blitz
|
||||
|
||||
### Not implemented
|
||||
- Events
|
||||
- Events (Only tower defense and trials)
|
||||
|
||||
### Supported regions
|
||||
|
||||
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 +64,8 @@ class Handlers
|
||||
".stellasora.global",
|
||||
".stellasora.kr",
|
||||
".stellasora.jp",
|
||||
".stargazer-games.com"
|
||||
".stargazer-games.com",
|
||||
".yostar.cn"
|
||||
];
|
||||
|
||||
static function OnBeforeRequest(oS: Session) {
|
||||
@@ -88,12 +87,15 @@ Server commands need to be run in the server console OR in the signature edit me
|
||||
|
||||
```
|
||||
!account {create | delete} [email] (reserved player uid) = Creates or deletes an account.
|
||||
!battlepass [free | premium] lv(level) = Modifies the targeted player's battle pass
|
||||
!char [all | {characterId}] lv(level) a(ascension) s(skill level) t(talent level) f(affinity level) = Changes the properties of the targeted characters.
|
||||
!clean [all | {id} ...] [items|resources] = Removes items/resources from the targeted player.
|
||||
!disc [all | {discId}] lv(level) a(ascension) c(crescendo level) = Changes the properties of the targeted discs.
|
||||
!give [item id] x[amount] = Gives the targeted player an item through the mail.
|
||||
!giveall [characters | discs | materials] = Gives the targeted player items.
|
||||
!help = Displays a list of available commands. (Very spammy in-game)
|
||||
!level (level) = Sets the player level
|
||||
!mail = Sends the targeted player a system mail.
|
||||
!mail "subject" "body" [itemId xQty | itemId:qty ...] = Sends the targeted player a system mail.
|
||||
!reload = Reloads the server config.
|
||||
!remote = Creates a player token for remote api usage
|
||||
```
|
||||
|
||||
@@ -29,7 +29,7 @@ java {
|
||||
}
|
||||
}
|
||||
|
||||
version = '1.1.2'
|
||||
version = '1.1.3'
|
||||
|
||||
var shouldGenerateProto = System.getenv("GENERATE_PROTO") == "true"
|
||||
System.out.println(shouldGenerateProto ? "Generating proto files" : "Skipping proto generation")
|
||||
|
||||
@@ -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/stage 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
|
||||
|
||||
@@ -22,6 +22,9 @@ public class GameConstants {
|
||||
|
||||
RegionConfig.getRegion("tw")
|
||||
.setDataVersion(64);
|
||||
|
||||
RegionConfig.getRegion("cn")
|
||||
.setDataVersion(64);
|
||||
}
|
||||
|
||||
public static final ZoneId UTC_ZONE = ZoneId.of("UTC");
|
||||
@@ -35,6 +38,7 @@ public class GameConstants {
|
||||
public static final int PREM_GEM_ITEM_ID = 3;
|
||||
public static final int ENERGY_BUY_ITEM_ID = GEM_ITEM_ID;
|
||||
public static final int EXP_ITEM_ID = 21;
|
||||
public static final int WEEKLY_ENTRY_ITEM_ID = 28;
|
||||
|
||||
public static final int MAX_ENERGY = 240;
|
||||
public static final int ENERGY_REGEN_TIME = 360; // Seconds
|
||||
|
||||
@@ -6,7 +6,7 @@ import emu.nebula.command.CommandHandler;
|
||||
import emu.nebula.game.account.AccountHelper;
|
||||
import emu.nebula.util.Utils;
|
||||
|
||||
@Command(label = "account", permission = "admin.account", desc = "/account {create | delete} [email] (reserved player uid). Creates or deletes an account.")
|
||||
@Command(label = "account", permission = "admin.account", desc = "!account {create | delete} [email] (reserved player uid). Creates or deletes an account.")
|
||||
public class AccountCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,7 +5,7 @@ import emu.nebula.command.CommandArgs;
|
||||
import emu.nebula.command.CommandHandler;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
|
||||
@Command(label = "battlepass", aliases = {"bp"}, permission = "player.battlepass", desc = "/battlepass [free | premium] lv(level). mMdifies your battle pass")
|
||||
@Command(label = "battlepass", aliases = {"bp"}, permission = "player.battlepass", desc = "!battlepass [free | premium] lv(level) = Modifies the targeted player's battle pass")
|
||||
public class BattlePassCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,7 +20,7 @@ import java.util.HashSet;
|
||||
aliases = {"cl", "clear"},
|
||||
permission = "player.inventory",
|
||||
requireTarget = true,
|
||||
desc = "!clean [all | {id} ...] [items|resources]. Removes items/resources from the targeted player."
|
||||
desc = "!clean [all | {id} ...] [items|resources] = Removes items/resources from the targeted player."
|
||||
)
|
||||
public class CleanCommand implements CommandHandler {
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import emu.nebula.command.CommandHandler;
|
||||
aliases = {"g", "item"},
|
||||
permission = "player.give",
|
||||
requireTarget = true,
|
||||
desc = "/give [item id] x(amount). Gives the targeted player an item."
|
||||
desc = "!give [item id] x(amount). Gives the targeted player an item."
|
||||
)
|
||||
public class GiveCommand implements CommandHandler {
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import emu.nebula.command.Command;
|
||||
import emu.nebula.command.CommandArgs;
|
||||
import emu.nebula.command.CommandHandler;
|
||||
|
||||
@Command(label = "help", permission = "player.help", desc = "/help. Displays a list of available commands.")
|
||||
@Command(label = "help", permission = "player.help", desc = "!help = Displays a list of available commands. (Very spammy in-game)")
|
||||
public class HelpCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,8 +8,8 @@ import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.NotifyGm.GmWorldClass;
|
||||
import emu.nebula.util.Utils;
|
||||
|
||||
@Command(label = "setlevel", aliases = {"level", "l"}, permission = "player.level", requireTarget = true, desc = "/level [level]. Set player level")
|
||||
public class SetLevelCommand implements CommandHandler {
|
||||
@Command(label = "setlevel", aliases = {"level", "l"}, permission = "player.level", requireTarget = true, desc = "!level [level] = Set's the targeted player's level")
|
||||
public class LevelCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
public String execute(CommandArgs args) {
|
||||
@@ -14,7 +14,7 @@ import emu.nebula.util.Utils;
|
||||
aliases = {"m"},
|
||||
permission = "player.mail",
|
||||
requireTarget = true,
|
||||
desc = "/mail \"subject\" \"body\" [itemId xQty | itemId:qty ...]. Sends the targeted player a system mail."
|
||||
desc = "!mail \"subject\" \"body\" [itemId xQty | itemId:qty ...] = Sends the targeted player a system mail."
|
||||
)
|
||||
public class MailCommand implements CommandHandler {
|
||||
private static final String USAGE_TEXT = "Usage: /mail \"subject\" \"body\" [itemId xQty | itemId:qty ...]";
|
||||
|
||||
@@ -5,7 +5,7 @@ import emu.nebula.command.Command;
|
||||
import emu.nebula.command.CommandArgs;
|
||||
import emu.nebula.command.CommandHandler;
|
||||
|
||||
@Command(label = "reload", permission = "admin.reload", desc = "/reload. Reloads the server config.")
|
||||
@Command(label = "reload", permission = "admin.reload", desc = "!reload = Reloads the server config.")
|
||||
public class ReloadCommand implements CommandHandler {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,7 +7,7 @@ import emu.nebula.command.CommandHandler;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
@Command(label = "remote", permission = "player.remote", requireTarget = true, desc = "/remote. Send remote to web remote")
|
||||
@Command(label = "remote", permission = "player.remote", requireTarget = true, desc = "!remote = Creates a player token for remote api usage")
|
||||
public class RemoteKeyCommand implements CommandHandler {
|
||||
private final String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
|
||||
|
||||
@@ -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,23 +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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package emu.nebula.data.resources;
|
||||
|
||||
import emu.nebula.data.BaseDef;
|
||||
import emu.nebula.data.ResourceType;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ResourceType(name = "ScoreBossReward.json")
|
||||
public class ScoreBossRewardDef extends BaseDef {
|
||||
private int StarNeed;
|
||||
private int RewardItemId1;
|
||||
private int RewardNum1;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return StarNeed;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package emu.nebula.data.resources;
|
||||
|
||||
import emu.nebula.data.BaseDef;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.ResourceType;
|
||||
import emu.nebula.data.ResourceType.LoadPriority;
|
||||
import emu.nebula.game.instance.InstanceData;
|
||||
import emu.nebula.game.inventory.ItemRewardList;
|
||||
import emu.nebula.game.inventory.ItemRewardParam;
|
||||
@@ -10,9 +12,10 @@ import emu.nebula.util.JsonUtils;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ResourceType(name = "WeekBossLevel.json")
|
||||
@ResourceType(name = "WeekBossLevel.json", loadPriority = LoadPriority.LOW)
|
||||
public class WeekBossLevelDef extends BaseDef implements InstanceData {
|
||||
private int Id;
|
||||
private int Difficulty;
|
||||
private int PreLevelId;
|
||||
private int NeedWorldClass;
|
||||
private String BaseAwardPreview;
|
||||
@@ -44,14 +47,33 @@ public class WeekBossLevelDef extends BaseDef implements InstanceData {
|
||||
for (int[] award : awards) {
|
||||
int itemId = award[0];
|
||||
int min = award[1];
|
||||
int max = award.length >= 4 ? award[2] : min;
|
||||
int max = award[1];
|
||||
boolean isFirst = award[award.length - 1] == 1;
|
||||
|
||||
// Set reward count based on difficulty
|
||||
if (min == -1) {
|
||||
min = 0;
|
||||
max = 1;
|
||||
min = this.Difficulty;
|
||||
max = this.Difficulty;
|
||||
|
||||
var item = GameData.getItemDataTable().get(itemId);
|
||||
if (item != null) {
|
||||
switch (item.getRarity()) {
|
||||
case 2:
|
||||
max = this.Difficulty * 3;
|
||||
break;
|
||||
case 3:
|
||||
min = this.Difficulty * 2;
|
||||
max = this.Difficulty * 6;
|
||||
break;
|
||||
case 4:
|
||||
min = this.Difficulty * 3;
|
||||
max = this.Difficulty * 9;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create reward param
|
||||
var reward = new ItemRewardParam(itemId, min, max);
|
||||
|
||||
if (isFirst) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -1,26 +1,25 @@
|
||||
package emu.nebula.game.activity.type;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.resources.ActivityDef;
|
||||
import emu.nebula.game.activity.ActivityManager;
|
||||
import emu.nebula.game.activity.GameActivity;
|
||||
import emu.nebula.game.inventory.ItemParamMap;
|
||||
import emu.nebula.game.player.PlayerChangeInfo;
|
||||
import emu.nebula.proto.ActivityDetail.ActivityMsg;
|
||||
import emu.nebula.proto.Public.ActivityQuest;
|
||||
import emu.nebula.proto.Public.ActivityTowerDefenseLevel;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Entity
|
||||
public class TowerDefenseActivity extends GameActivity {
|
||||
private Map<Integer, Integer> completedStages;
|
||||
private Map<Integer, Integer> completedQuests;
|
||||
private Int2IntMap completedStages;
|
||||
private Int2IntMap completedQuests;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public TowerDefenseActivity() {
|
||||
@@ -29,19 +28,16 @@ public class TowerDefenseActivity extends GameActivity {
|
||||
|
||||
public TowerDefenseActivity(ActivityManager manager, ActivityDef data) {
|
||||
super(manager, data);
|
||||
this.completedStages = new HashMap<Integer, Integer>();
|
||||
this.completedQuests = new HashMap<Integer, Integer>();
|
||||
this.completedStages = new Int2IntOpenHashMap();
|
||||
this.completedQuests = new Int2IntOpenHashMap();
|
||||
}
|
||||
|
||||
public PlayerChangeInfo claimReward(int level) {
|
||||
// Initialize change info
|
||||
var change = new PlayerChangeInfo();
|
||||
|
||||
// Get rewards
|
||||
var rewards = GameData.getTowerDefenseLevelDataTable().get(level).getRewards();
|
||||
|
||||
// Add rewards
|
||||
return getPlayer().getInventory().addItems(rewards, change);
|
||||
return getPlayer().getInventory().addItems(rewards);
|
||||
}
|
||||
|
||||
// public PlayerChangeInfo claimReward(int groupId) {
|
||||
|
||||
@@ -58,15 +58,25 @@ 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;
|
||||
}
|
||||
|
||||
// Prevent players from getting unavliable characters
|
||||
if (!data.isAvailable()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create character
|
||||
var character = new GameCharacter(this.getPlayer(), data);
|
||||
|
||||
@@ -127,15 +137,25 @@ 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) {
|
||||
// Sanity check to make sure we dont have this character already
|
||||
public GameDisc addDisc(DiscDef data) {
|
||||
// Sanity check to make sure we dont have this disc already
|
||||
if (this.hasDisc(data.getId())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Prevent players from getting unavliable discs
|
||||
if (!data.isAvailable()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Create disc
|
||||
var disc = new GameDisc(this.getPlayer(), data);
|
||||
|
||||
|
||||
@@ -137,5 +137,55 @@ public class InstanceManager extends PlayerManager {
|
||||
// Success
|
||||
return change.setSuccess(true);
|
||||
}
|
||||
|
||||
public PlayerChangeInfo settleWeekly(InstanceData data, boolean win) {
|
||||
// Calculate settle data
|
||||
var settleData = new InstanceSettleData();
|
||||
|
||||
settleData.setWin(win);
|
||||
settleData.setFirst(settleData.isWin() && !getProgress().getWeekBossLog().containsKey(data.getId()));
|
||||
|
||||
// Init player change info
|
||||
var change = new PlayerChangeInfo();
|
||||
|
||||
// Handle win
|
||||
if (settleData.isWin()) {
|
||||
// Calculate rewards
|
||||
int entries = this.getPlayer().getInventory().getResourceCount(GameConstants.WEEKLY_ENTRY_ITEM_ID);
|
||||
|
||||
if (entries > 0) {
|
||||
// Generate regular rewards
|
||||
settleData.setRewards(data.getRewards().generate());
|
||||
|
||||
// Add regular rewards
|
||||
getPlayer().getInventory().addItems(settleData.getRewards(), change);
|
||||
|
||||
// Remove weekly entry
|
||||
getPlayer().getInventory().removeItem(GameConstants.WEEKLY_ENTRY_ITEM_ID, 1, change);
|
||||
}
|
||||
|
||||
// Add first clear rewards even if we dont have the entry ticket
|
||||
if (settleData.isFirst()) {
|
||||
// Generate first clear rewards
|
||||
settleData.setRewards(data.getFirstRewards().generate());
|
||||
|
||||
// Add to inventory
|
||||
getPlayer().getInventory().addItems(settleData.getFirstRewards(), change);
|
||||
}
|
||||
|
||||
// Log
|
||||
this.getProgress().saveInstanceLog(getProgress().getWeekBossLog(), "weekBossLog", data.getId(), 1);
|
||||
|
||||
// Quest triggers
|
||||
this.getPlayer().trigger(QuestCondition.WeekBoosClearSpecificDifficultyAndTotal, 1);
|
||||
this.getPlayer().trigger(QuestCondition.BattleTotal, 1);
|
||||
}
|
||||
|
||||
// Set extra data
|
||||
change.setExtraData(settleData);
|
||||
|
||||
// Success
|
||||
return change.setSuccess(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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,25 +399,51 @@ 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 {
|
||||
amount = 0;
|
||||
}
|
||||
}
|
||||
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 {
|
||||
amount = 0;
|
||||
}
|
||||
}
|
||||
case Energy -> {
|
||||
@@ -466,7 +514,7 @@ public class Inventory extends PlayerManager implements GameDatabaseObject {
|
||||
// Trigger quest + achievement
|
||||
if (amount > 0) {
|
||||
this.getPlayer().trigger(QuestCondition.ItemsAdd, amount, id);
|
||||
} else {
|
||||
} else if (amount < 0) {
|
||||
this.getPlayer().trigger(QuestCondition.ItemsDeplete, Math.abs(amount), id);
|
||||
}
|
||||
|
||||
@@ -825,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,21 +624,71 @@ 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);
|
||||
|
||||
// Add weekly boss entry item
|
||||
int entries = this.getInventory().getResourceCount(GameConstants.WEEKLY_ENTRY_ITEM_ID);
|
||||
if (entries < 3) {
|
||||
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
|
||||
@@ -719,6 +772,11 @@ public class Player implements GameDatabaseObject {
|
||||
// Load complete
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
public void onCreate() {
|
||||
// Send welcome mail
|
||||
this.getMailbox().sendWelcomeMail();
|
||||
}
|
||||
|
||||
public void onLogin() {
|
||||
// See if we need to reset dailies
|
||||
@@ -756,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]);
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import emu.nebula.Nebula;
|
||||
import emu.nebula.game.GameContext;
|
||||
import emu.nebula.game.GameContextModule;
|
||||
import emu.nebula.game.account.Account;
|
||||
import emu.nebula.game.achievement.AchievementManager;
|
||||
import emu.nebula.game.activity.ActivityManager;
|
||||
import emu.nebula.game.agent.AgentManager;
|
||||
import emu.nebula.game.battlepass.BattlePass;
|
||||
import emu.nebula.game.character.GameCharacter;
|
||||
@@ -130,12 +132,13 @@ public class PlayerModule extends GameContextModule {
|
||||
player.onLoad();
|
||||
player.save();
|
||||
|
||||
// Send welcome mail
|
||||
player.getMailbox().sendWelcomeMail();
|
||||
// Handle any player creation events
|
||||
player.onCreate();
|
||||
|
||||
// Put in player cache
|
||||
this.addToCache(player);
|
||||
|
||||
// Complete
|
||||
return player;
|
||||
}
|
||||
|
||||
@@ -179,6 +182,8 @@ public class PlayerModule extends GameContextModule {
|
||||
datastore.getCollection(StoryManager.class).deleteOne(idFilter);
|
||||
datastore.getCollection(QuestManager.class).deleteOne(idFilter);
|
||||
datastore.getCollection(AgentManager.class).deleteOne(idFilter);
|
||||
datastore.getCollection(AchievementManager.class).deleteOne(idFilter);
|
||||
datastore.getCollection(ActivityManager.class).deleteOne(idFilter);
|
||||
|
||||
datastore.getCollection(BattlePass.class).deleteOne(idFilter);
|
||||
datastore.getCollection(ScoreBossRankEntry.class).deleteOne(idFilter);
|
||||
|
||||
@@ -132,7 +132,6 @@ public class QuestManager extends PlayerManager implements GameDatabaseObject {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update this quest on the player client
|
||||
*/
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
package emu.nebula.game.scoreboss;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.resources.ScoreBossControlDef;
|
||||
import emu.nebula.data.resources.ScoreBossRewardDef;
|
||||
import emu.nebula.game.inventory.ItemParamMap;
|
||||
import emu.nebula.game.player.Player;
|
||||
import emu.nebula.game.player.PlayerChangeInfo;
|
||||
import emu.nebula.game.player.PlayerManager;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@@ -27,7 +34,7 @@ public class ScoreBossManager extends PlayerManager {
|
||||
return GameData.getScoreBossControlDataTable().get(this.getControlId());
|
||||
}
|
||||
|
||||
public ScoreBossRankEntry getRanking() {
|
||||
public ScoreBossRankEntry getRankEntry() {
|
||||
if (this.ranking == null && !this.checkedDatabase) {
|
||||
this.ranking = Nebula.getGameDatabase().getObjectByUid(ScoreBossRankEntry.class, this.getPlayerUid());
|
||||
this.checkedDatabase = true;
|
||||
@@ -57,7 +64,7 @@ public class ScoreBossManager extends PlayerManager {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean settle(int stars, int score) {
|
||||
public boolean settle(int stars, int score, int skillScore) {
|
||||
// Get level
|
||||
var control = getControlData();
|
||||
if (control == null || !control.getLevelGroup().contains(this.getLevelId())) {
|
||||
@@ -71,7 +78,7 @@ public class ScoreBossManager extends PlayerManager {
|
||||
}
|
||||
|
||||
// Get ranking from database
|
||||
this.getRanking();
|
||||
this.getRankEntry();
|
||||
|
||||
// Create ranking if its not in the database
|
||||
if (this.ranking == null) {
|
||||
@@ -79,7 +86,7 @@ public class ScoreBossManager extends PlayerManager {
|
||||
}
|
||||
|
||||
// Settle
|
||||
this.ranking.settle(this.getPlayer(), build, getControlId(), getLevelId(), stars, score);
|
||||
this.ranking.settle(this.getPlayer(), build, getControlId(), getLevelId(), stars, score, skillScore);
|
||||
|
||||
// Save ranking
|
||||
this.ranking.save();
|
||||
@@ -91,4 +98,54 @@ public class ScoreBossManager extends PlayerManager {
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
public PlayerChangeInfo claimRewards(int star) {
|
||||
// Get rank entry
|
||||
this.getRankEntry();
|
||||
|
||||
if (this.ranking == null) {
|
||||
return new PlayerChangeInfo();
|
||||
}
|
||||
|
||||
// Init variables
|
||||
Collection<ScoreBossRewardDef> claims = null;
|
||||
|
||||
// Add to claim list
|
||||
if (star > 0) {
|
||||
var data = GameData.getScoreBossRewardDataTable().get(star);
|
||||
if (data != null) {
|
||||
claims = List.of(data);
|
||||
}
|
||||
} else {
|
||||
claims = GameData.getScoreBossRewardDataTable().values();
|
||||
}
|
||||
|
||||
// Init rewards
|
||||
var rewards = new ItemParamMap();
|
||||
int starCount = ranking.getStars();
|
||||
boolean shouldSave = false;
|
||||
|
||||
// Try and claim
|
||||
for (var data : claims) {
|
||||
// Check if we have earned enough stars
|
||||
if (starCount >= data.getStarNeed() && !ranking.getClaimedRewards().contains(data.getId())) {
|
||||
// Add rewards
|
||||
rewards.add(data.getRewardItemId1(), data.getRewardNum1());
|
||||
|
||||
// Set in claimed rewards
|
||||
this.ranking.getClaimedRewards().add(data.getId());
|
||||
|
||||
// Set save flag so we update ranking to the database
|
||||
shouldSave = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Save to database
|
||||
if (shouldSave) {
|
||||
this.ranking.save();
|
||||
}
|
||||
|
||||
// Add rewards
|
||||
return this.getPlayer().getInventory().addItems(rewards);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@ import emu.nebula.proto.Public.HonorInfo;
|
||||
import emu.nebula.proto.ScoreBossRank.ScoreBossRankChar;
|
||||
import emu.nebula.proto.ScoreBossRank.ScoreBossRankData;
|
||||
import emu.nebula.proto.ScoreBossRank.ScoreBossRankTeam;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@@ -33,6 +34,9 @@ public class ScoreBossRankEntry implements GameDatabaseObject {
|
||||
private int titleSuffix;
|
||||
private int[] honor;
|
||||
private int score;
|
||||
@SuppressWarnings("unused")
|
||||
private int stars;
|
||||
private IntSet claimedRewards;
|
||||
|
||||
private int controlId;
|
||||
private Map<Integer, ScoreBossTeamEntry> teams;
|
||||
@@ -51,6 +55,25 @@ public class ScoreBossRankEntry implements GameDatabaseObject {
|
||||
this.teams = new HashMap<>();
|
||||
}
|
||||
|
||||
// TODO replace later
|
||||
public int getStars() {
|
||||
int stars = 0;
|
||||
|
||||
for (var team : this.getTeams().values()) {
|
||||
stars += team.getStars();
|
||||
}
|
||||
|
||||
return stars;
|
||||
}
|
||||
|
||||
public IntSet getClaimedRewards() {
|
||||
if (this.claimedRewards == null) {
|
||||
this.claimedRewards = new IntOpenHashSet();
|
||||
}
|
||||
|
||||
return this.claimedRewards;
|
||||
}
|
||||
|
||||
public void update(Player player) {
|
||||
this.name = player.getName();
|
||||
this.level = player.getLevel();
|
||||
@@ -60,28 +83,39 @@ public class ScoreBossRankEntry implements GameDatabaseObject {
|
||||
this.honor = player.getHonor();
|
||||
}
|
||||
|
||||
public void settle(Player player, StarTowerBuild build, int controlId, int level, int stars, int score) {
|
||||
public void settle(Player player, StarTowerBuild build, int controlId, int level, int stars, int score, int skillScore) {
|
||||
// Update player data
|
||||
this.update(player);
|
||||
|
||||
// Reset score entry if control id doesn't match
|
||||
if (this.controlId != controlId) {
|
||||
this.controlId = controlId;
|
||||
this.getTeams().clear();
|
||||
this.reset();
|
||||
}
|
||||
|
||||
// Set team entry
|
||||
var team = new ScoreBossTeamEntry(player, build, stars, score);
|
||||
var team = new ScoreBossTeamEntry(player, build, stars, score, skillScore);
|
||||
|
||||
// Put in team map
|
||||
this.getTeams().put(level, team);
|
||||
|
||||
// Calculate score
|
||||
// Calculate score/stars
|
||||
this.score = 0;
|
||||
this.stars = 0;
|
||||
|
||||
for (var t : this.getTeams().values()) {
|
||||
this.score += t.getLevelScore();
|
||||
this.stars += t.getStars();
|
||||
}
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
this.score = 0;
|
||||
this.stars = 0;
|
||||
this.getClaimedRewards().clear();
|
||||
this.getTeams().clear();
|
||||
}
|
||||
|
||||
// Proto
|
||||
|
||||
public ScoreBossRankData toProto() {
|
||||
@@ -115,6 +149,7 @@ public class ScoreBossRankEntry implements GameDatabaseObject {
|
||||
private int buildScore;
|
||||
private int stars;
|
||||
private int levelScore;
|
||||
private int skillScore;
|
||||
private List<ScoreBossCharEntry> characters;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
@@ -122,11 +157,12 @@ public class ScoreBossRankEntry implements GameDatabaseObject {
|
||||
|
||||
}
|
||||
|
||||
public ScoreBossTeamEntry(Player player, StarTowerBuild build, int stars, int score) {
|
||||
public ScoreBossTeamEntry(Player player, StarTowerBuild build, int stars, int score, int skillScore) {
|
||||
this.buildId = build.getUid();
|
||||
this.buildScore = build.getScore();
|
||||
this.stars = stars;
|
||||
this.levelScore = score;
|
||||
this.skillScore = skillScore;
|
||||
this.characters = new ArrayList<>();
|
||||
|
||||
for (var charId : build.getCharIds()) {
|
||||
|
||||
@@ -76,6 +76,7 @@ public class StarTowerGame {
|
||||
|
||||
private int pendingPotentialCases = 0;
|
||||
private int pendingSubNotes = 0;
|
||||
private boolean completed;
|
||||
|
||||
// Bag
|
||||
private ItemParamMap items;
|
||||
@@ -768,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();
|
||||
@@ -807,33 +783,68 @@ public class StarTowerGame {
|
||||
}
|
||||
|
||||
public StarTowerInteractResp settle(StarTowerInteractResp rsp, boolean isWin) {
|
||||
// Set completed flag
|
||||
this.completed = true;
|
||||
|
||||
// End game
|
||||
this.getManager().endGame(isWin);
|
||||
this.getManager().settleGame(isWin);
|
||||
|
||||
// Settle info
|
||||
var settle = rsp.getMutableSettle()
|
||||
.setTotalTime(this.getBattleTime())
|
||||
.setBuild(this.getBuild().toProto());
|
||||
|
||||
// Mark change info
|
||||
// Set empty change info
|
||||
settle.getMutableChange();
|
||||
|
||||
// Log victory
|
||||
if (isWin) {
|
||||
// Add star tower history
|
||||
this.getManager().getPlayer().getProgress().addStarTowerLog(this.getId());
|
||||
|
||||
// Trigger achievement
|
||||
var elementType = this.getTeamElement();
|
||||
if (elementType != null) {
|
||||
this.getAchievementManager().trigger(AchievementCondition.TowerClearSpecificCharacterTypeWithTotal, 1, elementType.getValue(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Complete
|
||||
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() {
|
||||
|
||||
@@ -10,7 +10,9 @@ import emu.nebula.game.player.PlayerManager;
|
||||
import emu.nebula.game.player.PlayerProgress;
|
||||
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;
|
||||
|
||||
@@ -33,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) {
|
||||
@@ -219,7 +225,7 @@ public class StarTowerManager extends PlayerManager {
|
||||
return change.setExtraData(this.game);
|
||||
}
|
||||
|
||||
public StarTowerGame endGame(boolean victory) {
|
||||
public StarTowerGame settleGame(boolean victory) {
|
||||
// Cache instance
|
||||
var game = this.game;
|
||||
|
||||
@@ -232,27 +238,87 @@ public class StarTowerManager extends PlayerManager {
|
||||
|
||||
// Handle victory events
|
||||
if (victory) {
|
||||
// Trigger achievements
|
||||
this.getPlayer().trigger(AchievementCondition.TowerClearTotal, 1);
|
||||
this.getPlayer().trigger(
|
||||
AchievementCondition.TowerClearSpecificGroupIdAndDifficulty,
|
||||
1,
|
||||
game.getData().getGroupId(),
|
||||
game.getData().getDifficulty()
|
||||
);
|
||||
this.getPlayer().trigger(
|
||||
// Add star tower history
|
||||
this.getPlayer().getProgress().addStarTowerLog(game.getId());
|
||||
|
||||
// Achievement conditions
|
||||
var achievements = this.getPlayer().getAchievementManager();
|
||||
|
||||
achievements.trigger(AchievementCondition.TowerClearTotal, 1);
|
||||
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
|
||||
return game;
|
||||
}
|
||||
|
||||
public PlayerChangeInfo addRewards(PlayerChangeInfo change) {
|
||||
// Create change info
|
||||
if (change == null) {
|
||||
change = new PlayerChangeInfo();
|
||||
}
|
||||
|
||||
// Get game
|
||||
var game = this.getGame();
|
||||
|
||||
if (game == null || !game.isCompleted()) {
|
||||
return change;
|
||||
}
|
||||
|
||||
// Add journey tickets
|
||||
this.getPlayer().getInventory().addItem(12, game.getModifiers().calculateTickets(), change);
|
||||
|
||||
// (Custom) Add research materials since tower quests are not implemented yet
|
||||
int amount = 50 + (Utils.randomRange(game.getDifficulty() - 1, game.getDifficulty() * 2) * 10);
|
||||
this.getPlayer().getInventory().addItem(51, amount, change);
|
||||
|
||||
// Clear game instance
|
||||
this.game = null;
|
||||
|
||||
// Return game
|
||||
return game;
|
||||
// Return change info
|
||||
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
|
||||
@@ -277,8 +343,10 @@ public class StarTowerManager extends PlayerManager {
|
||||
// Create player change info
|
||||
var change = new PlayerChangeInfo();
|
||||
|
||||
// Cache build and clear reference
|
||||
// Cache build
|
||||
var build = this.lastBuild;
|
||||
|
||||
// Clear reference to build
|
||||
this.lastBuild = null;
|
||||
|
||||
// Check if the player wants this build or not
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package emu.nebula.game.tower;
|
||||
|
||||
import emu.nebula.GameConstants;
|
||||
import emu.nebula.util.Utils;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
@@ -178,4 +179,27 @@ public class StarTowerModifiers {
|
||||
public void consumeShopReroll() {
|
||||
this.shopRerollCount = Math.max(this.shopRerollCount - 1, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amount of tickets we earn from completing this monolith
|
||||
*/
|
||||
public int calculateTickets() {
|
||||
// Get base amount
|
||||
int tickets = 50;
|
||||
|
||||
// Add tickets based on difficulty
|
||||
tickets += Utils.randomRange(game.getDifficulty() * 50, game.getDifficulty() * 100);
|
||||
|
||||
// Apply talent modifiers
|
||||
if (this.hasGrowthNode(20403)) {
|
||||
tickets *= 2; // +100%
|
||||
} else if (this.hasGrowthNode(20102)) {
|
||||
tickets *= 1.6; // +60%
|
||||
} else if (this.hasGrowthNode(10501)) {
|
||||
tickets *= 1.3; // +30%
|
||||
}
|
||||
|
||||
// Complete
|
||||
return tickets;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
@@ -162,8 +169,10 @@ public class HttpServer {
|
||||
|
||||
getApp().post("/user/detail", new UserLoginHandler());
|
||||
getApp().post("/user/set", new UserSetDataHandler());
|
||||
getApp().post("/user/set-info", new UserSetDataHandler()); // CN
|
||||
getApp().post("/user/login", new UserLoginHandler());
|
||||
getApp().post("/user/quick-login", new UserLoginHandler());
|
||||
getApp().post("/user/send-sms", new HttpJsonResponse("{\"Code\":200,\"Data\":{},\"Msg\":\"OK\"}"));
|
||||
|
||||
getApp().post("/yostar/get-auth", new GetAuthHandler());
|
||||
getApp().post("/yostar/send-code", new HttpJsonResponse("{\"Code\":200,\"Data\":{},\"Msg\":\"OK\"}")); // Dummy handler
|
||||
|
||||
@@ -4,7 +4,6 @@ import emu.nebula.net.NetHandler;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.ActivityTowerDefenseLevelSettle.ActivityTowerDefenseLevelSettleReq;
|
||||
import emu.nebula.net.HandlerId;
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.game.activity.type.TowerDefenseActivity;
|
||||
import emu.nebula.net.GameSession;
|
||||
|
||||
@@ -20,7 +19,7 @@ public class HandlerActivityTowerDefenseLevelSettleReq extends NetHandler {
|
||||
var activity = session.getPlayer().getActivityManager().getActivity(TowerDefenseActivity.class, 102001);
|
||||
|
||||
// Claim rewards
|
||||
var change = activity.claimReward((int)req.getLevelId());
|
||||
var change = activity.claimReward(req.getLevelId());
|
||||
|
||||
// Update completed stages
|
||||
activity.getCompletedStages().put(req.getLevelId(), req.getStar());
|
||||
|
||||
@@ -19,7 +19,15 @@ public class HandlerPlayerLoginReq extends NetHandler {
|
||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||
// Parse request
|
||||
var req = LoginReq.parseFrom(message);
|
||||
var loginToken = req.getOfficialOverseas().getToken();
|
||||
|
||||
// os
|
||||
String loginToken = req.getOfficialOverseas().getToken();
|
||||
|
||||
if (loginToken == null || loginToken.isEmpty()) {
|
||||
// cn
|
||||
loginToken = req.getOfficial().getToken();
|
||||
}
|
||||
|
||||
|
||||
// Login
|
||||
boolean result = session.login(loginToken);
|
||||
|
||||
@@ -2,6 +2,7 @@ package emu.nebula.server.handlers;
|
||||
|
||||
import emu.nebula.net.NetHandler;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.Public.ScoreBossLevel;
|
||||
import emu.nebula.proto.ScoreBossInfoOuterClass.ScoreBossInfo;
|
||||
import emu.nebula.net.HandlerId;
|
||||
import emu.nebula.net.GameSession;
|
||||
@@ -15,6 +16,38 @@ public class HandlerScoreBossInfoReq extends NetHandler {
|
||||
var rsp = ScoreBossInfo.newInstance()
|
||||
.setControlId(session.getPlayer().getScoreBossManager().getControlId());
|
||||
|
||||
// Get rank entry
|
||||
var rankEntry = session.getPlayer().getScoreBossManager().getRankEntry();
|
||||
if (rankEntry != null) {
|
||||
// Set total score
|
||||
rsp.setScore(rankEntry.getScore());
|
||||
rsp.setStar(rankEntry.getStars());
|
||||
|
||||
// Encode team data to proto
|
||||
for (var teamEntry : rankEntry.getTeams().entrySet()) {
|
||||
int id = teamEntry.getKey();
|
||||
var team = teamEntry.getValue();
|
||||
|
||||
var info = ScoreBossLevel.newInstance()
|
||||
.setBuildId(team.getBuildId())
|
||||
.setLevelId(id)
|
||||
.setScore(team.getLevelScore())
|
||||
.setSkillScore(team.getSkillScore())
|
||||
.setStar(team.getStars());
|
||||
|
||||
for (var charEntry : team.getCharacters()) {
|
||||
info.addCharIds(charEntry.getId());
|
||||
}
|
||||
|
||||
rsp.addLevels(info);
|
||||
}
|
||||
|
||||
// Add claimed rewards
|
||||
for (int id : rankEntry.getClaimedRewards()) {
|
||||
rsp.addStarRewards(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Encode and send
|
||||
return session.encodeMsg(NetMsgId.score_boss_info_succeed_ack, rsp);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public class HandlerScoreBossRankReq extends NetHandler {
|
||||
.setLastRefreshTime(Nebula.getCurrentTime());
|
||||
|
||||
// Get self
|
||||
var self = session.getPlayer().getScoreBossManager().getRanking();
|
||||
var self = session.getPlayer().getScoreBossManager().getRankEntry();
|
||||
|
||||
if (self != null) {
|
||||
rsp.setSelf(self.toProto());
|
||||
|
||||
@@ -16,7 +16,7 @@ public class HandlerScoreBossSettleReq extends NetHandler {
|
||||
var req = ScoreBossSettleReq.parseFrom(message);
|
||||
|
||||
// Settle
|
||||
boolean success = session.getPlayer().getScoreBossManager().settle(req.getStar(), req.getScore());
|
||||
boolean success = session.getPlayer().getScoreBossManager().settle(req.getStar(), req.getScore(), req.getSkillScore());
|
||||
|
||||
if (success == false) {
|
||||
return session.encodeMsg(NetMsgId.score_boss_settle_failed_ack);
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package emu.nebula.server.handlers;
|
||||
|
||||
import emu.nebula.net.NetHandler;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.ScoreBossStarRewardReceive.ScoreBossStarRewardReceiveReq;
|
||||
import emu.nebula.net.HandlerId;
|
||||
import emu.nebula.net.GameSession;
|
||||
|
||||
@HandlerId(NetMsgId.score_boss_star_reward_receive_req)
|
||||
public class HandlerScoreBossStarRewardReceiveReq extends NetHandler {
|
||||
|
||||
@Override
|
||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||
// Parse request
|
||||
var req = ScoreBossStarRewardReceiveReq.parseFrom(message);
|
||||
|
||||
// Claim rewards
|
||||
var change = session.getPlayer().getScoreBossManager().claimRewards(req.getStar());
|
||||
|
||||
// Encode and send
|
||||
return session.encodeMsg(NetMsgId.score_boss_star_reward_receive_succeed_ack, change.toProto());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,6 +26,9 @@ public class HandlerStarTowerBuildWhetherSaveReq extends NetHandler {
|
||||
return session.encodeMsg(NetMsgId.star_tower_build_whether_save_failed_ack);
|
||||
}
|
||||
|
||||
// Add rewards from game
|
||||
session.getPlayer().getStarTowerManager().addRewards(change);
|
||||
|
||||
// Build response
|
||||
var rsp = StarTowerBuildWhetherSaveResp.newInstance()
|
||||
.setChange(change.toProto());
|
||||
|
||||
@@ -11,7 +11,7 @@ public class HandlerStarTowerGiveUpReq extends NetHandler {
|
||||
|
||||
@Override
|
||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||
var game = session.getPlayer().getStarTowerManager().endGame(false);
|
||||
var game = session.getPlayer().getStarTowerManager().settleGame(false);
|
||||
|
||||
if (game == null) {
|
||||
return session.encodeMsg(NetMsgId.star_tower_give_up_failed_ack);
|
||||
|
||||
@@ -7,7 +7,6 @@ import emu.nebula.proto.WeekBossSettle.WeekBossSettleReq;
|
||||
import emu.nebula.net.HandlerId;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.game.instance.InstanceSettleData;
|
||||
import emu.nebula.game.quest.QuestCondition;
|
||||
import emu.nebula.net.GameSession;
|
||||
|
||||
@HandlerId(NetMsgId.week_boss_settle_req)
|
||||
@@ -28,12 +27,9 @@ public class HandlerWeekBossSettleReq extends NetHandler {
|
||||
var req = WeekBossSettleReq.parseFrom(message);
|
||||
|
||||
// Settle instance
|
||||
var changes = player.getInstanceManager().settleInstance(
|
||||
var changes = player.getInstanceManager().settleWeekly(
|
||||
data,
|
||||
QuestCondition.WeekBoosClearSpecificDifficultyAndTotal,
|
||||
player.getProgress().getWeekBossLog(),
|
||||
"weekBossLog",
|
||||
req.getResult() ? 1 : 0
|
||||
req.getResult()
|
||||
);
|
||||
|
||||
var settleData = (InstanceSettleData) changes.getExtraData();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package emu.nebula.server.routes;
|
||||
|
||||
import emu.nebula.util.JsonUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import emu.nebula.server.HttpServer;
|
||||
@@ -10,21 +11,47 @@ import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class CommonConfigHandler implements Handler {
|
||||
private String osConfig = "{\"Code\":200,\"Data\":{\"AppConfig\":{\"ACCOUNT_RETRIEVAL\":{\"FIRST_LOGIN_POPUP\":false,\"LOGIN_POPUP\":false,\"PAGE_URL\":\"\"},\"AGREEMENT_POPUP_TYPE\":\"Browser\",\"APPLE_CURRENCY_BLOCK_LIST\":null,\"APPLE_TYPE_KEY\":\"apple_hk\",\"APP_CLIENT_LANG\":[\"en\"],\"APP_DEBUG\":0,\"APP_GL\":\"en\",\"BIND_METHOD\":[\"google\",\"apple_hk\",\"facebook\"],\"CAPTCHA_ENABLED\":false,\"CLIENT_LOG_REPORTING\":{\"ENABLE\":false},\"CREDIT_INVESTIGATION\":\"0.0\",\"DESTROY_USER_DAYS\":15,\"DESTROY_USER_ENABLE\":1,\"DETECTION_ADDRESS\":{\"AUTO\":{\"DNS\":[\"${url}\",\"${url}\",\"${url}/meta/serverlist.html\"],\"HTTP\":[\"${url}\",\"${url}\",\"${url}\"],\"MTR\":[\"${url}\",\"${url}\",\"${url}/meta/serverlist.html\"],\"PING\":[\"${url}\",\"${url}\",\"${url}/meta/serverlist.html\"],\"TCP\":[\"${url}\",\"${url}\",\"${url}/meta/serverlist.html\"]},\"ENABLE\":true,\"ENABLE_MANUAL\":true,\"INTERNET\":\"https://www.google.com\",\"INTERNET_ADDRESS\":\"https://www.google.com\",\"NETWORK_ENDPORINT\":\"\",\"NETWORK_PROJECT\":\"\",\"NETWORK_SECRET_KEY\":\"\"},\"ENABLE_AGREEMENT\":true,\"ENABLE_MULTI_LANG_AGREEMENT\":false,\"ENABLE_TEXT_REVIEW\":true,\"ERROR_CODE\":\"4.4\",\"FILE_DOMAIN\":\"\",\"GEETEST_ENABLE\":false,\"GEETEST_ID\":\"\",\"GOOGLE_ANALYTICS_MEASUREMENT_ID\":\"\",\"MIGRATE_POPUP\":true,\"NICKNAME_REG\":\"^[A-Za-z0-9]{2,20}$\",\"POPUP\":{\"Data\":[{\"Lang\":\"ja\",\"Text\":\"YostarIDを作成\"},{\"Lang\":\"en\",\"Text\":\"CreateaYostaraccount\"},{\"Lang\":\"kr\",\"Text\":\"YOSTAR계정가입하기\"},{\"Lang\":\"fr\",\"Text\":\"CréezvotrecompteYostar\"},{\"Lang\":\"de\",\"Text\":\"EinenYostar-Accounterstellen\"}],\"Enable\":true},\"PRIVACY_AGREEMENT\":\"0.1\",\"RECHARGE_LIMIT\":{\"Enable\":false,\"IsOneLimit\":false,\"Items\":[],\"OneLimitAmount\":0},\"SHARE\":{\"CaptureScreen\":{\"AutoCloseDelay\":0,\"Enabled\":false},\"Facebook\":{\"AppID\":\"\",\"Enabled\":false},\"Instagram\":{\"Enabled\":false},\"Kakao\":{\"AppKey\":\"\",\"Enabled\":false},\"Naver\":{\"Enabled\":false},\"Twitter\":{\"Enabled\":false}},\"SLS\":{\"ACCESS_KEY_ID\":\"7b5d0ffd0943f26704fc547a871c68b1b5d56b5c9caeb354205b81f445d7af59\",\"ACCESS_KEY_SECRET\":\"4a5e9cc8a50819290c9bfa1fedc79da7c50e85189a05eb462a3d28a7688eabb0\",\"ENABLE\":false},\"SURVEY_POPUP_TYPE\":\"Browser\",\"UDATA\":{\"Enable\":false,\"URL\":\"${url}\"},\"USER_AGREEMENT\":\"0.1\",\"YOSTAR_PREFIX\":\"yoyo\"},\"EuropeUnion\":false,\"StoreConfig\":{\"ADJUST_APPID\":\"\",\"ADJUST_CHARGEEVENTTOKEN\":\"\",\"ADJUST_ENABLED\":0,\"ADJUST_EVENTTOKENS\":null,\"ADJUST_ISDEBUG\":0,\"AIRWALLEX_ENABLED\":false,\"AI_HELP\":{\"AihelpAppID\":\"yostar1_platform_2db52a57068b1ee3fe3652c8b53d581b\",\"AihelpAppKey\":\"YOSTAR1_app_bc226f4419a7447c9de95711f8a2d3d9\",\"AihelpDomain\":\"yostar1.aihelp.net\",\"CustomerServiceURL\":\"\",\"CustomerWay\":1,\"DisplayType\":\"Browser\",\"Enable\":1,\"Mode\":\"robot\"},\"APPLEID\":\"\",\"CODA_ENABLED\":false,\"ENABLED_PAY\":{\"AIRWALLEX_ENABLED\":false,\"CODA_ENABLED\":false,\"GMOAlipay\":false,\"GMOAu\":false,\"GMOCreditcard\":false,\"GMOCvs\":false,\"GMODocomo\":false,\"GMOPaypal\":false,\"GMOPaypay\":false,\"GMOSoftbank\":false,\"MYCARD_ENABLED\":false,\"PAYPAL_ENABLED\":true,\"RAZER_ENABLED\":false,\"STEAM_ENABLED\":false,\"STRIPE_ENABLED\":true,\"TOSS_ENABLED\":false,\"WEBMONEY_ENABLED\":false},\"FACEBOOK_APPID\":\"\",\"FACEBOOK_CLIENT_TOKEN\":\"\",\"FACEBOOK_SECRET\":\"\",\"FIREBASE_ENABLED\":0,\"GMO_CC_JS\":\"https://\",\"GMO_CC_KEY\":\"\",\"GMO_CC_SHOPID\":\"\",\"GMO_PAY_CHANNEL\":{\"GMOAlipay\":false,\"GMOAu\":false,\"GMOCreditcard\":false,\"GMOCvs\":false,\"GMODocomo\":false,\"GMOPaypal\":false,\"GMOPaypay\":false,\"GMOSoftbank\":false},\"GMO_PAY_ENABLED\":false,\"GOOGLE_CLIENT_ID\":\"\",\"GOOGLE_CLIENT_SECRET\":\"\",\"GUEST_CREATE_METHOD\":0,\"GUIDE_POPUP\":{\"DATA\":null,\"ENABLE\":0},\"LOGIN\":{\"DEFAULT\":\"yostar\",\"ICON_SIZE\":\"big\",\"SORT\":[\"google\",\"apple\",\"device\"]},\"MYCARD_ENABLED\":false,\"ONE_STORE_LICENSE_KEY\":\"\",\"PAYPAL_ENABLED\":false,\"RAZER_ENABLED\":false,\"REMOTE_CONFIG\":[],\"SAMSUNG_SANDBOX_MODE\":false,\"STEAM_APPID\":\"\",\"STEAM_ENABLED\":false,\"STEAM_PAY_APPID\":\"\",\"STRIPE_ENABLED\":false,\"TOSS_ENABLED\":false,\"TWITTER_KEY\":\"\",\"TWITTER_SECRET\":\"\",\"WEBMONEY_ENABLED\":false}},\"Msg\":\"OK\"}";
|
||||
private String cnConfig = "{\"Code\":200,\"Data\":{\"AppConfig\":{\"AppropriateAge\":{\"Level\":\"18+\",\"Msg\":\"《星塔旅人》游戏适龄提示\\n1、本游戏是一款玩法简单的角色扮演游戏,适用于年满18周岁及以上的用户。\\n2、本游戏基于架空的故事背景和幻想世界观,剧情简单且积极向上,没有基于真实历史和现实事件的改编内容。游戏玩法基于肢体操作,鼓励玩家通过训练达成目标。游戏中有少量自定义文字系统,该社交系统遵循相关法律法规进行管理。\\n3、本游戏中有用户实名认证系统,对年满18周岁及以上的用户开放,使用18周岁以下的身份信息认证账号将无法进入游戏。\"},\"Captcha\":{\"AppID\":191947906,\"Enable\":true},\"DestroyUser\":{\"Days\":15,\"Enable\":true},\"DetectionAddress\":{\"Auto\":{\"DNS\":[\"${url}/meta/serverlist.html\",\"${url}\"],\"HTTP\":[\"${url}/meta/serverlist.html\",\"${url}\"],\"MTR\":[\"${url}/meta/serverlist.html\",\"${url}\"],\"PING\":[\"${url}/meta/serverlist.html\",\"${url}\"],\"TCP\":[\"${url}/meta/serverlist.html\",\"${url}\"]},\"Enable\":true,\"Internet\":\"https://www.baidu.com\"},\"EnableTextReview\":true,\"NicknameReg\":\"^[A-Za-z0-9一-龥]{2,16}$\",\"Passport\":{\"AuthCodeCoolDownDays\":90,\"AuthCodeValidHour\":48,\"DestroyDays\":15,\"ModifyEmailDays\":30,\"ModifyMobileDays\":30,\"Prefix\":\"YS\"},\"PassportPopup\":{\"Enable\":false,\"Text\":\"\"},\"SLS\":{\"AccessKeyID\":\"7b5d0ffd0943f26704fc547a871c68b1b5d56b5c9caeb354205b81f445d7af59\",\"AccessKeySecret\":\"4a5e9cc8a50819290c9bfa1fedc79da7c50e85189a05eb462a3d28a7688eabb0\",\"ENABLE\":true},\"Share\":{\"CaptureScreen\":{\"AutoCloseDelay\":0,\"Enabled\":false},\"PengYouQuan\":{\"AppID\":\"\",\"Enabled\":false,\"UniversalLink\":\"\"},\"QQ\":{\"AppID\":\"\",\"Enabled\":false,\"UniversalLink\":\"\"},\"Qzone\":{\"AppID\":\"\",\"Enabled\":false,\"UniversalLink\":\"\"},\"Sort\":null,\"WeiXin\":{\"AppID\":\"\",\"Enabled\":false,\"UniversalLink\":\"\"},\"Weibo\":{\"AppKey\":\"\",\"Enabled\":false,\"RedirectURL\":\"\",\"UniversalLink\":\"\"}},\"ThirdInfoShareList\":\"https://${url}/cn-nova/shared_list\",\"Version\":{\"ChildPrivacyAgreement\":\"0.1\",\"ErrorCode\":\"5.3\",\"PassportPrivacyAgreement\":\"0.1\",\"PassportUserAgreement\":\"0.1\",\"PrivacyAgreement\":\"0.1\",\"UserAgreement\":\"0.1\",\"UserDestroy\":\"0.1\"}},\"ChannelConfig\":{\"Adjust\":{\"AppID\":\"\",\"Debug\":false,\"Enable\":false,\"EventTokens\":null},\"AiHelp\":{\"DisplayType\":\"WebView\",\"Enable\":true,\"ServiceInterfaceURL\":\"https://customer.yostar.net/\",\"ServiceURL\":\"https://customer-pc.yostar.net/#/\"},\"AntiAddiction\":{\"Enable\":true},\"Debug\":1,\"JPush\":{\"Debug\":false,\"Key\":\"\"},\"Login\":{\"Default\":\"mobile\",\"EnableList\":[\"mobile\",\"taptap\"]},\"OneKeyLoginSecret\":\"5c222d7c997339c921bd4fdcb7549ab4\",\"Taptap\":{\"ClientID\":\"9aeghiagor7hp43smv\",\"ClientPublicKey\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwp10sKQjAn+kxSxZebHBgl3Tuqjapxdtqzy68y2CPzELHVeBQpK6jPnHyjvZcpgsW3/Rr4hyzPsxMHp7akNRfkOy2jqEGl/2hDeYpSsvK4vw9triXz4DTLESpU+RWfTglf3LRHB76RJggcGw0Pt+QAItHlOMQH+9LBuWtnS+bcf2YD+kC4jTmvr2dB6i3dhyaorVuT2OfnTRDZREU0WauWdACWHyaUELwA/JfZW+ir88k++qEjxaq76avRXzfJ0SuA8lqJKRirBc4dgMLvpjpjy1mVV3us64fSyAYwqUFCFNT5HT4/MMCbD4YZs20pgT8sUG04kbxlA1qu6sIh2BHwIDAQAB\",\"ClientToken\":\"ENWpPiooc3lI3ZNVNQNOXWZ7dE4YrVOsbMY7b1Li\"},\"Udata\":{\"Enable\":true}}},\"Msg\":\"OK\"}";
|
||||
|
||||
private HttpServer server;
|
||||
private String json;
|
||||
|
||||
public CommonConfigHandler(HttpServer server) {
|
||||
this.server = server;
|
||||
this.json = "{\"Code\":200,\"Data\":{\"AppConfig\":{\"ACCOUNT_RETRIEVAL\":{\"FIRST_LOGIN_POPUP\":false,\"LOGIN_POPUP\":false,\"PAGE_URL\":\"\"},\"AGREEMENT_POPUP_TYPE\":\"Browser\",\"APPLE_CURRENCY_BLOCK_LIST\":null,\"APPLE_TYPE_KEY\":\"apple_hk\",\"APP_CLIENT_LANG\":[\"en\"],\"APP_DEBUG\":0,\"APP_GL\":\"en\",\"BIND_METHOD\":[\"google\",\"apple_hk\",\"facebook\"],\"CAPTCHA_ENABLED\":false,\"CLIENT_LOG_REPORTING\":{\"ENABLE\":false},\"CREDIT_INVESTIGATION\":\"0.0\",\"DESTROY_USER_DAYS\":15,\"DESTROY_USER_ENABLE\":1,\"DETECTION_ADDRESS\":{\"AUTO\":{\"DNS\":[\"${url}\",\"${url}\",\"${url}/meta/serverlist.html\"],\"HTTP\":[\"${url}\",\"${url}\",\"${url}\"],\"MTR\":[\"${url}\",\"${url}\",\"${url}/meta/serverlist.html\"],\"PING\":[\"${url}\",\"${url}\",\"${url}/meta/serverlist.html\"],\"TCP\":[\"${url}\",\"${url}\",\"${url}/meta/serverlist.html\"]},\"ENABLE\":true,\"ENABLE_MANUAL\":true,\"INTERNET\":\"https://www.google.com\",\"INTERNET_ADDRESS\":\"https://www.google.com\",\"NETWORK_ENDPORINT\":\"\",\"NETWORK_PROJECT\":\"\",\"NETWORK_SECRET_KEY\":\"\"},\"ENABLE_AGREEMENT\":true,\"ENABLE_MULTI_LANG_AGREEMENT\":false,\"ENABLE_TEXT_REVIEW\":true,\"ERROR_CODE\":\"4.4\",\"FILE_DOMAIN\":\"\",\"GEETEST_ENABLE\":false,\"GEETEST_ID\":\"\",\"GOOGLE_ANALYTICS_MEASUREMENT_ID\":\"\",\"MIGRATE_POPUP\":true,\"NICKNAME_REG\":\"^[A-Za-z0-9]{2,20}$\",\"POPUP\":{\"Data\":[{\"Lang\":\"ja\",\"Text\":\"YostarIDを作成\"},{\"Lang\":\"en\",\"Text\":\"CreateaYostaraccount\"},{\"Lang\":\"kr\",\"Text\":\"YOSTAR계정가입하기\"},{\"Lang\":\"fr\",\"Text\":\"CréezvotrecompteYostar\"},{\"Lang\":\"de\",\"Text\":\"EinenYostar-Accounterstellen\"}],\"Enable\":true},\"PRIVACY_AGREEMENT\":\"0.1\",\"RECHARGE_LIMIT\":{\"Enable\":false,\"IsOneLimit\":false,\"Items\":[],\"OneLimitAmount\":0},\"SHARE\":{\"CaptureScreen\":{\"AutoCloseDelay\":0,\"Enabled\":false},\"Facebook\":{\"AppID\":\"\",\"Enabled\":false},\"Instagram\":{\"Enabled\":false},\"Kakao\":{\"AppKey\":\"\",\"Enabled\":false},\"Naver\":{\"Enabled\":false},\"Twitter\":{\"Enabled\":false}},\"SLS\":{\"ACCESS_KEY_ID\":\"7b5d0ffd0943f26704fc547a871c68b1b5d56b5c9caeb354205b81f445d7af59\",\"ACCESS_KEY_SECRET\":\"4a5e9cc8a50819290c9bfa1fedc79da7c50e85189a05eb462a3d28a7688eabb0\",\"ENABLE\":false},\"SURVEY_POPUP_TYPE\":\"Browser\",\"UDATA\":{\"Enable\":false,\"URL\":\"${url}\"},\"USER_AGREEMENT\":\"0.1\",\"YOSTAR_PREFIX\":\"yoyo\"},\"EuropeUnion\":false,\"StoreConfig\":{\"ADJUST_APPID\":\"\",\"ADJUST_CHARGEEVENTTOKEN\":\"\",\"ADJUST_ENABLED\":0,\"ADJUST_EVENTTOKENS\":null,\"ADJUST_ISDEBUG\":0,\"AIRWALLEX_ENABLED\":false,\"AI_HELP\":{\"AihelpAppID\":\"yostar1_platform_2db52a57068b1ee3fe3652c8b53d581b\",\"AihelpAppKey\":\"YOSTAR1_app_bc226f4419a7447c9de95711f8a2d3d9\",\"AihelpDomain\":\"yostar1.aihelp.net\",\"CustomerServiceURL\":\"\",\"CustomerWay\":1,\"DisplayType\":\"Browser\",\"Enable\":1,\"Mode\":\"robot\"},\"APPLEID\":\"\",\"CODA_ENABLED\":false,\"ENABLED_PAY\":{\"AIRWALLEX_ENABLED\":false,\"CODA_ENABLED\":false,\"GMOAlipay\":false,\"GMOAu\":false,\"GMOCreditcard\":false,\"GMOCvs\":false,\"GMODocomo\":false,\"GMOPaypal\":false,\"GMOPaypay\":false,\"GMOSoftbank\":false,\"MYCARD_ENABLED\":false,\"PAYPAL_ENABLED\":true,\"RAZER_ENABLED\":false,\"STEAM_ENABLED\":false,\"STRIPE_ENABLED\":true,\"TOSS_ENABLED\":false,\"WEBMONEY_ENABLED\":false},\"FACEBOOK_APPID\":\"\",\"FACEBOOK_CLIENT_TOKEN\":\"\",\"FACEBOOK_SECRET\":\"\",\"FIREBASE_ENABLED\":0,\"GMO_CC_JS\":\"https://\",\"GMO_CC_KEY\":\"\",\"GMO_CC_SHOPID\":\"\",\"GMO_PAY_CHANNEL\":{\"GMOAlipay\":false,\"GMOAu\":false,\"GMOCreditcard\":false,\"GMOCvs\":false,\"GMODocomo\":false,\"GMOPaypal\":false,\"GMOPaypay\":false,\"GMOSoftbank\":false},\"GMO_PAY_ENABLED\":false,\"GOOGLE_CLIENT_ID\":\"\",\"GOOGLE_CLIENT_SECRET\":\"\",\"GUEST_CREATE_METHOD\":0,\"GUIDE_POPUP\":{\"DATA\":null,\"ENABLE\":0},\"LOGIN\":{\"DEFAULT\":\"yostar\",\"ICON_SIZE\":\"big\",\"SORT\":[\"google\",\"apple\",\"device\"]},\"MYCARD_ENABLED\":false,\"ONE_STORE_LICENSE_KEY\":\"\",\"PAYPAL_ENABLED\":false,\"RAZER_ENABLED\":false,\"REMOTE_CONFIG\":[],\"SAMSUNG_SANDBOX_MODE\":false,\"STEAM_APPID\":\"\",\"STEAM_ENABLED\":false,\"STEAM_PAY_APPID\":\"\",\"STRIPE_ENABLED\":false,\"TOSS_ENABLED\":false,\"TWITTER_KEY\":\"\",\"TWITTER_SECRET\":\"\",\"WEBMONEY_ENABLED\":false}},\"Msg\":\"OK\"}";
|
||||
|
||||
|
||||
String address = server.getServerConfig().getDisplayAddress();
|
||||
this.json = this.json.replaceAll("\\$\\{url}", address);
|
||||
this.osConfig = this.osConfig.replaceAll("\\$\\{url}", address);
|
||||
this.cnConfig = this.cnConfig.replaceAll("\\$\\{url}", address);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(@NotNull Context ctx) throws Exception {
|
||||
ctx.contentType(ContentType.APPLICATION_JSON);
|
||||
ctx.result(this.json);
|
||||
|
||||
String Channel = "";
|
||||
var req = JsonUtils.decode(ctx.header("Authorization"), authDataJson.class);
|
||||
|
||||
if (req != null) {
|
||||
Channel = req.Head.Channel;
|
||||
}
|
||||
|
||||
if (Channel != null && Channel.equals("official")) {
|
||||
// cn
|
||||
ctx.result(cnConfig);
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.result(osConfig);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class authDataJson {
|
||||
public handJson Head;
|
||||
public String Sign;
|
||||
|
||||
protected static class handJson {
|
||||
public String Channel;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,14 +2,13 @@ package emu.nebula.server.routes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.server.routes.entity.ChinaUserLoginEntity;
|
||||
import emu.nebula.server.routes.entity.OverseaUserLoginEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import emu.nebula.game.account.Account;
|
||||
import emu.nebula.game.account.AccountHelper;
|
||||
import emu.nebula.server.routes.UserLoginEntity.LoginYostarJson;
|
||||
import emu.nebula.server.routes.UserLoginEntity.UserDetailJson;
|
||||
import emu.nebula.server.routes.UserLoginEntity.UserInfoJson;
|
||||
import emu.nebula.server.routes.UserLoginEntity.UserKeyJson;
|
||||
import emu.nebula.util.JsonUtils;
|
||||
import io.javalin.http.ContentType;
|
||||
import io.javalin.http.Context;
|
||||
@@ -29,54 +28,120 @@ public class UserLoginHandler implements Handler {
|
||||
account = this.getAccountFromBody(ctx);
|
||||
}
|
||||
|
||||
// Check
|
||||
if (account == null) {
|
||||
ctx.contentType(ContentType.APPLICATION_JSON);
|
||||
ctx.result("{\"Code\":100403,\"Data\":{},\"Msg\":\"Error\"}"); // TOKEN_AUTH_FAILED
|
||||
return;
|
||||
}
|
||||
|
||||
// Create response
|
||||
var response = new UserLoginEntity();
|
||||
|
||||
response.Code = 200;
|
||||
response.Msg = "OK";
|
||||
response.Data = new UserDetailJson();
|
||||
response.Data.Keys = new ArrayList<>();
|
||||
response.Data.UserInfo = new UserInfoJson();
|
||||
response.Data.Yostar = new LoginYostarJson();
|
||||
|
||||
response.Data.UserInfo.ID = account.getUid();
|
||||
response.Data.UserInfo.UID2 = 0;
|
||||
response.Data.UserInfo.PID = "NEBULA";
|
||||
response.Data.UserInfo.Token = account.getLoginToken();
|
||||
response.Data.UserInfo.Birthday = "";
|
||||
response.Data.UserInfo.RegChannel = "pc";
|
||||
response.Data.UserInfo.TransCode = "";
|
||||
response.Data.UserInfo.State = 1;
|
||||
response.Data.UserInfo.DeviceID = "";
|
||||
response.Data.UserInfo.CreatedAt = account.getCreatedAt();
|
||||
|
||||
response.Data.Yostar.ID = account.getUid();
|
||||
response.Data.Yostar.Country = "US";
|
||||
response.Data.Yostar.Nickname = account.getNickname();
|
||||
response.Data.Yostar.Picture = account.getPicture();
|
||||
response.Data.Yostar.State = 1;
|
||||
response.Data.Yostar.AgreeAd = 0;
|
||||
response.Data.Yostar.CreatedAt = account.getCreatedAt();
|
||||
|
||||
var key = new UserKeyJson();
|
||||
key.ID = account.getUid();
|
||||
key.Type = "yostar";
|
||||
key.Key = account.getEmail();
|
||||
key.NickName = account.getEmail();
|
||||
key.CreatedAt = account.getCreatedAt();
|
||||
|
||||
response.Data.Keys.add(key);
|
||||
|
||||
// Result
|
||||
ctx.contentType(ContentType.APPLICATION_JSON);
|
||||
ctx.result(JsonUtils.encode(response, true));
|
||||
ctx.result(getJsonResult(ctx, account));
|
||||
}
|
||||
|
||||
private String getJsonResult(Context ctx, Account account) {
|
||||
if (account == null) {
|
||||
return "{\"Code\":100403,\"Data\":{},\"Msg\":\"Error\"}";
|
||||
}
|
||||
|
||||
String Channel = "";
|
||||
var req = JsonUtils.decode(ctx.header("Authorization"), UserAuthDataJson.class);
|
||||
|
||||
if (req != null) {
|
||||
Channel = req.Head.Channel;
|
||||
}
|
||||
|
||||
String token = account.getLoginToken();
|
||||
if (token == null || token.isEmpty()) {
|
||||
account.generateLoginToken();
|
||||
}
|
||||
|
||||
String nickName = account.getNickname();
|
||||
if (nickName == null || nickName.isEmpty()) {
|
||||
account.setNickname(account.getEmail());
|
||||
}
|
||||
|
||||
// Check if it's a CN channel
|
||||
// The data required by CN channels is somewhat different from other regional servers
|
||||
if (Channel != null && Channel.equals("official")) {
|
||||
// CN
|
||||
var response = new ChinaUserLoginEntity();
|
||||
|
||||
response.Code = 200;
|
||||
response.Msg = "OK";
|
||||
response.Data = new ChinaUserLoginEntity.UserDetailJson();
|
||||
response.Data.IsNew = false;
|
||||
response.Data.IsTestAccount = false;
|
||||
response.Data.Keys = new ArrayList<>();
|
||||
response.Data.User = new ChinaUserLoginEntity.UserJson();
|
||||
response.Data.Yostar = new ChinaUserLoginEntity.LoginYostarJson();
|
||||
response.Data.Identity = new ChinaUserLoginEntity.IdentityJson();
|
||||
response.Data.TaptapProfile = null;
|
||||
|
||||
response.Data.User.ID = Long.parseLong(account.getUid());
|
||||
response.Data.User.PID = "NEBULA";
|
||||
response.Data.User.Token = account.getLoginToken();
|
||||
response.Data.User.State = 1;
|
||||
response.Data.User.RegChannel = "pc_official";
|
||||
response.Data.User.DestroyState = 0;
|
||||
|
||||
response.Data.Yostar.ID = Long.parseLong(account.getUid());
|
||||
response.Data.Yostar.NickName = account.getNickname();
|
||||
response.Data.Yostar.Picture = account.getPicture();
|
||||
response.Data.Yostar.State = 1;
|
||||
response.Data.Yostar.CreatedAt = account.getCreatedAt();
|
||||
response.Data.Yostar.DefaultNickName = "";
|
||||
|
||||
response.Data.Identity.Type = 0;
|
||||
response.Data.Identity.RealName = "***";
|
||||
response.Data.Identity.IDCard = "******************";
|
||||
response.Data.Identity.Underage = false;
|
||||
response.Data.Identity.PI = "";
|
||||
response.Data.Identity.BirthDate = "";
|
||||
response.Data.Identity.State = 1;
|
||||
|
||||
var key = new ChinaUserLoginEntity.UserKeyJson();
|
||||
key.Type = "mobile";
|
||||
key.NickName = account.getEmail();
|
||||
key.NickNameEnc = "";
|
||||
|
||||
response.Data.Keys.add(key);
|
||||
return JsonUtils.encode(response, true);
|
||||
} else {
|
||||
// OS
|
||||
var response = new OverseaUserLoginEntity();
|
||||
|
||||
response.Code = 200;
|
||||
response.Msg = "OK";
|
||||
response.Data = new OverseaUserLoginEntity.UserDetailJson();
|
||||
response.Data.Keys = new ArrayList<>();
|
||||
response.Data.UserInfo = new OverseaUserLoginEntity.UserInfoJson();
|
||||
response.Data.Yostar = new OverseaUserLoginEntity.LoginYostarJson();
|
||||
|
||||
response.Data.UserInfo.ID = account.getUid();
|
||||
response.Data.UserInfo.UID2 = 0;
|
||||
response.Data.UserInfo.PID = "NEBULA";
|
||||
response.Data.UserInfo.Token = account.getLoginToken();
|
||||
response.Data.UserInfo.Birthday = "";
|
||||
response.Data.UserInfo.RegChannel = "pc";
|
||||
response.Data.UserInfo.TransCode = "";
|
||||
response.Data.UserInfo.State = 1;
|
||||
response.Data.UserInfo.DeviceID = "";
|
||||
response.Data.UserInfo.CreatedAt = account.getCreatedAt();
|
||||
|
||||
response.Data.Yostar.ID = account.getUid();
|
||||
response.Data.Yostar.Country = "US";
|
||||
response.Data.Yostar.Nickname = account.getNickname();
|
||||
response.Data.Yostar.Picture = account.getPicture();
|
||||
response.Data.Yostar.State = 1;
|
||||
response.Data.Yostar.AgreeAd = 0;
|
||||
response.Data.Yostar.CreatedAt = account.getCreatedAt();
|
||||
|
||||
var key = new OverseaUserLoginEntity.UserKeyJson();
|
||||
key.ID = account.getUid();
|
||||
key.Type = "yostar";
|
||||
key.Key = account.getEmail();
|
||||
key.NickName = account.getEmail();
|
||||
key.CreatedAt = account.getCreatedAt();
|
||||
|
||||
response.Data.Keys.add(key);
|
||||
|
||||
return JsonUtils.encode(response, true);
|
||||
}
|
||||
}
|
||||
|
||||
protected Account getAccountFromBody(Context ctx) {
|
||||
@@ -86,9 +151,32 @@ public class UserLoginHandler implements Handler {
|
||||
if (req == null || req.OpenID == null || req.Token == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Account account = AccountHelper.getAccountByLoginToken(req.Token);
|
||||
|
||||
if (account != null) return account;
|
||||
|
||||
// In CN region, login method is mobile phone + MFA verification code
|
||||
// OpenID is mobile phone number, Token is a six-digit verification code
|
||||
// These are stored in the body
|
||||
{
|
||||
// CN region requires an OpenID query
|
||||
account = AccountHelper.getAccountByEmail(req.OpenID);
|
||||
if (account == null) {
|
||||
// Create an account if were allowed to
|
||||
if (Nebula.getConfig().getServerOptions().isAutoCreateAccount()) {
|
||||
account = AccountHelper.createAccount(req.OpenID, null, 0);
|
||||
}
|
||||
} else {
|
||||
// Check passcode sent by email
|
||||
if (!account.verifyCode(req.Token)) {
|
||||
account = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get account
|
||||
return AccountHelper.getAccountByLoginToken(req.Token);
|
||||
return account;
|
||||
}
|
||||
|
||||
protected Account getAccountFromHeader(Context ctx) {
|
||||
@@ -121,6 +209,7 @@ public class UserLoginHandler implements Handler {
|
||||
protected static class UserAuthHeadJson {
|
||||
public String UID;
|
||||
public String Token;
|
||||
public String Channel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,8 +31,9 @@ public class UserSetDataHandler extends UserLoginHandler {
|
||||
ctx.result("{\"Code\":100110,\"Data\":{},\"Msg\":\"Error\"}"); // VALID_FAIL
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.Key.equals("Nickname")) {
|
||||
|
||||
// OS uses the former, CN uses the latter
|
||||
if (req.Key.equals("Nickname") || req.Key.equals("nickname")) {
|
||||
account.setNickname(req.Value);
|
||||
account.save();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package emu.nebula.server.routes.entity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class ChinaUserLoginEntity {
|
||||
public int Code;
|
||||
public UserDetailJson Data;
|
||||
public String Msg;
|
||||
|
||||
public static class UserDetailJson {
|
||||
public Object Destroy;
|
||||
public Object YostarDestroy;
|
||||
|
||||
public boolean IsNew;
|
||||
public boolean IsTestAccount;
|
||||
public List<UserKeyJson> Keys;
|
||||
public UserJson User;
|
||||
public LoginYostarJson Yostar;
|
||||
public Object TaptapProfile;
|
||||
public IdentityJson Identity;
|
||||
}
|
||||
|
||||
public static class UserJson {
|
||||
public long ID;
|
||||
public String PID;
|
||||
public String Token;
|
||||
public int State;
|
||||
public String RegChannel;
|
||||
public int DestroyState;
|
||||
}
|
||||
|
||||
public static class UserKeyJson {
|
||||
public String Type;
|
||||
public String NickName;
|
||||
public String NickNameEnc;
|
||||
}
|
||||
|
||||
public static class LoginYostarJson {
|
||||
public long ID;
|
||||
public String NickName;
|
||||
public String Picture;
|
||||
public int State;
|
||||
public long CreatedAt;
|
||||
public String DefaultNickName;
|
||||
}
|
||||
|
||||
public static class IdentityJson {
|
||||
public int Type;
|
||||
public String RealName;
|
||||
public String IDCard;
|
||||
public boolean Underage;
|
||||
public String PI;
|
||||
public String BirthDate;
|
||||
public int State;
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package emu.nebula.server.routes;
|
||||
package emu.nebula.server.routes.entity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class UserLoginEntity {
|
||||
public class OverseaUserLoginEntity {
|
||||
public int Code;
|
||||
public UserDetailJson Data;
|
||||
public String Msg;
|
||||
@@ -49,6 +49,10 @@ public class AeadHelper {
|
||||
RegionConfig.getRegion("tw")
|
||||
.setServerMetaKey("owGYVDmfHrxi^4pm")
|
||||
.setServerGarbleKey("N&mfco452ZH5!nE3s&o5uxB57UGPENVo");
|
||||
|
||||
RegionConfig.getRegion("cn")
|
||||
.setServerMetaKey("Xf&FRcsYm48cJ2A@")
|
||||
.setServerGarbleKey("QW*Wi7fKjLk!T82Qf2nEGZA%nSC!D9qV");
|
||||
}
|
||||
|
||||
public static void loadKeys() {
|
||||
|
||||
@@ -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