Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: remove double save loading #1741

Merged
merged 27 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/release/dev/sp-httpclient-callback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
HTTP Client API now supports callbacks, not only promises. This is useful since in SkyrimPlatform promises aren't resolving in the main menu.
1 change: 1 addition & 0 deletions docs/release/dev/sp-loadgame.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added `time` and `loadOrder` parameters to `loadGame` function.
1 change: 1 addition & 0 deletions docs/release/dev/sp-tick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added initial support for calling script functions in tick context: `Game.getModCount`, `Game.getModName`.
6 changes: 3 additions & 3 deletions savefile/src/SFStructure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,17 @@ int64_t SaveFile_::SaveFile::FindIndexInFormIdArray(uint32_t refID)
}

void SaveFile_::SaveFile::OverwritePluginInfo(
std::vector<std::string>& newPlaginNames)
std::vector<std::string>& newPluginNames)
{
uint32_t oldSize = this->pluginInfoSize;

this->pluginInfoSize = 1;
this->pluginInfo.numPlugins = 0;
this->pluginInfo.pluginsName.clear();

this->pluginInfo.numPlugins = uint8_t(newPlaginNames.size());
this->pluginInfo.numPlugins = static_cast<uint8_t>(newPluginNames.size());

for (auto& plugin : newPlaginNames) {
for (auto& plugin : newPluginNames) {
this->pluginInfo.pluginsName.push_back(plugin);
this->pluginInfoSize += uint32_t(2 + plugin.size());
}
Expand Down
205 changes: 92 additions & 113 deletions skymp5-client/src/features/authSystem.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import * as sp from "skyrimPlatform";
import * as browser from "./browser";
import { AuthGameData, RemoteAuthGameData } from "./authModel";
import { Transform } from "../sync/movement";
import { FunctionInfo } from "../lib/functionInfo";
import { SpApiInteractor } from "../services/spApiInteractor";
import { LoadGameService } from "../services/services/loadGameService";

const normalizeUrl = (url: string) => {
if (url.endsWith('/')) {
Expand Down Expand Up @@ -53,15 +50,15 @@ export const addAuthListener = (callback: AuthCallback): void => {
authListeners.push(callback);
}

export const main = (lobbyLocation: Transform): void => {
export const main = (): void => {
const settingsGameData = sp.settings["skymp5-client"]["gameData"] as any;
const isOfflineMode = Number.isInteger(settingsGameData?.profileId);
if (isOfflineMode) {
onAuthListeners({ local: { profileId: settingsGameData.profileId } });
} else {
startListenBrowserMessage();
browser.addOnWindowLoadListener(() => {
if (isListenBrowserMessage) loadLobby(lobbyLocation);
if (isListenBrowserMessage) loadLobby();
});
}
}
Expand All @@ -78,7 +75,7 @@ export const setPlayerAuthMode = (frozen: boolean): void => {
sp.Game.forceFirstPerson();
}

function createPlaySession(token: string) {
function createPlaySession(token: string, callback: (res: string, err: string) => void) {
const client = new sp.HttpClient(authUrl);
let masterKey = sp.settings["skymp5-client"]["server-master-key"];
if (!masterKey) {
Expand All @@ -88,17 +85,21 @@ function createPlaySession(token: string) {
masterKey = sp.settings["skymp5-client"]["server-ip"] + ":" + sp.settings["skymp5-client"]["server-port"];
}
sp.printConsole({ masterKey });
return client.post(`/api/users/me/play/${masterKey}`, {

client.post(`/api/users/me/play/${masterKey}`, {
body: '{}',
contentType: 'application/json',
headers: {
'authorization': token,
},
}).then((res) => {
}, (res: sp.HttpResponse) => {
if (res.status != 200) {
throw Error('status code ' + res.status);
callback('', 'status code ' + res.status);
}
else {
// TODO: handle JSON.parse failure?
callback(JSON.parse(res.body).session, '');
}
return JSON.parse(res.body).session;
});
}

Expand Down Expand Up @@ -146,86 +147,64 @@ const checkLoginState = () => {
if (!isListenBrowserMessage) {
return;
}

new sp.HttpClient(authUrl)
.get("/api/users/login-discord/status?state=" + discordAuthState)
.then(response => {
switch (response.status) {
case 200:
const {
token,
masterApiId,
discordUsername,
discordDiscriminator,
discordAvatar,
} = JSON.parse(response.body) as AuthStatus;
browserState.failCount = 0;
createPlaySession(token).then((playSession) => {
authData = {
session: playSession,
.get("/api/users/login-discord/status?state=" + discordAuthState, undefined,
(response) => {
switch (response.status) {
case 200:
const {
token,
masterApiId,
discordUsername,
discordDiscriminator,
discordAvatar,
};
refreshWidgets();
});
break;
case 401: // Unauthorized
browserState.failCount = 0;
browserState.comment = (`Still waiting...`);
setTimeout(() => checkLoginState(), 1.5 + Math.random() * 2);
break;
case 403: // Forbidden
case 404: // Not found
browserState.failCount = 9000;
browserState.comment = (`Fail: ${response.body}`);
break;
default:
++browserState.failCount;
browserState.comment = `Server returned ${response.status.toString() || "???"} "${response.body || response.error}"`;
setTimeout(() => checkLoginState(), 1.5 + Math.random() * 2);
}
})
.catch(reason => {
++browserState.failCount;
if (typeof reason === "string") {
browserState.comment = (`Skyrim platform error (http): ${reason}`)
} else {
browserState.comment = (`Skyrim platform error (http): request rejected`);
}
})
.finally(() => {
refreshWidgets();
});
} = JSON.parse(response.body) as AuthStatus;
browserState.failCount = 0;
createPlaySession(token, (playSession, error) => {
if (error) {
browserState.failCount = 0;
browserState.comment = (error);
setTimeout(() => checkLoginState(), 1.5 + Math.random() * 2);
refreshWidgets();
return;
}
authData = {
session: playSession,
masterApiId,
discordUsername,
discordDiscriminator,
discordAvatar,
};
refreshWidgets();
});
break;
case 401: // Unauthorized
browserState.failCount = 0;
browserState.comment = (`Still waiting...`);
setTimeout(() => checkLoginState(), 1.5 + Math.random() * 2);
break;
case 403: // Forbidden
case 404: // Not found
browserState.failCount = 9000;
browserState.comment = (`Fail: ${response.body}`);
break;
default:
++browserState.failCount;
browserState.comment = `Server returned ${response.status.toString() || "???"} "${response.body || response.error}"`;
setTimeout(() => checkLoginState(), 1.5 + Math.random() * 2);
}
});
};

const loadLobby = (location: Transform): void => {
sp.once("update", () => {
defaultAutoVanityModeDelay = sp.Utility.getINIFloat("fAutoVanityModeDelay:Camera");
setPlayerAuthMode(true);
authData = browser.getAuthData();
refreshWidgets();
sp.browser.setVisible(true);
});

sp.once("loadGame", () => {
// In non-offline mode we still want to see our face in RaceMenu
const ironHelment = sp.Armor.from(sp.Game.getFormEx(0x00012e4d));
const pl = sp.Game.getPlayer();
if (pl) pl.unequipItem(ironHelment, false, true);

sp.browser.setFocused(true);
browser.keepCursorMenuOpenedWhenBrowserFocused();
checkLoginState();
});
const loadLobby = (): void => {
authData = browser.getAuthData();
refreshWidgets();
sp.browser.setVisible(true);
sp.browser.setFocused(true);

const loadGameService = SpApiInteractor.makeController().lookupListener(LoadGameService);
loadGameService.loadGame(
location.pos,
location.rot,
location.worldOrCell
);
// Launch checkLoginState loop
checkLoginState();
}

declare const window: any;
Expand All @@ -234,54 +213,54 @@ const browsersideWidgetSetter = () => {
const loginWidget = {
type: "form",
id: 1,
caption: "authorization",
caption: "Авторизация",
elements: [
{
type: "button",
tags: ["BUTTON_STYLE_GITHUB"],
hint: "get a colored nickname and mention in news",
click: () => window.skyrimPlatform.sendMessage(events.openGithub),
},
{
type: "button",
tags: ["BUTTON_STYLE_PATREON", "ELEMENT_SAME_LINE", "HINT_STYLE_RIGHT"],
hint: "get a colored nickname and other bonuses for patrons",
click: () => window.skyrimPlatform.sendMessage(events.openPatreon),
},
{
type: "icon",
text: "username",
tags: ["ICON_STYLE_SKYMP"],
},
// {
// type: "button",
// tags: ["BUTTON_STYLE_GITHUB"],
// hint: "get a colored nickname and mention in news",
// click: () => window.skyrimPlatform.sendMessage(events.openGithub),
// },
// {
// type: "button",
// tags: ["BUTTON_STYLE_PATREON", "ELEMENT_SAME_LINE", "HINT_STYLE_RIGHT"],
// hint: "get a colored nickname and other bonuses for patrons",
// click: () => window.skyrimPlatform.sendMessage(events.openPatreon),
// },
// {
// type: "icon",
// text: "username",
// tags: ["ICON_STYLE_SKYMP"],
// },
{
type: "text",
text: (
authData ? (
authData.discordUsername
? `${authData.discordUsername}`
? `Добро пожаловать, ${authData.discordUsername}`
: `id: ${authData.masterApiId}`
) : "Please log in"
) : "Не авторизирован"
),
tags: ["ELEMENT_SAME_LINE", "ELEMENT_STYLE_MARGIN_EXTENDED"],
},
{
type: "icon",
text: "discord",
tags: ["ICON_STYLE_DISCORD"],
tags: [/*"ELEMENT_SAME_LINE", */"ELEMENT_STYLE_MARGIN_EXTENDED"],
},
// {
// type: "icon",
// text: "discord",
// tags: ["ICON_STYLE_DISCORD"],
// },
{
type: "button",
text: authData ? "change account" : "login or register",
tags: ["ELEMENT_SAME_LINE"],
text: authData ? "Сменить аккаунт" : "Войти через Discord",
tags: [/*"ELEMENT_SAME_LINE"*/],
click: () => window.skyrimPlatform.sendMessage(events.openDiscordOauth),
hint: "You can log in or change account at any time",
hint: "Вы можете войти или поменять аккаунт",
},
{
type: "button",
text: "travel to skyrim",
text: "Играть",
tags: ["BUTTON_STYLE_FRAME", "ELEMENT_STYLE_MARGIN_EXTENDED"],
click: () => window.skyrimPlatform.sendMessage(events.login),
hint: "Connect to the game server",
hint: "Подключиться к игровому серверу",
},
{
type: "text",
Expand Down
1 change: 0 additions & 1 deletion skymp5-client/src/features/browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
once,
Input,
printConsole,
settings,
Menu,
DxScanCode,
writePlugin,
Expand Down
8 changes: 5 additions & 3 deletions skymp5-client/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ import { ActivationService } from "./services/services/activationService";
import { CraftService } from "./services/services/craftService";
import { DropItemService } from "./services/services/dropItemService";
import { HitService } from "./services/services/hitService";
import { SendMessagesService } from "./services/services/sendMessagesService";
import { RagdollService } from "./services/services/ragdollService";
import { DeathService } from "./services/services/deathService";
import { ContainersService } from "./services/services/containersService";
import { NetworkingService } from "./services/services/networkingService";
import { RemoteServer } from "./services/services/remoteServer";

browser.main();

Expand Down Expand Up @@ -107,10 +108,11 @@ const main = () => {
new CraftService(sp, controller),
new DropItemService(sp, controller),
new HitService(sp, controller),
new SendMessagesService(sp, controller),
new RagdollService(sp, controller),
new DeathService(sp, controller),
new ContainersService(sp, controller)
new ContainersService(sp, controller),
new NetworkingService(sp, controller),
new RemoteServer(sp, controller)
];
SpApiInteractor.setup(listeners);
listeners.forEach(listener => SpApiInteractor.registerListenerForLookup(listener.constructor.name, listener));
Expand Down
3 changes: 2 additions & 1 deletion skymp5-client/src/lib/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export class RespawnNeededError extends Error {

export class NeverError extends Error {
constructor(message: never) {
super(`Unreachable statement: ${message}`);
super(`NeverError: ${JSON.stringify(message)}`);
Object.setPrototypeOf(this, NeverError.prototype);
}
}
Loading
Loading