返回提交历史
Modified
config-vanilla.json
+1
-0
Modified
src/services/configService.ts
+1
-0
Modified
src/services/worldStateService.ts
+103
-123
Modified
src/types/worldStateTypes.ts
+8
-3
Modified
static/webui/index.html
+8
-0
Modified
static/webui/translations/de.js
+1
-0
Modified
static/webui/translations/en.js
+1
-0
Modified
static/webui/translations/es.js
+1
-0
Modified
static/webui/translations/fr.js
+1
-0
Modified
static/webui/translations/ru.js
+1
-0
Modified
static/webui/translations/uk.js
+1
-0
Modified
static/webui/translations/zh.js
+1
-0
XFEstudio/XFESpaceNinjaServer
feat: St. Patrick’s Day FlashSales (#3446)
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3446 Reviewed-by: Sainan <63328889+sainan@users.noreply.github.com> Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
e782ef6a
代码差异
12 个文件
+128
-126
@@ -72,6 +72,7 @@
72
72
"ghoulEmergenceOverride": null,
73
73
"plagueStarOverride": null,
74
74
"starDaysOverride": null,
75
"saintPatrickOverride": null,
75
76
"dogDaysOverride": null,
76
77
"dogDaysRewardsOverride": null,
77
78
"bellyOfTheBeast": false,
@@ -84,6 +84,7 @@ export interface IConfig {
84
84
ghoulEmergenceOverride?: boolean;
85
85
plagueStarOverride?: boolean;
86
86
starDaysOverride?: boolean;
87
saintPatrickOverride?: boolean;
87
88
dogDaysOverride?: boolean;
88
89
dogDaysRewardsOverride?: number;
89
90
bellyOfTheBeast?: boolean;
@@ -1897,16 +1897,16 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
1897
1897
}
1898
1898
1899
1899
if (config.worldState?.qtccAlerts) {
1900
const activationTimeStamp = "1759327200000";
1901
const expiryTimeStamp = "2000000000000";
1900
const activation = 1759327200000;
1901
const expiry = 2000000000000;
1902
1902
1903
1903
worldState.Alerts.push(
1904
1904
{
1905
1905
_id: {
1906
1906
$oid: "68dc23c42e9d3acfa708ff3b"
1907
1907
},
1908
Activation: { $date: { $numberLong: activationTimeStamp } },
1909
Expiry: { $date: { $numberLong: expiryTimeStamp } },
1908
Activation: { $date: { $numberLong: activation.toString() } },
1909
Expiry: { $date: { $numberLong: expiry.toString() } },
1910
1910
MissionInfo: {
1911
1911
location: "SolNode123",
1912
1912
missionType: "MT_SURVIVAL",
@@ -1930,8 +1930,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
1930
1930
_id: {
1931
1931
$oid: "68dc2466e298b4f04206687a"
1932
1932
},
1933
Activation: { $date: { $numberLong: activationTimeStamp } },
1934
Expiry: { $date: { $numberLong: expiryTimeStamp } },
1933
Activation: { $date: { $numberLong: activation.toString() } },
1934
Expiry: { $date: { $numberLong: expiry.toString() } },
1935
1935
MissionInfo: {
1936
1936
location: "SolNode149",
1937
1937
missionType: "MT_DEFENSE",
@@ -1955,8 +1955,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
1955
1955
_id: {
1956
1956
$oid: "68dc26865e7cb56b820b4252"
1957
1957
},
1958
Activation: { $date: { $numberLong: activationTimeStamp } },
1959
Expiry: { $date: { $numberLong: expiryTimeStamp } },
1958
Activation: { $date: { $numberLong: activation.toString() } },
1959
Expiry: { $date: { $numberLong: expiry.toString() } },
1960
1960
MissionInfo: {
1961
1961
location: "SolNode39",
1962
1962
missionType: "MT_EXCAVATE",
@@ -2007,42 +2007,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
2007
2007
{ TypeName: "/Lotus/Types/Items/ShipDecos/Plushies/PlushyProtectorStalker", PremiumOverride: 35 }
2008
2008
];
2009
2009
2010
worldState.FlashSales.push(
2011
...storeItems.map(item => ({
2012
...{
2013
StartDate: { $date: { $numberLong: activationTimeStamp } },
2014
EndDate: { $date: { $numberLong: expiryTimeStamp } },
2015
ProductExpiryOverride: { $date: { $numberLong: expiryTimeStamp } },
2016
ShowInMarket: item.ShowInMarket ?? true,
2017
HideFromMarket: item.HideFromMarket ?? false,
2018
SupporterPack: item.SupporterPack ?? false,
2019
Discount: item.Discount ?? 0,
2020
BogoBuy: item.BogoBuy ?? 0,
2021
BogoGet: item.BogoGet ?? 0,
2022
RegularOverride: item.RegularOverride ?? 0,
2023
PremiumOverride: item.PremiumOverride ?? 0
2024
},
2025
...item
2026
}))
2027
);
2028
2029
const seasonalItems = storeItems.map(item => item.TypeName);
2030
2031
const seasonalCategory = worldState.InGameMarket.LandingPage.Categories.find(
2032
c => c.CategoryName == "COMMUNITY"
2033
);
2034
if (seasonalCategory) {
2035
seasonalCategory.Items ??= [];
2036
seasonalCategory.Items.push(...seasonalItems);
2037
} else {
2038
worldState.InGameMarket.LandingPage.Categories.push({
2039
CategoryName: "COMMUNITY",
2040
Name: "/Lotus/Language/Store/CommunityCategoryTitle",
2041
Icon: "community",
2042
AddToMenu: true,
2043
Items: seasonalItems
2044
});
2045
}
2010
pushFlashSales(worldState, storeItems, activation, expiry, "COMMUNITY", buildLabel);
2046
2011
}
2047
2012
2048
2013
const isFebruary = date.getUTCMonth() == 1;
@@ -2238,8 +2203,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
2238
2203
buildLabel &&
2239
2204
version_compare(buildLabel, gameToBuildVersion["25.7.0"]) >= 0
2240
2205
) {
2241
const activationTimeStamp = config.worldState?.dogDaysOverride ? "1699372800000" : dogDaysStart.toString();
2242
const expiryTimeStamp = config.worldState?.dogDaysOverride ? "2000000000000" : dogDaysEnd.toString();
2206
const activation = config.worldState?.dogDaysOverride ? 1699372800000 : dogDaysStart;
2207
const expiry = config.worldState?.dogDaysOverride ? 2000000000000 : dogDaysEnd;
2243
2208
const rewards = [
2244
2209
[
2245
2210
{
@@ -2396,8 +2361,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
2396
2361
"c57487c3768936d" +
2397
2362
year.toString(16)
2398
2363
},
2399
Activation: { $date: { $numberLong: activationTimeStamp } },
2400
Expiry: { $date: { $numberLong: expiryTimeStamp } },
2364
Activation: { $date: { $numberLong: activation.toString() } },
2365
Expiry: { $date: { $numberLong: expiry.toString() } },
2401
2366
Count: 0,
2402
2367
Goal: 100,
2403
2368
InterimGoals: [25, 50],
@@ -2441,43 +2406,30 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
2441
2406
{ TypeName: "/Lotus/Types/StoreItems/SuitCustomizations/ColourPickerRollers", PremiumOverride: 75 }
2442
2407
];
2443
2408
2444
worldState.FlashSales.push(
2445
...storeItems.map(item => ({
2446
...{
2447
StartDate: { $date: { $numberLong: activationTimeStamp } },
2448
EndDate: { $date: { $numberLong: expiryTimeStamp } },
2449
ProductExpiryOverride: { $date: { $numberLong: expiryTimeStamp } },
2450
ShowInMarket: item.ShowInMarket ?? true,
2451
HideFromMarket: item.HideFromMarket ?? false,
2452
SupporterPack: item.SupporterPack ?? false,
2453
Discount: item.Discount ?? 0,
2454
BogoBuy: item.BogoBuy ?? 0,
2455
BogoGet: item.BogoGet ?? 0,
2456
RegularOverride: item.RegularOverride ?? 0,
2457
PremiumOverride: item.PremiumOverride ?? 0
2458
},
2459
...item
2460
}))
2461
);
2409
pushFlashSales(worldState, storeItems, activation, expiry, "SEASONAL", buildLabel);
2410
}
2462
2411
2463
const seasonalItems = storeItems.map(item => item.TypeName);
2412
// there no strict start day so lets pick first march monday
2413
const firstMarchWeekday = new Date(Date.UTC(date.getUTCFullYear(), 2, 1)).getUTCDay();
2414
const firstMarchMondayOffset = (8 - firstMarchWeekday) % 7;
2464
2415
2465
const seasonalCategory = worldState.InGameMarket.LandingPage.Categories.find(c => c.CategoryName == "SEASONAL");
2416
const saintPatrickStart = Date.UTC(date.getUTCFullYear(), 2, firstMarchMondayOffset + 1, 16);
2417
const saintPatrickEnd = Date.UTC(date.getUTCFullYear(), 2, firstMarchMondayOffset + 22, 16);
2466
2418
2467
if (seasonalCategory) {
2468
seasonalCategory.Items ??= [];
2469
seasonalCategory.Items.push(...seasonalItems);
2470
} else {
2471
worldState.InGameMarket.LandingPage.Categories.push({
2472
CategoryName: "SEASONAL",
2473
Name: "/Lotus/Language/Store/SeasonalCategoryTitle",
2474
Icon: "seasonal",
2475
AddToMenu: true,
2476
Items: seasonalItems
2477
});
2478
}
2479
}
2419
const isSaintPatrickActive = timeMs >= saintPatrickStart && timeMs < saintPatrickEnd;
2420
if (
2421
(config.worldState?.saintPatrickOverride ?? isSaintPatrickActive) &&
2422
buildLabel &&
2423
version_compare(buildLabel, gameToBuildVersion["13.0.0"]) >= 0
2424
) {
2425
const activation = config.worldState?.saintPatrickOverride ? 1772467200000 : saintPatrickStart;
2426
const expiry = config.worldState?.saintPatrickOverride ? 2000000000000 : saintPatrickEnd;
2427
const storeItems: (Partial<IFlashSale> & { TypeName: string })[] = [
2428
{ TypeName: "/Lotus/Types/StoreItems/SuitCustomizations/ColourPickerShamrockItem", RegularOverride: 1 }
2429
];
2480
2430
2431
pushFlashSales(worldState, storeItems, activation, expiry, "SEASONAL", buildLabel);
2432
}
2481
2433
if (config.worldState?.anniversary != undefined) {
2482
2434
// Incompatible with: Use Tag from Warframe Anniversary for old Events, Wolf Hunt, Galleon Of Ghouls, Hallowed Flame, Hallowed Nightmares, Dog Days, Proxy Rebellion, Long Shadow
2483
2435
const goalsByWeek: Partial<IGoal>[][] = [
@@ -3121,18 +3073,18 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
3121
3073
buildLabel &&
3122
3074
version_compare(buildLabel, gameToBuildVersion["29.3.1"]) >= 0
3123
3075
) {
3124
const activationTimeStamp = config.worldState?.naberusNightsOverride
3125
? "1727881200000"
3126
: Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1).toString();
3076
const activation = config.worldState?.naberusNightsOverride
3077
? 1727881200000
3078
: Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1);
3127
3079
3128
const expiryTimeStamp = config.worldState?.naberusNightsOverride
3129
? "2000000000000"
3130
: Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1).toString();
3080
const expiry = config.worldState?.naberusNightsOverride
3081
? 2000000000000
3082
: Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1);
3131
3083
3132
3084
worldState.Goals.push({
3133
3085
_id: { $oid: "66fd602de1778d583419e8e7" },
3134
Activation: { $date: { $numberLong: activationTimeStamp } },
3135
Expiry: { $date: { $numberLong: expiryTimeStamp } },
3086
Activation: { $date: { $numberLong: activation.toString() } },
3087
Expiry: { $date: { $numberLong: expiry.toString() } },
3136
3088
Count: 0,
3137
3089
Goal: 0,
3138
3090
Success: 0,
@@ -3284,40 +3236,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
3284
3236
{ TypeName: "/Lotus/Types/StoreItems/Packages/HalloweenSkinPackD", PremiumOverride: 180 }
3285
3237
];
3286
3238
3287
worldState.FlashSales.push(
3288
...storeItems.map(item => ({
3289
...{
3290
StartDate: { $date: { $numberLong: activationTimeStamp } },
3291
EndDate: { $date: { $numberLong: expiryTimeStamp } },
3292
ProductExpiryOverride: { $date: { $numberLong: expiryTimeStamp } },
3293
ShowInMarket: item.ShowInMarket ?? true,
3294
HideFromMarket: item.HideFromMarket ?? false,
3295
SupporterPack: item.SupporterPack ?? false,
3296
Discount: item.Discount ?? 0,
3297
BogoBuy: item.BogoBuy ?? 0,
3298
BogoGet: item.BogoGet ?? 0,
3299
RegularOverride: item.RegularOverride ?? 0,
3300
PremiumOverride: item.PremiumOverride ?? 0
3301
},
3302
...item
3303
}))
3304
);
3305
3306
const seasonalItems = storeItems.map(item => item.TypeName);
3307
const seasonalCategory = worldState.InGameMarket.LandingPage.Categories.find(c => c.CategoryName == "SEASONAL");
3308
3309
if (seasonalCategory) {
3310
seasonalCategory.Items ??= [];
3311
seasonalCategory.Items.push(...seasonalItems);
3312
} else {
3313
worldState.InGameMarket.LandingPage.Categories.push({
3314
CategoryName: "SEASONAL",
3315
Name: "/Lotus/Language/Store/SeasonalCategoryTitle",
3316
Icon: "seasonal",
3317
AddToMenu: true,
3318
Items: seasonalItems
3319
});
3320
}
3239
pushFlashSales(worldState, storeItems, activation, expiry, "SEASONAL", buildLabel);
3321
3240
}
3322
3241
3323
3242
if (config.worldState?.bellyOfTheBeast && buildLabel && version_compare(buildLabel, "2024.06.12.18.42") >= 0) {
@@ -4668,3 +4587,64 @@ export const populateFeaturedGuilds = async (worldState: IWorldState): Promise<v
4668
4587
});
4669
4588
}
4670
4589
};
4590
4591
const storeCategories: Record<string, { Name: string; Icon: string; AddToMenu?: boolean }> = {
4592
NEW_PLAYER: { Name: "/Lotus/Language/Store/NewPlayerCategoryTitle", Icon: "newplayer", AddToMenu: true },
4593
POPULAR: { Name: "/Lotus/Language/Menu/StorePopular", Icon: "popular", AddToMenu: true },
4594
HEIRLOOM: { Name: "/Lotus/Language/Store/HeirloomCategoryTitle", Icon: "heirloom", AddToMenu: true },
4595
SEASONAL: { Name: "/Lotus/Language/Store/SeasonalCategoryTitle", Icon: "seasonal", AddToMenu: true },
4596
SALE: { Name: "/Lotus/Language/Menu/Store_Sale", Icon: "sale", AddToMenu: true },
4597
WISH_LIST: { Name: "/Lotus/Language/Menu/Store_Wishlist", Icon: "wishlist" },
4598
PREMIUM_BUNDLES: { Name: "/Lotus/Language/Store/Store_PremiumBundles", Icon: "premiumbundles" },
4599
QUICK_BUY: { Name: "/Lotus/Language/Store/TopSeller_Title", Icon: "quickbuy" }
4600
};
4601
4602
const pushFlashSales = (
4603
ws: IWorldState,
4604
storeItems: (Partial<IFlashSale> & { TypeName: string })[],
4605
startDate: number | Date,
4606
endDate: number | Date,
4607
category: string,
4608
buildLabel?: string
4609
): void => {
4610
ws.FlashSales.push(
4611
...storeItems.map(item => ({
4612
...{
4613
StartDate: toMongoDate2(startDate, buildLabel),
4614
EndDate: toMongoDate2(endDate, buildLabel),
4615
ProductExpiryOverride: toMongoDate2(endDate, buildLabel),
4616
ShowInMarket: item.ShowInMarket ?? true,
4617
HideFromMarket: item.HideFromMarket ?? false,
4618
SupporterPack: item.SupporterPack ?? false,
4619
Discount: item.Discount ?? 0,
4620
BogoBuy: item.BogoBuy ?? 0,
4621
BogoGet: item.BogoGet ?? 0,
4622
RegularOverride: item.RegularOverride ?? 0,
4623
PremiumOverride: item.PremiumOverride ?? 0,
4624
Featured: item.Featured ?? category != "POPULAR",
4625
Popular: item.Popular ?? category == "POPULAR",
4626
BannerIndex: item.BannerIndex ?? 10
4627
},
4628
...item
4629
}))
4630
);
4631
4632
if (category in storeCategories) {
4633
const categoryData = storeCategories[category];
4634
const seasonalCategory = ws.InGameMarket.LandingPage.Categories.find(c => c.CategoryName == category);
4635
const seasonalItems = storeItems.map(item => item.TypeName);
4636
4637
if (seasonalCategory) {
4638
seasonalCategory.Items ??= [];
4639
seasonalCategory.Items.push(...seasonalItems);
4640
} else {
4641
ws.InGameMarket.LandingPage.Categories.push({
4642
...{
4643
CategoryName: category,
4644
Items: seasonalItems
4645
},
4646
...categoryData
4647
});
4648
}
4649
}
4650
};
@@ -459,9 +459,14 @@ export interface IFlashSale {
459
459
BogoGet: number;
460
460
PremiumOverride: number;
461
461
RegularOverride: number;
462
ProductExpiryOverride?: IMongoDate;
463
StartDate: IMongoDate;
464
EndDate: IMongoDate;
462
ProductExpiryOverride?: IMongoDateWithLegacySupport;
463
StartDate: IMongoDateWithLegacySupport;
464
EndDate: IMongoDateWithLegacySupport;
465
466
// Pre-U22.9 fields
467
Featured?: boolean;
468
Popular?: boolean;
469
BannerIndex?: number;
465
470
}
466
471
467
472
export interface IInGameMarket {
@@ -1483,6 +1483,14 @@
1483
1483
<option value="false" data-loc="disabled"></option>
1484
1484
</select>
1485
1485
</div>
1486
<div class="form-group mt-2">
1487
<label class="form-label" for="worldState.saintPatrickOverride" data-loc="worldState_saintPatrick"></label>
1488
<select class="form-control" id="worldState.saintPatrickOverride" data-default="null">
1489
<option value="null" data-loc="normal"></option>
1490
<option value="true" data-loc="enabled"></option>
1491
<option value="false" data-loc="disabled"></option>
1492
</select>
1493
</div>
1486
1494
<div class="form-group mt-2 d-flex gap-2">
1487
1495
<div class="flex-fill">
1488
1496
<label class="form-label" for="worldState.dogDaysOverride" data-loc="worldState_dogDays"></label>
@@ -307,6 +307,7 @@ dict = {
307
307
worldState_tennoLiveRelay: `TennoLive Relais`,
308
308
worldState_baroTennoConRelay: `Baros TennoCon-Relais`,
309
309
worldState_starDays: `Sternen-Tage`,
310
worldState_saintPatrick: `St. Patrick’s Day`,
310
311
worldState_galleonOfGhouls: `Galeone der Ghule`,
311
312
worldState_anniversary: `Warframe Jubiläum`,
312
313
worldState_useAnniversaryTagForOldGoals: `Verwende <code>Tag</code> vom Warframe Jubiläum für alte Events`,
@@ -306,6 +306,7 @@ dict = {
306
306
worldState_tennoLiveRelay: `TennoLive Relay`,
307
307
worldState_baroTennoConRelay: `Baro's TennoCon Relay`,
308
308
worldState_starDays: `Star Days`,
309
worldState_saintPatrick: `St. Patrick’s Day`,
309
310
worldState_galleonOfGhouls: `Galleon of Ghouls`,
310
311
worldState_anniversary: `Warframe Anniversary`,
311
312
worldState_useAnniversaryTagForOldGoals: `Use <code>Tag</code> from Warframe Anniversary for old Events`,
@@ -307,6 +307,7 @@ dict = {
307
307
worldState_tennoLiveRelay: `Repetidor de TennoLive`,
308
308
worldState_baroTennoConRelay: `Repetidor de Baro de la TennoCon`,
309
309
worldState_starDays: `Días estelares`,
310
worldState_saintPatrick: `Día de San Patricio`,
310
311
worldState_galleonOfGhouls: `Galeón de Gules`,
311
312
worldState_anniversary: `Aniversario de Warframe`,
312
313
worldState_useAnniversaryTagForOldGoals: `Usa <code>Tag</code> del Aniversario de Warframe para eventos pasados`,
@@ -307,6 +307,7 @@ dict = {
307
307
worldState_tennoLiveRelay: `Relais TennoLive`,
308
308
worldState_baroTennoConRelay: `Relais Baro TennoCon`,
309
309
worldState_starDays: `Jours Stellaires`,
310
worldState_saintPatrick: `Saint-Patrick`,
310
311
worldState_galleonOfGhouls: `Galion des Goules`,
311
312
worldState_anniversary: `Anniversaire de Warframe`,
312
313
worldState_useAnniversaryTagForOldGoals: `Utiliser <code>Tag</code> de l'Anniversaire de Warframe pour les anciens événements`,
@@ -307,6 +307,7 @@ dict = {
307
307
worldState_tennoLiveRelay: `Реле TennoLive`,
308
308
worldState_baroTennoConRelay: `Реле Баро TennoCon`,
309
309
worldState_starDays: `Звёздные дни`,
310
worldState_saintPatrick: `День Святого Патрика`,
310
311
worldState_galleonOfGhouls: `Галеон Гулей`,
311
312
worldState_anniversary: `Годовщина Warframe`,
312
313
worldState_useAnniversaryTagForOldGoals: `Использовать <code>Tag</code> из Годовщины Warframe для старых событий`,
@@ -307,6 +307,7 @@ dict = {
307
307
worldState_tennoLiveRelay: `Реле TennoLive`,
308
308
worldState_baroTennoConRelay: `Реле Баро TennoCon`,
309
309
worldState_starDays: `Зоряні дні`,
310
worldState_saintPatrick: `День святого Патрика`,
310
311
worldState_galleonOfGhouls: `Гульський галеон`,
311
312
worldState_anniversary: `Річниця Warframe`,
312
313
worldState_useAnniversaryTagForOldGoals: `Використати <code>Tag</code> з річниці Warframe для старих подій`,
@@ -307,6 +307,7 @@ dict = {
307
307
worldState_tennoLiveRelay: `TennoLive中继站`,
308
308
worldState_baroTennoConRelay: `Baro的TennoCon中继站`,
309
309
worldState_starDays: `活动:星日`,
310
worldState_saintPatrick: `圣帕特里克节`,
310
311
worldState_galleonOfGhouls: `战术警报:尸鬼的帆船战舰`,
311
312
worldState_anniversary: `12周年纪念活动`,
312
313
worldState_useAnniversaryTagForOldGoals: `使用纪念活动<code>Tag</code>解决旧活动不显示问题`,