返回提交历史
Modified
src/controllers/api/addPendingFriendController.ts
+1
-1
Modified
src/controllers/api/loginController.ts
+7
-1
Modified
src/controllers/api/removeFriendController.ts
+10
-10
Modified
src/models/loginModel.ts
+2
-1
Modified
src/services/friendService.ts
+5
-4
Modified
src/services/loginService.ts
+11
-7
Modified
src/types/friendTypes.ts
+4
-3
Modified
src/types/loginTypes.ts
+11
-1
XFEstudio/XFESpaceNinjaServer
feat: initial cross-platform stuff (#3533)
Basically just adding more layers of abstraction and hoping it's an improvement for later down the line. :) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3533 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
ca815c6b
代码差异
8 个文件
+51
-28
@@ -62,7 +62,7 @@ const sendFriendRequest = async (
62
62
63
63
const friendInfo: IFriendInfo = {
64
64
_id: toOid(requesteeAccount._id),
65
DisplayName: getUnicodeName(requesteeAccount.DisplayName, requesterAccount.BuildLabel),
65
DisplayName: getUnicodeName(requesteeAccount, requesterAccount.BuildLabel),
66
66
LastLogin: toMongoDate(requesteeAccount.LastLogin),
67
67
Note: message
68
68
};
@@ -5,7 +5,12 @@ import { buildConfig } from "../../services/buildConfigService.ts";
5
5
6
6
import { Account } from "../../models/loginModel.ts";
7
7
import { createAccount, createNonce, getUsernameFromEmail, isCorrectPassword } from "../../services/loginService.ts";
8
import type { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "../../types/loginTypes.ts";
8
import {
9
Platform,
10
type IDatabaseAccountJson,
11
type ILoginRequest,
12
type ILoginResponse
13
} from "../../types/loginTypes.ts";
9
14
import { logger } from "../../utils/logger.ts";
10
15
import { version_compare } from "../../helpers/inventoryHelpers.ts";
11
16
import { handleNonceInvalidation } from "../../services/wsService.ts";
@@ -113,6 +118,7 @@ export const loginController: RequestHandler = async (request, response) => {
113
118
account.CountryCode = loginRequest.lang?.toUpperCase() ?? "EN";
114
119
account.BuildLabel = buildLabel;
115
120
account.LastLogin = new Date();
121
account.LastPlatform = isAndroid ? Platform.Android : Platform.Windows;
116
122
account.Dropped = undefined;
117
123
await account.save();
118
124
@@ -1,11 +1,11 @@
1
1
import gameToBuildVersion from "../../constants/gameToBuildVersion.ts";
2
import { toOid, version_compare } from "../../helpers/inventoryHelpers.ts";
2
import { fromOid, toOid2, version_compare } from "../../helpers/inventoryHelpers.ts";
3
3
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
4
4
import { Friendship } from "../../models/friendModel.ts";
5
5
import { Account } from "../../models/loginModel.ts";
6
6
import { getInventory } from "../../services/inventoryService.ts";
7
7
import { getAccountForRequest, getUnicodeName } from "../../services/loginService.ts";
8
import type { IOid } from "../../types/commonTypes.ts";
8
import type { IOidWithLegacySupport } from "../../types/commonTypes.ts";
9
9
import { parallelForeach } from "../../utils/async-utils.ts";
10
10
import type { RequestHandler } from "express";
11
11
import type { Types } from "mongoose";
@@ -19,11 +19,11 @@ export const removeFriendGetController: RequestHandler = async (req, res) => {
19
19
Friendship.find({ friend: accountId }, "owner")
20
20
]);
21
21
const promises: Promise<void>[] = [];
22
const friends: IOid[] = [];
22
const friends: IOidWithLegacySupport[] = [];
23
23
for (const externalFriendship of externalFriendships) {
24
24
if (!internalFriendships.find(x => x.friend.equals(externalFriendship.owner))) {
25
25
promises.push(Friendship.deleteOne({ _id: externalFriendship._id }) as unknown as Promise<void>);
26
friends.push(toOid(externalFriendship.owner));
26
friends.push(toOid2(externalFriendship.owner, account.BuildLabel));
27
27
}
28
28
}
29
29
await Promise.all(promises);
@@ -67,12 +67,12 @@ export const removeFriendPostController: RequestHandler = async (req, res) => {
67
67
68
68
// Remove all remaining friends that aren't in SkipFriendIds & give response.
69
69
const promises = [];
70
const removeFriendOids: IOid[] = [];
70
const removeFriendOids: IOidWithLegacySupport[] = [];
71
71
for (const friend of friends) {
72
72
if (!data.SkipFriendIds.find(skipFriendId => checkFriendId(skipFriendId, friend))) {
73
73
promises.push(Friendship.deleteOne({ owner: account._id, friend: friend }));
74
74
promises.push(Friendship.deleteOne({ owner: friend, friend: account._id }));
75
removeFriendOids.push(toOid(friend));
75
removeFriendOids.push(toOid2(friend, account.BuildLabel));
76
76
}
77
77
}
78
78
await Promise.all(promises);
@@ -97,21 +97,21 @@ interface IRemoveFriendsResponseU40 {
97
97
98
98
// < U40
99
99
interface IRemoveFriendsResponseU39 {
100
Friends: IOid[];
100
Friends: IOidWithLegacySupport[];
101
101
}
102
102
103
103
const toRemoveFriendsResponse = async (
104
104
buildLabel: string | undefined,
105
friends: IOid[]
105
friends: IOidWithLegacySupport[]
106
106
): Promise<IRemoveFriendsResponseU39 | IRemoveFriendsResponseU40> => {
107
107
if (buildLabel && version_compare(buildLabel, gameToBuildVersion["40.0.0"]) < 0) {
108
108
return { Friends: friends } satisfies IRemoveFriendsResponseU39;
109
109
} else {
110
110
const response: IRemoveFriendsResponseU40 = { FriendNames: [] };
111
111
for (const friend of friends) {
112
const acct = await Account.findById(friend.$oid, "DisplayName");
112
const acct = await Account.findById(fromOid(friend));
113
113
if (acct) {
114
response.FriendNames.push(getUnicodeName(acct.DisplayName, buildLabel));
114
response.FriendNames.push(getUnicodeName(acct, buildLabel));
115
115
}
116
116
}
117
117
return response;
@@ -25,8 +25,9 @@ const databaseAccountSchema = new Schema<IDatabaseAccountJson>(
25
25
TrackedSettings: { type: [String], default: [] },
26
26
Nonce: { type: Number, default: 0 },
27
27
BuildLabel: String,
28
Dropped: Boolean,
29
28
LastLogin: { type: Date, default: 0 },
29
LastPlatform: Number,
30
Dropped: Boolean,
30
31
LatestEventMessageDate: { type: Date, default: 0 },
31
32
LastLoginRewardDate: { type: Number, default: 0 },
32
33
LoginDays: { type: Number, default: 1 },
@@ -3,13 +3,14 @@ import { getInventory } from "./inventoryService.ts";
3
3
import { Account } from "../models/loginModel.ts";
4
4
import type { Types } from "mongoose";
5
5
import { Friendship } from "../models/friendModel.ts";
6
import { fromOid, toMongoDate } from "../helpers/inventoryHelpers.ts";
6
import { fromOid, toMongoDate2 } from "../helpers/inventoryHelpers.ts";
7
7
import { getUnicodeName } from "./loginService.ts";
8
8
9
9
export const addAccountDataToFriendInfo = async (info: IFriendInfo, buildLabel: string | undefined): Promise<void> => {
10
const account = (await Account.findById(fromOid(info._id), "DisplayName LastLogin"))!;
11
info.DisplayName = getUnicodeName(account.DisplayName, buildLabel);
12
info.LastLogin = toMongoDate(account.LastLogin);
10
const account = (await Account.findById(fromOid(info._id)))!;
11
info.DisplayName = getUnicodeName(account, buildLabel);
12
info.LastLogin = toMongoDate2(account.LastLogin, buildLabel);
13
info.LastPlatform = account.LastPlatform;
13
14
};
14
15
15
16
export const addInventoryDataToFriendInfo = async (info: IFriendInfo): Promise<void> => {
@@ -1,6 +1,6 @@
1
1
import { Account } from "../models/loginModel.ts";
2
2
import { createInventory } from "./inventoryService.ts";
3
import type { IDatabaseAccountJson, IDatabaseAccountRequiredFields } from "../types/loginTypes.ts";
3
import { Platform, type IDatabaseAccountJson, type IDatabaseAccountRequiredFields } from "../types/loginTypes.ts";
4
4
import { createShip } from "./shipService.ts";
5
5
import type { Document, Types } from "mongoose";
6
6
import { Loadout, type TLoadoutDatabaseDocument } from "../models/inventoryModels/loadoutModel.ts";
@@ -128,10 +128,14 @@ export const isAdministrator = (account: TAccountDocument): boolean => {
128
128
return config.administratorNames?.indexOf(account.DisplayName) != -1;
129
129
};
130
130
131
const platform_magics = [753, 639, 247, 37, 60];
131
export const getOriginalPlatform = (account: TAccountDocument): number => {
132
return account.GoogleTokenId ? Platform.Android : Platform.Windows;
133
};
134
135
const platform_magics = [753, 639, 247, 37, 60, 161];
132
136
export const getSuffixedName = (account: TAccountDocument): string => {
133
137
const name = account.DisplayName;
134
const platformId = 0;
138
const platformId = getOriginalPlatform(account); // Name suffix is based on the original platform, so cross-save does not change it.
135
139
const suffix = ((crc32.str(name.toLowerCase() + "595") >>> 0) + platform_magics[platformId]) % 1000;
136
140
return name + "#" + suffix.toString().padStart(3, "0");
137
141
};
@@ -140,10 +144,10 @@ export const getAccountFromSuffixedName = (name: string): Promise<TAccountDocume
140
144
return Account.findOne({ DisplayName: name.split("#")[0] });
141
145
};
142
146
143
export const getUnicodeName = (DisplayName: string, buildLabel: string | undefined): string => {
147
export const getUnicodeName = (account: TAccountDocument, buildLabel: string | undefined): string => {
144
148
if (buildLabel && version_compare(buildLabel, gameToBuildVersion["32.0.0"]) < 0) {
145
return DisplayName;
149
return account.DisplayName;
146
150
}
147
const platformId = 0; // TODO
148
return DisplayName + String.fromCharCode(0xe000 + platformId);
151
const platformId = getOriginalPlatform(account);
152
return account.DisplayName + String.fromCharCode(0xe000 + platformId);
149
153
};
@@ -1,5 +1,6 @@
1
1
import type { Types } from "mongoose";
2
import type { IMongoDate, IOidWithLegacySupport } from "./commonTypes.ts";
2
import type { IMongoDateWithLegacySupport, IOidWithLegacySupport } from "./commonTypes.ts";
3
import type { Platform } from "./loginTypes.ts";
3
4
4
5
export interface IFriendInfo {
5
6
_id: IOidWithLegacySupport;
@@ -9,13 +10,13 @@ export interface IFriendInfo {
9
10
Status?: number;
10
11
ActiveAvatarImageType?: string;
11
12
TitleType?: string;
12
LastLogin?: IMongoDate;
13
LastLogin?: IMongoDateWithLegacySupport;
13
14
PlayerLevel?: number;
14
15
Suffix?: number;
15
16
Note?: string;
16
17
Favorite?: boolean;
17
18
NewRequest?: boolean;
18
LastPlatform?: number;
19
LastPlatform?: Platform;
19
20
}
20
21
21
22
export interface IFriendship {
@@ -1,5 +1,14 @@
1
1
import type { Types } from "mongoose";
2
2
3
export enum Platform {
4
Windows = 0,
5
PlayStation = 1,
6
Xbox = 2,
7
Switch = 3,
8
iOS = 4,
9
Android = 5
10
}
11
3
12
export interface IAccountAndLoginResponseCommons {
4
13
DisplayName: string;
5
14
CountryCode?: string;
@@ -22,7 +31,8 @@ export interface IDatabaseAccountRequiredFields extends IAccountAndLoginResponse
22
31
}
23
32
24
33
export interface IDatabaseAccount extends IDatabaseAccountRequiredFields {
25
Dropped?: boolean;
34
LastPlatform?: Platform;
35
Dropped?: true;
26
36
LatestEventMessageDate: Date;
27
37
LastLoginRewardDate: number;
28
38
LoginDays: number;