From afd435e3bd5ee382f265214100246b7c728d5c42 Mon Sep 17 00:00:00 2001
From: Ecks1337
Date: Tue, 30 Aug 2022 03:00:36 +0100
Subject: [PATCH] Implement shader uploading
---
package-lock.json | 2 +-
package.json | 2 +-
src/main/routes/firmware.ipc.ts | 2 +-
src/main/routes/gamebanana.ts | 2 +-
src/main/routes/modsDownload.ts | 2 +-
src/main/routes/shaders.ts | 228 +++++++-----------
src/main/services/HttpService.ts | 27 ++-
src/renderer/actions/emulatorFiles.action.ts | 6 +-
src/renderer/actions/mod.action.ts | 4 +-
src/renderer/actions/shaders.action.ts | 20 +-
.../GameDetailComponent.tsx | 2 +-
src/renderer/i18n/br.json | 3 +-
src/renderer/i18n/de.json | 4 +-
src/renderer/i18n/en.json | 12 +-
src/renderer/i18n/es.json | 3 +-
src/renderer/i18n/it.json | 7 +-
src/renderer/i18n/ru.json | 4 +-
src/renderer/i18n/se.json | 3 +-
src/renderer/i18n/tr.json | 7 +-
src/renderer/i18n/zh-CN.json | 7 +-
.../resources/{pirate.gif => dance.gif} | Bin
src/types.ts | 9 +
22 files changed, 159 insertions(+), 197 deletions(-)
rename src/renderer/resources/{pirate.gif => dance.gif} (100%)
diff --git a/package-lock.json b/package-lock.json
index 777ca7cb..86f4bc96 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "RyuSAK",
- "version": "1.3.0",
+ "version": "1.4.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
diff --git a/package.json b/package.json
index 052bdf10..125ccf42 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "RyuSAK",
"productName": "RyuSAK",
- "version": "1.3.0",
+ "version": "1.4.0",
"description": "RyuSAK",
"repository": "https://github.com/Ecks1337/RyuSAK",
"main": ".webpack/main",
diff --git a/src/main/routes/firmware.ipc.ts b/src/main/routes/firmware.ipc.ts
index f1303b93..9f1830a5 100644
--- a/src/main/routes/firmware.ipc.ts
+++ b/src/main/routes/firmware.ipc.ts
@@ -8,7 +8,7 @@ const installFirmware = async (dataPath: string, fwVersion: string, mainWindow:
const zipPath = path.resolve(app.getPath("temp"), "firmware.zip"); // Do not change the name of the zip
try {
- const result = await HttpService.fetchWithProgress(HTTP_PATHS.FIRMWARE_ZIP.replace("{fw_version}", fwVersion), zipPath, mainWindow, "firmware.zip");
+ const result = await HttpService.getWithProgress(HTTP_PATHS.FIRMWARE_ZIP.replace("{fw_version}", fwVersion), zipPath, mainWindow, "firmware.zip");
if (!result) {
return { error: true, code: "FETCH_FAILED" };
diff --git a/src/main/routes/gamebanana.ts b/src/main/routes/gamebanana.ts
index 6462d89d..c82a8528 100644
--- a/src/main/routes/gamebanana.ts
+++ b/src/main/routes/gamebanana.ts
@@ -6,7 +6,7 @@ export type searchProps = [string];
export const searchGameBana = async (...args: searchProps): Promise => {
const [name] = args;
- const response = await HttpService.searchGameBana(name) as { _idRow: number }[];
+ const response = await HttpService.searchGameBanana(name) as { _idRow: number }[];
if (response.length === 0) {
return;
diff --git a/src/main/routes/modsDownload.ts b/src/main/routes/modsDownload.ts
index a25a2563..8f227d4b 100644
--- a/src/main/routes/modsDownload.ts
+++ b/src/main/routes/modsDownload.ts
@@ -33,7 +33,7 @@ export const downloadMod = async (mainWindow: BrowserWindow, ...args: downloadMo
await fs.ensureDir(destPath);
const modDestPath = path.resolve(destPath, name);
- const result = await HttpService.fetchWithProgress(url, modDestPath, mainWindow, modName);
+ const result = await HttpService.getWithProgress(url, modDestPath, mainWindow, modName);
if (!result) {
return Promise.reject(new Error("Unable to retrieve file"));
diff --git a/src/main/routes/shaders.ts b/src/main/routes/shaders.ts
index 60df5ebe..c67aa0d9 100644
--- a/src/main/routes/shaders.ts
+++ b/src/main/routes/shaders.ts
@@ -1,11 +1,12 @@
import fs from "fs-extra";
import path from "path";
import zip from "adm-zip";
-import HttpService, { HTTP_PATHS } from "../services/HttpService";
-import { BrowserWindow, dialog } from "electron";
+import HttpService, { HTTP_PATHS, OTHER_URLS } from "../services/HttpService";
+import { BrowserWindow } from "electron";
import EShopMetaService from "../services/EShopMetaService";
-import { ChildProcessWithoutNullStreams, spawn } from "child_process";
-import { Buffer } from "buffer";
+import { Buffer } from "buffer";;
+import FormData from "form-data";
+import { MirrorUploadResponse } from "../../types";
export type countShadersProps = [string, string];
@@ -13,90 +14,15 @@ export type installShadersProps = [string, string];
export type shareShaders = [string, string, number, number];
-export const asyncZipWrite = (archive: zip, path: string): Promise => new Promise((resolve) => {
- archive.writeZip(path, () => resolve());
+export const writeZipAsync = (archive: zip, path: string): Promise => new Promise((resolve) => {
+ archive.writeZip(path, (error) => resolve(error));
});
-const updateConfig = (conf: any) => {
- conf["logging_enable_error"] = true;
- conf["logging_enable_guest"] = true;
- conf["logging_enable_info"] = true;
- conf["logging_enable_stub"] = true;
- conf["logging_enable_warn"] = true;
- conf["logging_enable_fs_access_log"] = true;
- return conf;
-};
-
-const asyncReadRyujinxProcess = async (ryuBinPath: string): Promise => new Promise((resolve, reject) => {
- let child: ChildProcessWithoutNullStreams;
- try {
- child = spawn(ryuBinPath);
- } catch(e) {
- dialog.showMessageBox({
- title: "Error",
- message: "Cannot launch Ryujinx, please redo the same but launch RyuSAK as admin. Probably antivirus is preventing RyuSAK to launch Ryujinx.",
- type: "error",
- buttons: ["Ok"],
- });
- return Promise.reject("");
- }
- let fullData = "";
- let ranTitleId: string;
- let ranTitleVersion: string;
-
- child.on("exit", () => resolve(false));
- child.stdout.on("data", (data: string) => {
- fullData += data;
- const titleIdMatch = /for Title (.+)/gi.exec(fullData);
- const titleVersionMatch = /v([\d+.]+) \[/.exec(fullData);
-
- if (titleVersionMatch && titleVersionMatch.length >= 2) {
- ranTitleVersion = titleVersionMatch[1];
- }
-
- if (titleIdMatch && titleIdMatch.length >= 2) {
- ranTitleId = titleIdMatch[1].trim();
- }
-
- if (ranTitleId && fullData.toLowerCase().includes("cache loaded")) {
- resolve({ ranTitleId, compiledShadersCount: 0, ranTitleVersion });
- child.kill();
- }
- });
- child.stdout.on("error", () => reject(false));
-});
-
-export const packShaders = async (dataPath: string, titleID: string): Promise => {
- const guestData = path.resolve(dataPath, "games", titleID.toLowerCase(), "cache", "shader", "guest.data");
- const archive = new zip();
- archive.addLocalFile(guestData);
- archive.addLocalFile(path.resolve(dataPath, "games", titleID.toLowerCase(), "cache", "shader", "guest.toc"));
- archive.addLocalFile(path.resolve(dataPath, "games", titleID.toLowerCase(), "cache", "shader", "shared.data"));
- archive.addLocalFile(path.resolve(dataPath, "games", titleID.toLowerCase(), "cache", "shader", "shared.toc"));
-
- const zipPath = path.resolve(guestData, "..", "upload.zip");
- await asyncZipWrite(archive, zipPath);
-
- return zipPath;
-};
-
export const countShaders = async (...args: countShadersProps): Promise => {
const [titleId, dataPath] = args;
const shaderTocFile = path.resolve(dataPath, "games", titleId.toLocaleLowerCase(), "cache", "shader", "shared.toc");
- const shaderExists = await fs.pathExists(shaderTocFile);
- const shaderZipPath = path.resolve(dataPath, "games", titleId.toLocaleLowerCase(), "cache", "shader", "guest", "program", "cache.zip");
- const shaderZipExists = await fs.pathExists(shaderZipPath);
-
- if (!shaderExists) {
- if (shaderZipExists) {
- try {
- const archive = new zip(shaderZipPath);
- return archive.getEntries().length;
- } catch(e) {
- return 0;
- }
- }
+ if (!await fs.pathExists(shaderTocFile)) {
return 0;
}
@@ -104,16 +30,17 @@ export const countShaders = async (...args: countShadersProps): Promise
const fd = await fs.open(shaderTocFile, "r+");
const buffer = Buffer.alloc(8);
await fs.read(fd, buffer, 0, 8, 4);
- const cacheVersion = buffer.readBigUInt64LE();
+ const cacheVersion = buffer.readUInt32LE();
await fs.close(fd);
- if (cacheVersion < 65537) {
+ // ((1 << 16) | 2) aka v1.2
+ if (cacheVersion < 65538) {
return 0;
}
// If cache version is accepted by Ryujinx, computer shader count
const stat = await fs.stat(shaderTocFile);
- return Math.max(+((stat.size - 32) / 8), 0);
+ return Math.max((stat.size - 32) / 8, 0);
};
export const installShaders = async (mainWindow: BrowserWindow, ...args: installShadersProps): Promise => {
@@ -123,8 +50,8 @@ export const installShaders = async (mainWindow: BrowserWindow, ...args: install
await fs.ensureDir(shaderCacheDir);
await fs.emptyDir(shaderCacheDir);
- const shaderCacheZipPath = path.resolve(shaderCacheDir, "cache.zip");
- const result = await HttpService.fetchWithProgress(HTTP_PATHS.SHADER_ZIP.replace("{title_id}", titleId), shaderCacheZipPath, mainWindow, titleId);
+ const shaderCacheZipPath = path.resolve(shaderCacheDir, `${titleId}.zip`);
+ const result = await HttpService.getWithProgress(HTTP_PATHS.SHADERS_ZIP.replace("{title_id}", titleId), shaderCacheZipPath, mainWindow, titleId);
if (!result) {
return null;
@@ -138,69 +65,94 @@ export const installShaders = async (mainWindow: BrowserWindow, ...args: install
};
export const shareShaders = async (mainWindow: BrowserWindow, ...args: shareShaders) => {
- throw new Error("Not implemented"); // @ts-ignore
-
const [titleId, dataPath, localCount, ryusakCount] = args;
-
- const guestTocFile = path.resolve(dataPath, "games", titleId.toLowerCase(), "cache", "shader", "guest.toc");
-
- if (!await fs.pathExists(guestTocFile)) {
- return { error: true, code: "SHADER_CACHE_V1" };
- }
-
- const { canceled, filePaths } = await dialog.showOpenDialog(mainWindow, { properties: ["openFile"] });
-
- if (canceled) {
- return { error: true, code: "OPERATION_CANCELED" };
- }
-
- const ryuBinary = filePaths[0];
-
- if (!ryuBinary.toLowerCase().includes("ryujinx")) {
- return { error: true, code: "INVALID_RYUJINX_BINARY" };
- }
-
- const ldnConfigPath = path.resolve(dataPath, "LDNConfig.json");
- const hasLdnConfigFile = await fs.promises.access(ldnConfigPath).then(() => true).catch(() => false);
- const standardConfigPath = path.resolve(dataPath, "Config.json");
-
- let ryujinxConfig = JSON.parse((await fs.promises.readFile(standardConfigPath)).toString());
- ryujinxConfig = updateConfig(ryujinxConfig);
- await fs.promises.writeFile(hasLdnConfigFile ? ldnConfigPath : standardConfigPath, JSON.stringify(ryujinxConfig, null, 2), "utf-8");
-
const metadata = await EShopMetaService.getEShopMeta(titleId);
- const result = await asyncReadRyujinxProcess(ryuBinary).catch(() => false);
-
- if (!result) {
- return;
- }
+ const shaderCacheDir = path.resolve(dataPath, "games", titleId.toLowerCase(), "cache", "shader");
+ const shaderCacheZipPath = path.resolve(shaderCacheDir, `${titleId}.zip`);
- if (result.ranTitleId.toLowerCase() !== titleId.toLowerCase()) {
- return { error: true, code: `You shared the wrong titleID, you had to run ${metadata.name || metadata.id} in Ryujinx` };
- }
+ const shaderCacheZip = new zip();
+ shaderCacheZip.addLocalFile(path.resolve(shaderCacheDir, "guest.data"));
+ shaderCacheZip.addLocalFile(path.resolve(shaderCacheDir, "guest.toc"));
+ shaderCacheZip.addLocalFile(path.resolve(shaderCacheDir, "shared.data"));
+ shaderCacheZip.addLocalFile(path.resolve(shaderCacheDir, "shared.toc"));
- /**
- if (result.compiledShadersCount !== localCount) {
- return { error: true, code: `You have ${localCount} on your cache but Ryujinx compiled ${result.compiledShadersCount}. That means that some shaders are either corrupted or rejected. This probably isn't your fault, it probably means you build shaders a longer time ago and Ryujinx chose to reject them because they changed something in their code. The game probably run fine, but because we share shaders to everyone, we chose to reject your submission to avoid any conflict as we aren't 100% sure if this will cause issue to anyone.` };
- }
- */
+ await writeZipAsync(shaderCacheZip, shaderCacheZipPath);
- const shadersPath = await packShaders(dataPath, titleId);
- const size = fs.lstatSync(shadersPath).size;
+ const size = fs.lstatSync(shaderCacheZipPath).size;
let bytes = 0;
let lastEmittedEventTimestamp = 0;
-
- // @ts-ignore
- const readStream = fs.createReadStream(shadersPath).on("data", (chunk) => {
+ const readStream = fs.createReadStream(shaderCacheZipPath).on("data", (chunk) => {
bytes += chunk.length;
- const currentTimestamp = +new Date();
+ const currentTimestamp = new Date().getUTCMilliseconds();
if (currentTimestamp - lastEmittedEventTimestamp >= 100) {
const percentage = (bytes / size * 100).toFixed(2);
mainWindow.webContents.send("download-progress", titleId, percentage);
- lastEmittedEventTimestamp = +new Date();
+ lastEmittedEventTimestamp = new Date().getUTCMilliseconds();
}
});
- // TODO: implement uploading shaders
- return true;
+ const formData = new FormData();
+ formData.append("file", readStream);
+
+ const uploadRes = await HttpService.post(OTHER_URLS.SHADERS_UPLOAD, formData);
+ await fs.unlink(shaderCacheZipPath);
+
+ if (!uploadRes.ok) {
+ return { error: true, code: "SHADER_UPLOAD_FAIL", message: `${uploadRes.status} - ${uploadRes.statusText}` };
+ }
+
+ const uploadJson = await uploadRes.json() as MirrorUploadResponse;
+ const message = {
+ embeds: [
+ {
+ author: {
+ name: "RyuSAK",
+ url: "https://github.com/Ecks1337/RyuSAK",
+ icon_url: "https://raw.githubusercontent.com/Ecks1337/RyuSAK/master/src/assets/icon.ico"
+ },
+ color: 5055982,
+ fields: [
+ {
+ name: "Title Name",
+ value: metadata.name
+ },
+ {
+ name: "Title ID",
+ value: metadata.id
+ },
+ {
+ name: "Local Shader Count",
+ value: localCount
+ },
+ {
+ name: "RyuSAK Shader Count",
+ value: ryusakCount
+ },
+ {
+ name: "File ID",
+ value: uploadJson.fileId
+ },
+ {
+ name: "Deletion Token",
+ value: uploadJson.deletionToken
+ },
+ {
+ name: "Deletion Time",
+ value: uploadJson.deletionTime
+ }
+ ]
+ }
+ ]
+ };
+
+ const webhookRes = await HttpService.postJSON(OTHER_URLS.SHADERS_POST, message);
+ if (webhookRes.ok) {
+ return { error: false, code: null, message: null };
+ } else {
+ return {
+ error: true,
+ code: "SHADER_WEBHOOK_FAIL",
+ message: `Title Name: ${metadata.name}Title ID: ${metadata.id}Local Shader Count: ${localCount}RyuSAK Shader Count: ${ryusakCount}File ID: ${uploadJson.fileId}Deletion Token: ${uploadJson.deletionToken}Deletion Time: ${uploadJson.deletionTime}
`
+ };
+ }
};
diff --git a/src/main/services/HttpService.ts b/src/main/services/HttpService.ts
index 2848c7a3..9bc6c92e 100644
--- a/src/main/services/HttpService.ts
+++ b/src/main/services/HttpService.ts
@@ -1,5 +1,5 @@
import { URL } from "url";
-import fetch, { RequestInit } from "node-fetch";
+import fetch, { RequestInit, HeadersInit, BodyInit } from "node-fetch";
import pRetry from "p-retry";
import { app, BrowserWindow, ipcMain } from "electron";
import http from "http";
@@ -22,12 +22,14 @@ export enum HTTP_PATHS {
MOD_DOWNLOAD = "/json/archive/nintendo/switch/mods/{title_id}/{version}/{name}/",
SAVES_LIST = "/json/archive/nintendo/switch/savegames/",
SAVES_DOWNLOAD = "/archive/nintendo/switch/savegames/{file_name}",
- SHADER_ZIP = "/archive/nintendo/switch/shaders/SPIR-V/{title_id}.zip",
+ SHADERS_ZIP = "/archive/nintendo/switch/shaders/SPIR-V/{title_id}.zip",
SHADERS_LIST = "/archive/nintendo/switch/ryusak/shader_count_spirv.json",
THRESHOLD = "/archive/nintendo/switch/ryusak/threshold.txt",
}
export enum OTHER_URLS {
+ SHADERS_UPLOAD = "https://send.nukes.wtf/upload/",
+ SHADERS_POST = "https://discord.com/api/webhooks/1013993198537941083/30P1JsEyExC5nz3toqcE_YWosCJJh-DuQzF8DBtaG2ZJj64FJJ6pMS2rSxB7M0CGurRP",
RELEASE_INFO = "https://api.github.com/repos/Ecks1337/RyuSAK/releases/latest",
COMPAT_LIST = "https://api.github.com/search/issues?q={query}%20repo:Ryujinx/Ryujinx-Games-List",
ESHOP_DATA = "https://github.com/AdamK2003/titledb/releases/download/latest/titles.US.en.json",
@@ -106,7 +108,24 @@ class HttpService {
) as Promise;
}
- public async fetchWithProgress(path: string, destPath: string, mainWindow: BrowserWindow, eventName: string) {
+ public async post(url: string, body: BodyInit, headers: HeadersInit = null) {
+ return this.fetch(url, {
+ agent: this.httpsAgent,
+ method: "POST",
+ body,
+ headers
+ });
+ }
+
+ public async postJSON(url: string, obj: any) {
+ return this.post(
+ url,
+ JSON.stringify(obj),
+ { "Content-Type": "application/json" }
+ );
+ }
+
+ public async getWithProgress(path: string, destPath: string, mainWindow: BrowserWindow, eventName: string) {
const url = new URL(path, CDN_URL);
const fileStream = fs.createWriteStream(destPath);
const controller = new AbortController();
@@ -234,7 +253,7 @@ class HttpService {
return this.get(HTTP_PATHS.SAVES_DOWNLOAD.replace("{file_name}", fileName), "BUFFER");
}
- public async searchGameBana(query: string) {
+ public async searchGameBanana(query: string) {
return this.get(OTHER_URLS.GAME_BANANA_SEARCH.replace("{query}", query));
}
diff --git a/src/renderer/actions/emulatorFiles.action.ts b/src/renderer/actions/emulatorFiles.action.ts
index f3ab9fff..139c4e47 100644
--- a/src/renderer/actions/emulatorFiles.action.ts
+++ b/src/renderer/actions/emulatorFiles.action.ts
@@ -1,7 +1,7 @@
import { GetState, SetState } from "zustand/vanilla";
import { ipcRenderer } from "electron";
import Swal from "sweetalert2";
-import pirate from "../resources/pirate.gif";
+import dance from "../resources/dance.gif";
import useStore from "./state";
import { IAlert } from "./alert.action";
import useTranslation, { I18nKeys } from "../i18n/I18nService";
@@ -32,14 +32,14 @@ const createEmulatorFilesSLice = (_set: SetState<{ }>, get: GetState${t("firmwareLocation")} : ${extractPath}
`,
});
},
downloadKeysAction: async (dataPath: string) => {
const result = await invokeIpc("install-keys", dataPath);
Swal.fire({
- imageUrl: pirate,
+ imageUrl: dance,
html: `${t("keysLocation")} : ${result}
`
});
}
diff --git a/src/renderer/actions/mod.action.ts b/src/renderer/actions/mod.action.ts
index 44b2b16b..4d381f23 100644
--- a/src/renderer/actions/mod.action.ts
+++ b/src/renderer/actions/mod.action.ts
@@ -3,7 +3,7 @@ import useStore from "./state";
import { ipcRenderer } from "electron";
import Swal from "sweetalert2";
import useTranslation from "../i18n/I18nService";
-import pirate from "../resources/pirate.gif";
+import dance from "../resources/dance.gif";
import { invokeIpc } from "../utils";
const { t } = useTranslation();
@@ -45,7 +45,7 @@ const createDownloadModSlice = (set: SetState): ISaveAction => ({
}
Swal.fire({
- imageUrl: pirate,
+ imageUrl: dance,
html: t("modInstalled").replace("{path}", result)
});
}
diff --git a/src/renderer/actions/shaders.action.ts b/src/renderer/actions/shaders.action.ts
index f4c494ec..c83bb6d5 100644
--- a/src/renderer/actions/shaders.action.ts
+++ b/src/renderer/actions/shaders.action.ts
@@ -3,7 +3,7 @@ import Swal from "sweetalert2";
import useStore from "./state";
import useTranslation from "../i18n/I18nService";
import { SetState } from "zustand/vanilla";
-import pirate from "../resources/pirate.gif";
+import dance from "../resources/dance.gif";
import { invokeIpc } from "../utils";
export interface IShaders {
@@ -43,7 +43,7 @@ const createShadersSlice = (set: SetState): IShaders => ({
}
Swal.fire({
- imageUrl: pirate,
+ imageUrl: dance,
text: "Success !"
});
return set({ needRefreshShaders: !state.needRefreshShaders });
@@ -59,12 +59,6 @@ const createShadersSlice = (set: SetState): IShaders => ({
});
return false;
}
-
- await Swal.fire({
- icon: "info",
- text: `${t("pickRyuDataPath")}. ${t("shadersCheck")}`,
- allowOutsideClick: false
- });
const state = useStore.getState();
const dlManagerFilename = t("shadersSharing");
@@ -92,17 +86,21 @@ const createShadersSlice = (set: SetState): IShaders => ({
state.removeFileAction(dlManagerFilename);
ipcRenderer.removeListener("download-progress", onShadersShareProgress);
- if (result !== true) {
+ if (result.error) {
return Swal.fire({
icon: "error",
- text: result.code === "SHADER_CACHE_V1" ? t(result.code) : result.code
+ html: result.code == "SHADER_UPLOAD_FAIL"
+ ? t("SHADER_UPLOAD_FAIL").replace("{status}", result.message)
+ : result.code == "SHADER_WEBHOOK_FAIL"
+ ? t("SHADER_WEBHOOK_FAIL").replace("{details}", result.message)
+ : result.code
});
}
localStorage.setItem(key, "true");
return Swal.fire({
- imageUrl: pirate,
+ imageUrl: dance,
html: t("shadersShared"),
});
}
diff --git a/src/renderer/components/GameDetailComponent/GameDetailComponent.tsx b/src/renderer/components/GameDetailComponent/GameDetailComponent.tsx
index 4eb5ffa3..e4d9335a 100644
--- a/src/renderer/components/GameDetailComponent/GameDetailComponent.tsx
+++ b/src/renderer/components/GameDetailComponent/GameDetailComponent.tsx
@@ -272,7 +272,7 @@ const GameDetailComponent = () => {
disabled={threshold == -1 ? true : ((ryusakShadersCount + threshold) >= localShadersCount)}
onClick={() => shareShaders(metaData.id, dataPath, localShadersCount, ryusakShadersCount)}
>
- {threshold == -1 ? "Shader uploading is currently unavailable" : t("shareShaders")}
+ {threshold == -1 ? t("shaderUploadingUnavailable") : t("shareShaders")}
diff --git a/src/renderer/i18n/br.json b/src/renderer/i18n/br.json
index 522ebdb2..7e434c82 100644
--- a/src/renderer/i18n/br.json
+++ b/src/renderer/i18n/br.json
@@ -34,7 +34,7 @@
"refreshInfo": "Atualizado com sucesso. Por favor note que seu Jogo somente irá aparecer se você o iniciou pelo menos uma vez no emulador.",
"modInstalled": "Mod instalado com sucesso no diretório : {path}
",
"shaderInfo": "Shaders são pequenos códigos executados diretamente na GPU e são responsáveis pela renderização de terrenos, personagens, efeitos, grama, etc. Já que um Comptutador não pode executar o código Shader diretamente, primeiro é necessário converte-los em um formato que o Computador consegue processar. Esse processo de conversão consome tempo e você o perceberá de duas formas:
- Qualquer animação nova com um shader não processado, causará uma pausa na emulação até ser processado, o que causa lag/stuttering e quedas no FPS. Quando você carrega um jogo pela primeira vez, muitas conversões são realizadas. Quanto mais você joga, mais Shaders são processados e menos lag/stuttering acontece.
- O Emulador irá salver todos os Shaders que o jogo utiliza, criando um Cache deles. Quando você inicia um jogo, o emulador leva um pequeno tempo para carregar o Cache de shaders pré-salvos a fim de evitar lags e stutterings.",
- "shaderThreshold": "Isso significa que você pode compartilhar Shaders se a contagem de Shaders que você tem localmente com tempo jogado é maior que a contagem que o RyuSAK tem salvo na nuvem. Esse valor é baseado em quantos envios nós já recebemos e na nossa capacidade de processamento. Analisar o envio dos usuários consome bastante tempo e não vale a pena se a contagem de Shaders local do usuário é menor do que a Contagem da Nuvem do RyuSAK. Por enquanto, os envios estão limitados a 3 por usuário a cada hora.",
+ "shaderThreshold": "Isso significa que você pode compartilhar Shaders se a contagem de Shaders que você tem localmente com tempo jogado é maior que a contagem que o RyuSAK tem salvo na nuvem.",
"localShadersCount": "Contador de Shaders Local",
"ryusakShadersCount": "Contador de Shaders na Nuvem do RyuSAK",
"dlShaders": "Baixar shaders",
@@ -43,7 +43,6 @@
"threshold": "Limiar",
"refresh": "Atualizar",
"OPERATION_CANCELED": "Você cancelou a operação.",
- "INVALID_RYUJINX_BINARY": "Esse não é um arquivo binário válido do Ryujinx.",
"EMULATOR_PATH_ALREADY_EXISTS": "Você já adicionou esse caminho no RyuSAK.",
"FETCH_FAILED": "Não foi possível conseguir o recurso, tente novamente."
}
diff --git a/src/renderer/i18n/de.json b/src/renderer/i18n/de.json
index 808d1d90..4159c27b 100644
--- a/src/renderer/i18n/de.json
+++ b/src/renderer/i18n/de.json
@@ -2,7 +2,6 @@
"agree": "Ich stimme zu",
"loading_data": "Lade Daten...",
"configuration": "Konfiguration",
- "pickYuzuBin": "Bitte \"yuzu.exe\" (oder \"yuzu\" für Linux-Nutzer) auswählen",
"addConfigTitle": "Bitte einen Namen für die neue Konfiguration hinzufügen",
"addConfigEg": "z.B \"Portable\", \"Flatpack\"",
"mode": "Modus",
@@ -32,7 +31,7 @@
"refreshInfo": "Aktualisierung erfolgreich! Bitte beachte, dass nur Spiele angezeigt werden, welche bereits zuvor einmal im Emulator gestartet wurden.",
"modInstalled": "Mod erfolgreich installiert in: {path}
",
"shaderInfo": "Shader sind kleine Programme, die auf einer Grafikkarte laufen und für das Rendern von Grafiken wie Gelände, Figuren, Explosionen, Gras usw. verantwortlich sind. Da PCs die Shader der Switch nicht direkt ausführen können, muss jener diese zunächst in ein Format übersetzen, das der PC versteht. Dieser Übersetzungsprozess ist zeitaufwändig und kann in zweierlei Hinsicht bemerkt werden:
- Alle neuen Shader die auftauchen, führen dazu, dass die Emulation pausiert bis die Übersetzung abgeschlossen ist, was zu Stottern und/oder Einbrüchen der FPS führt. Wenn ein Spiel zum ersten Mal geladen wird, wird eine Menge übersetzt. Wenn viel gespielt wird, nimmt dieses Stottern schnell ab.
- Der Emulator speichert alle Shader, die ein Spiel verwendet, d. h. er legt diese im Cache ab. Wenn das Spiel anschließend erneut gestartet wird, wird der Emulator einige Zeit brauchen, um die gespeicherten Shader zu laden, damit das Stottern nicht erneut auftritt.",
- "shaderThreshold": "Die Zahl gibt an, dass Shader geteilt werden können, wenn die lokale Shader-Anzahl die der von RyuSAK übersteigt. Dies hängt davon ab, wie viele Shader geteilt wurden und wie hoch unsere Arbeitsbelastung ist. Die Überprüfung von Beiträgen ist sehr zeitaufwändig und lohnt sich nicht, wenn die Anzahl der Beiträge unter dem Schwellenwert liegt. Die Anzahl der Einsendungen per Nutzer ist vorerst auf 3 pro Stunde begrenzt.",
+ "shaderThreshold": "Die Zahl gibt an, dass Shader geteilt werden können, wenn die lokale Shader-Anzahl die der von RyuSAK übersteigt.",
"localShadersCount": "Anzahl der lokalen Shader",
"ryusakShadersCount": "Anzahl der globalen Shader",
"dlShaders": "Shader Cache herunterladen",
@@ -41,7 +40,6 @@
"threshold": "Schwellenwert",
"refresh": "Aktualisieren",
"OPERATION_CANCELED": "Operation abgebrochen.",
- "INVALID_RYUJINX_BINARY": "Dies ist keine gültige Ryujinx Binärdatei.",
"EMULATOR_PATH_ALREADY_EXISTS": "Pfad wurde bereits zu RyuSAK hinzugefügt.",
"FETCH_FAILED": "Die Ressource kann nicht abgerufen werden, bitte versuche es erneut."
}
diff --git a/src/renderer/i18n/en.json b/src/renderer/i18n/en.json
index 2aafc1b9..b5d93a91 100644
--- a/src/renderer/i18n/en.json
+++ b/src/renderer/i18n/en.json
@@ -1,5 +1,4 @@
{
- "SHADER_CACHE_V1": "RyuSAK detected you are using Ryujinx's V1 shader cache. The emulator developers created a new version of this shader cache with tons of improvements. Before sharing shaders, launch the game in Ryujinx, the emulator will convert the old cache to the new one automatically then reopen RyuSAK.",
"continue": "Continue",
"cancel": "Cancel",
"save": "Save",
@@ -9,9 +8,8 @@
"deleteGame": "Delete game",
"areYouSure": "Are you sure?",
"deleteGameNotice": "This option will delete the shader cache, CPU cache and mods folder for this game. This action cannot be undone.",
- "shadersCheck": "Then you will have to run your game with Ryujinx so RyuSAK can check that everything is working as expected for everyone. If you have been using the vulkan PR, don't attempt to share the shaders as it won't work as of now... ",
"shadersSharing": "Sharing Shaders...",
- "shadersShared": "Your shaders have been submitted! You can find them in the #ryu-shaders
channel. Once approved, they will be shared to everyone to be downloaded!",
+ "shadersShared": "Your shaders have been submitted!",
"gamebananaModsTitle": "Gamebanana mods (up to 20 most downloaded mods on GameBanana)",
"gamebananaNoMods": "Cannot find any mods on Gamebanana",
"gameBananaLoading": "Loading mods from Gamebanana ...",
@@ -53,16 +51,18 @@
"refreshInfo": "Refresh successful! Please note that only games which you launched at least once in the emulator will be shown, ",
"modInstalled": "Mod successfully installed at: {path}
",
"shaderInfo": "Shaders are small programs running on a graphics card that are responsible for rendering graphics like terrain, characters, explosions, grass etc. Since a PC cannot directly execute the Switch's shaders, it first has to translate them to a format your PC can understand. This translation process is time consuming and you'll notice it in two ways:
- Any new shaders that are encountered will cause the emulation to pause until the translation is done, which causes stuttering and FPS drops. When you load a game for the first time a lot of translation will happen. By playing more this stuttering decreases rapidly.
- The emulator will save any shaders a game uses (AKA it caches them). When you launch a game, the emulator will take some time loading saved shaders, to prevent the stuttering from happening again.",
- "shaderThreshold": "You can share Shaders if your local Shader count surpasses RyuSAK's count by at least this value. This is based on how many submissions we already have and our workload. Reviewing submissions is very time consuming and it is not worth our effort if the additional shader count is below the threshold. Submissions are limited to 3 per user per hour for now to prevent overloading the servers.",
+ "shaderThreshold": "You can share Shaders if your local Shader count surpasses RyuSAK's count by at least this value.",
"localShadersCount": "Local shader count",
"ryusakShadersCount": "RyuSAK shader count",
"dlShaders": "Download shaders",
"shareShaders": "Share shaders",
+ "shaderUploadingUnavailable": "Shader uploading is currently unavailable",
"shaders": "Shaders",
"threshold": "Threshold",
"refresh": "Refresh",
"OPERATION_CANCELED": "You cancelled the operation.",
- "INVALID_RYUJINX_BINARY": "This is not a valid Ryujinx binary file.",
"EMULATOR_PATH_ALREADY_EXISTS": "You already added this path to RyuSAK.",
- "FETCH_FAILED": "Unable to fetch resource, please retry."
+ "FETCH_FAILED": "Unable to fetch resource, please retry.",
+ "SHADER_UPLOAD_FAIL": "Failed to upload shader cache with status code {status}.",
+ "SHADER_WEBHOOK_FAIL": "Failed to post shader cache, please share the following details in the discord server:{details}"
}
diff --git a/src/renderer/i18n/es.json b/src/renderer/i18n/es.json
index 33fde571..8d1ac98f 100644
--- a/src/renderer/i18n/es.json
+++ b/src/renderer/i18n/es.json
@@ -33,7 +33,7 @@
"refreshInfo": "Se refrescó correctamente! Ten en cuenta que tu juego solo se mostrará si lo abriste al menos una vez en el emulador",
"modInstalled": "Mod instalado correctamente en: {path}
",
"shaderInfo": "Shaders son pequeños programas que corren en una tarjeta gráfica que son responsables de renderizar terrenos, personajes, explosiones, pasto, etc. Como una PC no puede ejecutar directamente los shaders, primero tiene que traducirlos a un formato que la PC pueda entender. Este proceso de traducción consume bastante tiempo y lo notarás en dos maneras :
- Cualquier shader nuevo que sea encontrado, causará que la emulación se detenga hasta que la traducción haya sido finalizada, lo que causa trabas y caída de FPS. Cuando cargás un juego por primera vez, mucha traducción pasará. Al estar jugando mas tiempo, las trabas serán cada vez menos.
- El emulador guardara cualquier shader que el juego utilice (osea los convierte en caché). Cuando inicias un juego, el emulador se tomará un tiempo cargando esos shaders guardados para prevenir las trabas que pasaban antes.",
- "shaderThreshold": "Eso significa que puedes compartir shaders si tu conteo de shaders local es mayor al que ya tiene RyuSAK. Esto es basado en cuantas submisiones ya tenemos y nuestra carga de trabajo. Revisando nuestras submisiones puede consumir bastante tiempo y no vale nuestro esfuerzo si el recuento está por debajo de la variable umbral. Submisiones están limitadas a 3 por usuario por hora por ahora para prevenir que los servidores sean sobrecargados.",
+ "shaderThreshold": "Eso significa que puedes compartir shaders si tu conteo de shaders local es mayor al que ya tiene RyuSAK.",
"localShadersCount": "Conteo de shaders locales",
"ryusakShadersCount": "Conteo de shaders en la nube de RyuSAK",
"dlShaders": "Descargar Shaders",
@@ -42,7 +42,6 @@
"threshold": "Umbral",
"refresh": "Refrescar",
"OPERATION_CANCELED": "Has cancelado la operación.",
- "INVALID_RYUJINX_BINARY": "Este no es un archivo binario válido de Ryujinx.",
"EMULATOR_PATH_ALREADY_EXISTS": "Ya has agregado este directorio a RyuSAK.",
"FETCH_FAILED": "No se pudo conseguir el recurso, por favor inténtelo de nuevo."
}
diff --git a/src/renderer/i18n/it.json b/src/renderer/i18n/it.json
index 9d5965fb..8583dcec 100644
--- a/src/renderer/i18n/it.json
+++ b/src/renderer/i18n/it.json
@@ -4,9 +4,8 @@
"deleteGame": "Cancella gioco",
"areYouSure": "Sei sicuro/a ?",
"deleteGameNotice": " Questa opzione cancellerà la tua shader cache, cache della CPU e la cartella dei mods per questo gioco. Questa azione non potrà essere annulata.",
- "shadersCheck": "Poi devi aprire il tuo gioco in Ryujinx per permettere a RyuSAK di verificare che tutto funzioni come si deve per tutti.",
"shadersSharing": "Condividendo i Shaders ...",
- "shadersShared": "I tuoi shaders sono stati caricati! Li puoi trovare nel #ryu-shaders
canale. Una volta approvati saranno condivisi a tutti!",
+ "shadersShared": "I tuoi shaders sono stati caricati!",
"gamebananaModsTitle": "Mods da Gamebanana (fino alle 20 mods piu scaricate su GameBanana)",
"gamebananaNoMods": "Nessuna mod trovata su Gamebanana",
"gameBananaLoading": "Caricando mods da Gamebanana ...",
@@ -44,7 +43,7 @@
"refreshInfo": "Aggiornato con successo, nota che il tuo gioco sarà mostrato solo se lo hai avviato almeno una volta nell'emulatore",
"modInstalled": "Mod installata con successo in : {path}
",
"shaderInfo": "Gli shader sono piccoli programmi in esecuzione su una scheda grafica che sono responsabili del rendering della grafica come terreno, personaggi, esplosioni, erba, ecc. Poiché un PC non può eseguire direttamente gli shader, deve prima tradurli in un formato che il PC possa capire. Questo processo di traduzione consuma molto tempo, infatti:
- Qualsiasi nuovo shaders che si incontra causerà una pausa nell'emulazione fino a quando la traduzione non sarà terminata, che causa stuttering e cali di FPS. Quando si carica un gioco per la prima volta, accadrà un sacco di traduzione. Giocando di più questo stuttering diminuisce rapidamente.
- L'emulatore salverà tutti gli shader utilizzati da un gioco (ovvero li memorizzerà nella cache). Quando si avvia un gioco, l'emulatore impiegherà un po' di tempo a caricare quegli shader salvati per evitare che lo stuttering si ripeta",
- "shaderThreshold": "Ciò significa che potete condividere gli shader se il vostro numero di shader locali supera quello di RyuSAK di questo valore. Questo si basa su quanti invii abbiamo già e sul nostro carico di lavoro. Esaminare le vostre richieste richiede molto tempo e non vale il nostro sforzo se il conteggio è al di sotto della variabile di soglia. Le richieste sono limitate a 3 per utente all'ora",
+ "shaderThreshold": "Ciò significa che potete condividere gli shader se il vostro numero di shader locali supera quello di RyuSAK di questo valore.",
"localShadersCount": "Quantità di shaders Locali",
"ryusakShadersCount": "Quantità di shaders di RyuSAK",
"dlShaders": "Scarica shaders",
@@ -52,8 +51,6 @@
"threshold": "Soglia",
"refresh": "Ricarica",
"OPERATION_CANCELED": "Hai annulato questa operazione.",
- "INVALID_RYUJINX_BINARY": "Questo non è un valido file binario di Ryujinx",
- "INVALID_YUZU_BINARY": "Questo non è un valido file binario di Yuzu",
"EMULATOR_PATH_ALREADY_EXISTS": "Hai già aggiunto questo percorso a RyuSAK.",
"FETCH_FAILED": "Impossibile prendere la risorsa, per favore riprova."
}
diff --git a/src/renderer/i18n/ru.json b/src/renderer/i18n/ru.json
index 928bd0e2..265fae38 100644
--- a/src/renderer/i18n/ru.json
+++ b/src/renderer/i18n/ru.json
@@ -34,7 +34,7 @@
"refreshInfo": "Обновление выполнено успешно. Обратите внимание, что ваша игра будет отображаться только в том случае, если вы запустили ее один раз в эмуляторе.",
"modInstalled": "Модификация успешно установлена в : {path}
",
"shaderInfo": "Шейдеры — это небольшие программы, работающие на видеокарте, которые отвечают за рендеринг графики, такой как ландшафт, персонажи, взрывы, трава и т. д. Поскольку ПК не может напрямую выполнять шейдеры, он сначала должен преобразовать их в формат, понятный ПК. Этот процесс перевода занимает много времени, и вы заметите это двумя способами:
- Любые новые шейдеры, которые встречаются, приведут к приостановке эмуляции до тех пор, пока перевод не будет выполнен, что вызывает заикание и падение FPS. Когда вы загружаете игру в первый раз, происходит много переводов. Чем больше вы играете, тем быстрее уменьшается заикание.
– Эмулятор сохраняет все используемые игрой шейдеры (т. е. кэширует их). Когда вы запускаете игру, эмулятору потребуется некоторое время, чтобы загрузить эти сохраненные шейдеры, чтобы предотвратить повторение заиканий.",
- "shaderThreshold": "Это означает, что вы можете делиться шейдерами, если ваше локальное количество шейдеров превышает количество шейдеров RyuSAK на это значение. Это зависит от того, сколько заявок у нас уже есть, и от нашей рабочей нагрузки. Просмотр отправленных вами материалов занимает очень много времени, и если количество запросов ниже пороговой переменной, это не стоит наших усилий. На данный момент отправка ограничена 3 на пользователя в час.",
+ "shaderThreshold": "Это означает, что вы можете делиться шейдерами, если ваше локальное количество шейдеров превышает количество шейдеров RyuSAK на это значение.",
"localShadersCount": "Количество локальных шейдеров",
"ryusakShadersCount": "Количество шейдеров RyuSAK",
"dlShaders": "Скачать шейдеры",
@@ -43,8 +43,6 @@
"threshold": "Порог",
"refresh": "Обновить",
"OPERATION_CANCELED": "Вы отменили операцию.",
- "INVALID_RYUJINX_BINARY": "Это недопустимый двоичный файл Ryujinx.",
- "INVALID_YUZU_BINARY": "Это недопустимый двоичный файл Yuzu.",
"EMULATOR_PATH_ALREADY_EXISTS": "Вы уже добавили этот путь в RyuSAK.",
"FETCH_FAILED": "Не удалось получить ресурс. Повторите попытку."
}
diff --git a/src/renderer/i18n/se.json b/src/renderer/i18n/se.json
index 098a0ed9..8e520fe3 100644
--- a/src/renderer/i18n/se.json
+++ b/src/renderer/i18n/se.json
@@ -33,14 +33,13 @@
"refreshInfo": "Uppdateringen lyckades! Observera att ditt spel endast kommer att visas om du har startat det minst en gång i emulatorn",
"modInstalled": "Mod installerades på : {path}
",
"shaderInfo": "Shaders är små program som körs på ett grafikkort som är ansvariga för att återge grafik som terräng, karaktärer, explosioner, gräs etc. Eftersom en PC inte direkt kan exekvera shaders, måste den först översätta dem till ett format som en PC kan förstå. Den här översättningsprocessen är tidskrävande och du kommer att märka den på två sätt:
- Alla nya shaders som påträffas kommer att göra att emuleringen pausas tills översättningen är klar, vilket orsakar stamning och FPS-fall. När du laddar ett spel för första gången kommer en hel del översättningar att hända. Genom att spela mer minskar denna stamning snabbt.
- Emulatorn sparar alla shaders som ett spel använder (aka den cachar dem). När du startar ett spel kommer emulatorn att ta lite tid att ladda de sparade shaders för att förhindra att stamningen händer igen.",
- "shaderThreshold": "Det betyder att du kan dela Shaders om ditt lokala Shader-antal överstiger RyuSAKs antal med detta värde. Detta är baserat på hur många inlämningar vi redan har och vår arbetsbelastning. Att granska dina bidrag är mycket tidskrävande och det är inte värt vår ansträngning om antalet är under shaders- variabeln. Inlämning är begränsad till 3 per användare och timme för närvarande för att förhindra att servrarna överbelastas.",
+ "shaderThreshold": "Det betyder att du kan dela Shaders om ditt lokala Shader-antal överstiger RyuSAKs antal med detta värde.",
"localShadersCount": "Lokal shaders count",
"ryusakShadersCount": "RyuSAK shaders count",
"dlShaders": "Ladda ner shaders",
"shareShaders": "Dela shaders",
"refresh": "Uppdatera",
"OPERATION_CANCELED": "Du avbröt operationen.",
- "INVALID_RYUJINX_BINARY": "Detta är inte en giltig Ryujinx binary fil.",
"EMULATOR_PATH_ALREADY_EXISTS": "Du har redan lagt till den här path till RyuSAK.",
"FETCH_FAILED": "Det gick inte att hämta resursen, försök igen."
}
diff --git a/src/renderer/i18n/tr.json b/src/renderer/i18n/tr.json
index acc0c3ef..45efe886 100644
--- a/src/renderer/i18n/tr.json
+++ b/src/renderer/i18n/tr.json
@@ -1,5 +1,4 @@
{
- "SHADER_CACHE_V1": "RyuSAK, Ryujinx V1 shader cache kullandığınızı tespit etti. Ryujinx geliştiricileri bu shader cache'in birçok yenilik içeren yeni bir sürümünü geliştirdiler. Shader paylaşmadan önce, oyunu Ryujinx'te açın, Ryujinx eski cache'i yeni cache'e dönüştürecektir. Bu işlemden sonra RyuSAK'ı tekrar açıp paylaşabilirsiniz.",
"continue": "Devam et",
"cancel": "İptal",
"save": "Save",
@@ -8,9 +7,8 @@
"deleteGame": "Oyunu sil",
"areYouSure": "Emin misiniz ?",
"deleteGameNotice": "Bu seçenek bu oyunun shader cache, CPU cache ve mod klasörlerini silecektir. Bu eylem geri alınamaz!",
- "shadersCheck": "Sonra Ryusak'ın her şeyin herkes için sorunsuz çalıştığını kontrol edebilmesi için oyununuzu Ryujinx'te açmanız gerek.",
"shadersSharing": "Shader paylaşılıyor ...",
- "shadersShared": "Shaderlarınız paylaşıldı! Paylaşılan shaderları #ryu-shaders
kanalında bulabilirsiniz. Shaderlar kontrol edilip onaylandıktan sonra herkese açık hale getirilecekler!",
+ "shadersShared": "Shaderlarınız paylaşıldı!",
"gamebananaModsTitle": "Gamebanana modları (Gamebanana'da en çok indirilen 20 ye kadar mod)",
"gamebananaNoMods": "Gamebanana'da mod bulunmuyor",
"gameBananaLoading": "Gamebanana'dan modlar yükleniyor ...",
@@ -50,7 +48,7 @@
"refreshInfo": "Yenileme başarılı! Oyununuzun gözükmesi için en az bir kere açmış olmanız gerektiğini unutmayın",
"modInstalled": "Mod belirtilen dizine başarıyla yüklendi : {path}
",
"shaderInfo": "Shaderlar; arazi, karakterler, patlamalar ve çimen gibi grafiklerin oluşturulmasından sorumlu, grafik işlemci biriminde çalışan küçük programlardır. Bilgisayar shaderları doğrudan anlayıp işleyemediği için önce işleyebileceği bir biçime çevirmesi gerekmektedir. Bu çeviri süreci zaman alır. Bunu iki şekilde görebilirsiniz:
- Yeni görülen shaderlar emülasyonun çeviri işlemini bitene kadar duraksamasına sebep olur, bu da kullanıcıya duraksamalar ve fps düşmesi şeklinde gözükür. Bir oyunu ilk defa açtığınızda birçok çeviri işlemi gerçekleşecektir. Oynadıkça bu yavaşlamalar azalacaktır.
- Emülator oyunun kullandığı shaderları işledikten sonra kaydedecektir (belleğe alacaktır). Oyunu tekrar açtığınızda emülatör önceki duraksamaların yaşanmaması için belleklenen shaderları yükleyeceğinden oyun daha yavaş açılacaktır.",
- "shaderThreshold": "Bu sayı shader paylaşma alt limitidir. Yerel shader sayınız RyuSAK'taki shader sayısından bu sayı kadar fazla ise shaderlarınızı paylaşabilirsiniz. Bu sayı paylaşan kişi sayısına ve meşguliyet durumumuza bağlıdır. Paylaşılan shaderları gözden geçirmemiz çok zaman aldığı için alt limitin altındaki eklemeler gözden geçirmemize değmez. Aşırı yüklenmeyi engellemek için şimdilik kişi başına saat başı 3 tane shader paylaşımı yapılabilir.",
+ "shaderThreshold": "Bu sayı shader paylaşma alt limitidir. Yerel shader sayınız RyuSAK'taki shader sayısından bu sayı kadar fazla ise shaderlarınızı paylaşabilirsiniz.",
"localShadersCount": "Yerel shader sayısı",
"ryusakShadersCount": "RyuSAK shader sayısı",
"dlShaders": "Shader indir",
@@ -59,7 +57,6 @@
"threshold": "Alt sınır",
"refresh": "Yenile",
"OPERATION_CANCELED": "İşlemi iptal ettiniz.",
- "INVALID_RYUJINX_BINARY": "Seçtiğiniz Ryujinx binary dosyası geçerli değil.",
"EMULATOR_PATH_ALREADY_EXISTS": "Bu dizini RyuSAK'a zaten eklediniz.",
"FETCH_FAILED": "Kaynağa erişilemedi, lütfen tekrar deneyin."
}
diff --git a/src/renderer/i18n/zh-CN.json b/src/renderer/i18n/zh-CN.json
index 819b8e02..8523a592 100644
--- a/src/renderer/i18n/zh-CN.json
+++ b/src/renderer/i18n/zh-CN.json
@@ -1,5 +1,4 @@
{
- "SHADER_CACHE_V1": "RyuSAK 检测到您正在使用 Ryujinx 的 V1 着色器缓存。模拟器开发人员创建了此着色器缓存的新版本,并进行了大量改进。在共享着色器之前,在 Ryujinx 中启动游戏,模拟器会将旧缓存转换为新的自动然后重新打开 RyuSAK。",
"continue": "继续",
"cancel": "取消",
"save": "保存",
@@ -8,9 +7,8 @@
"deleteGame": "删除游戏",
"areYouSure": "你确定吗?",
"deleteGameNotice": "此选项将删除此游戏的着色器缓存、CPU 缓存和模组文件夹。此操作无法撤消。",
- "shadersCheck": "那么你必须用 Ryujinx 运行你的游戏,这样 RyuSAK 才能检查每个人的一切是否按预期工作。如果你一直在使用 vulkan PR,请不要尝试共享着色器,因为它不会工作到现在...",
"shadersSharing": "共享着色器...",
- "shadersShared": "您的着色器已提交!您可以在#ryu-shaders
频道找到它们。一旦批准,它们将分享给大家下载!",
+ "shadersShared": "您的着色器已提交!",
"gamebananaModsTitle": "Gamebanana 模组(GameBanana 上最多 20 个下载次数最多的模组)",
"gamebananaNoMods": "在 Gamebanana 上找不到任何模组",
"gameBananaLoading": "正在从 Gamebanana 加载模组 ...",
@@ -49,7 +47,7 @@
"refreshInfo": "刷新成功!请注意,只会显示您在模拟器中至少启动过一次的游戏。",
"modInstalled": "Mod 成功安装在:{path}
",
"shaderInfo": "着色器是运行在显卡上的小程序,负责渲染地形、人物、爆炸、草等图形。由于 PC 不能直接执行 Switch 的着色器,它首先必须将它们转换为您的格式PC 可以理解。这个转换过程很耗时,你会从两个方面注意到它:
- 遇到任何新的着色器都会导致模拟暂停,直到转换完成,这会导致卡顿和 FPS 下降。当您第一次加载游戏时,会发生很多转换。玩得越多,这种卡顿就会迅速减少。
- 模拟器将保存游戏使用的任何着色器(AKA 它缓存他们)。当您启动游戏时,模拟器将需要一些时间来加载保存的着色器,以防止再次发生卡顿。",
- "shaderThreshold": "如果您的本地 Shader 计数超过 RyuSAK 的计数至少这个值,您可以共享着色器。这是基于我们已经有多少提交和我们的工作量。审查提交非常耗时,不值得我们努力如果额外的着色器计数低于阈值。现在每个用户每小时的提交限制为 3 次,以防止服务器过载。",
+ "shaderThreshold": "如果您的本地 Shader 计数超过 RyuSAK 的计数至少这个值,您可以共享着色器。",
"localShadersCount": "本地着色器计数",
"ryusakShadersCount": "RyuSAK 着色器计数",
"dlShaders": "下载着色器",
@@ -58,7 +56,6 @@
"threshold": "阈值",
"refresh": "刷新",
"OPERATION_CANCELED": "你取消了操作。",
- "INVALID_RYUJINX_BINARY": "这不是一个有效的 Ryujinx 二进制文件。",
"EMULATOR_PATH_ALREADY_EXISTS": "您已经将此路径添加到 RyuSAK。",
"FETCH_FAILED": "无法获取资源,请重试。"
}
diff --git a/src/renderer/resources/pirate.gif b/src/renderer/resources/dance.gif
similarity index 100%
rename from src/renderer/resources/pirate.gif
rename to src/renderer/resources/dance.gif
diff --git a/src/types.ts b/src/types.ts
index 4469ee81..725c85c4 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -7,6 +7,15 @@ export type MirrorFileMeta = {
export type MirrorDirMeta = Array;
+export type MirrorUploadResponse = {
+ fileSize: number,
+ fileName: string,
+ fileId: string,
+ contentType: string,
+ deletionTime: string,
+ deletionToken: string
+}
+
export type RyusakShaders = {
[key: string]: number;
};