Added files

This commit is contained in:
2025-04-04 22:10:30 +02:00
parent f7d6562bbe
commit 37524d7a0c
7 changed files with 569 additions and 0 deletions

52
css/_style.css Normal file
View File

@@ -0,0 +1,52 @@
:root {
--background-color: #1c1c1c;
--primary: #e3e3e3;
}
body {
background-color: var(--background-color);
margin: 0;
}
main {
display: grid;
min-height: 100vh;
place-items: center;
}
header {
color: var(--primary);
}
/*#file {
display: block;
border: 1px solid white;
border-radius: 100vw;
width: 400px;
height: 400px;
background-color: white;
}*/
#input {
display: none;
}
#upload {
display: block;
border: 1px solid var(--primary);
border-radius: 100vw;
width: 400px;
height: 400px;
background-color: var(--primary);
cursor: pointer;
}
#upload > span {
font-size: 2em;
color: var(--background-color);
}

190
css/style.css Normal file
View File

@@ -0,0 +1,190 @@
:root {
--col-dark: #1C1C1C;
--col-light: #E3E3E3;
}
@font-face {
font-family: 'Lato';
src: url('../fonts/Lato-Regular.ttf');
src: url('../fonts/Lato-Regular.ttf') format('truetype');
}
html, body {
margin: 0;
}
body {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
width: 100vw;
height: 100vh;
overflow: hidden;
background: var(--col-dark);
}
section {
color: var(--col-light);
font-family: Lato;
}
a {
color: var(--col-light);
text-decoration: none;
}
a[rel="author"] {
justify-self: end;
}
a[rel="author"]::before {
content: " - ";
}
main {
display: grid;
grid-template-columns: 1fr;
grid-template-rows: 1fr;
gap: 1rem;
}
section {
display: grid;
place-content: center;
place-items: center;
margin: 0 4rem;
}
section * {
margin: .2rem 0;
}
.btn {
cursor: pointer;
}
.btn:focus {
outline: none;
}
.btn.cbtn {
display: grid;
place-content: center;
place-items: center;
position: relative;
padding: 2.2rem;
width: 0;
height: 0;
border: none;
background: none;
font: unset;
border-radius: 100vw;
}
.btn.cbtn > i {
display: grid;
place-items: center;
}
.btn.cbtn > i::after {
content: "";
display: grid;
place-content: center;
position: absolute;
z-index: 1000;
overflow: hidden;
padding: 0rem;
background-color: var(--col-light);
color: var(--col-dark);
width: 0;
height: 0;
border-radius: 100vw;
transition: padding .2s, background-color .2s, color .2s;
}
.btn.cbtn:hover > i::after,
.btn.cbtn.dragover > i::after {
padding: var(--padding);
}
@keyframes cbtn-click {
from {
padding: 0rem;
opacity: 1;
}
to {
padding: calc(var(--padding) * 1.3);
opacity: 0;
}
}
.btn.cbtn > .click {
position: absolute;
padding: 0rem;
opacity: 1;
z-index: 10000;
border-radius: 100vw;
width: 0;
height: 0;
/*box-shadow: inset 0 0 2px #FFF;*/
background: #DDD8;
border: 4px solid #fff;
animation: cbtn-click .2s;
}
.btn.cbtn {
--padding: 5vmin;
padding: var(--padding);
font-size: 3vmin;
}
.btn.cbtn.medium {
--padding: 5vmin;
padding: var(--padding);
font-size: 3vmin;
}
.btn.cbtn.big {
--padding: 30vmin;
padding: var(--padding);
font-size: 8vmin;
}
.btn.cbtn.overlap {
margin: -1vmin;
}
footer {
display: grid;
grid-auto-columns: min-content;
grid-auto-flow: column;
padding: 3vmin;
}
#input {
display: none;
}
#button_text {
font-style: normal;
}
#button_text::before, #button_text::after {
content: "Drag & Drop Yuzu Executable here";
text-align: center;
}
.dragover {
--col-dark: #1C1C1C;
--col-light: #82DD90;
}

BIN
fonts/Lato-Regular.ttf Normal file

Binary file not shown.

32
index.html Normal file
View File

@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>YUZU Patcher</title>
<link rel="stylesheet" href="./css/style.css">
<script src="./js/FileSaver.js"></script>
<script src="./js/main.js"></script>
<script src="./js/button.js"></script>
</head>
<body>
<main>
<section>
<h1>A yuzu Emulator fork patcher</h1>
<p>
yuzu forks often change the application and engine name given to Vulkan.
<br>
This has the side effect of not applying a driver level patch by AMD for RDNA3 graphic cards, causing visual issues.
<br>
This tool replaces the application and engine name given to Vulkan with yuzu's.
</p>
<a rel="author">Sunpy</a>
<a id="upload" class="big btn cbtn" style="margin-top:6vmin">
<i id="button_text"></i>
<input type="file" id="input" />
</a>
</section>
</main>
<footer></footer>
</body>
</html>

172
js/FileSaver.js Normal file
View File

@@ -0,0 +1,172 @@
/*
* FileSaver.js
* A saveAs() FileSaver implementation.
*
* By Eli Grey, http://eligrey.com
*
* License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
* source : http://purl.eligrey.com/github/FileSaver.js
*/
// The one and only way of getting global scope in all environments
// https://stackoverflow.com/q/3277182/1008999
var _global = typeof window === 'object' && window.window === window
? window : typeof self === 'object' && self.self === self
? self : typeof global === 'object' && global.global === global
? global
: this
function bom (blob, opts) {
if (typeof opts === 'undefined') opts = { autoBom: false }
else if (typeof opts !== 'object') {
console.warn('Deprecated: Expected third argument to be a object')
opts = { autoBom: !opts }
}
// prepend BOM for UTF-8 XML and text/* types (including HTML)
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type })
}
return blob
}
function download (url, name, opts) {
var xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.responseType = 'blob'
xhr.onload = function () {
saveAs(xhr.response, name, opts)
}
xhr.onerror = function () {
console.error('could not download file')
}
xhr.send()
}
function corsEnabled (url) {
var xhr = new XMLHttpRequest()
// use sync to avoid popup blocker
xhr.open('HEAD', url, false)
try {
xhr.send()
} catch (e) {}
return xhr.status >= 200 && xhr.status <= 299
}
// `a.click()` doesn't work for all browsers (#465)
function click (node) {
try {
node.dispatchEvent(new MouseEvent('click'))
} catch (e) {
var evt = document.createEvent('MouseEvents')
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80,
20, false, false, false, false, 0, null)
node.dispatchEvent(evt)
}
}
// Detect WebView inside a native macOS app by ruling out all browsers
// We just need to check for 'Safari' because all other browsers (besides Firefox) include that too
// https://www.whatismybrowser.com/guides/the-latest-user-agent/macos
var isMacOSWebView = _global.navigator && /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent)
var saveAs = _global.saveAs || (
// probably in some web worker
(typeof window !== 'object' || window !== _global)
? function saveAs () { /* noop */ }
// Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView
: ('download' in HTMLAnchorElement.prototype && !isMacOSWebView)
? function saveAs (blob, name, opts) {
var URL = _global.URL || _global.webkitURL
// Namespace is used to prevent conflict w/ Chrome Poper Blocker extension (Issue #561)
var a = document.createElementNS('http://www.w3.org/1999/xhtml', 'a')
name = name || blob.name || 'download'
a.download = name
a.rel = 'noopener' // tabnabbing
// TODO: detect chrome extensions & packaged apps
// a.target = '_blank'
if (typeof blob === 'string') {
// Support regular links
a.href = blob
if (a.origin !== location.origin) {
corsEnabled(a.href)
? download(blob, name, opts)
: click(a, a.target = '_blank')
} else {
click(a)
}
} else {
// Support blobs
a.href = URL.createObjectURL(blob)
setTimeout(function () { URL.revokeObjectURL(a.href) }, 4E4) // 40s
setTimeout(function () { click(a) }, 0)
}
}
// Use msSaveOrOpenBlob as a second approach
: 'msSaveOrOpenBlob' in navigator
? function saveAs (blob, name, opts) {
name = name || blob.name || 'download'
if (typeof blob === 'string') {
if (corsEnabled(blob)) {
download(blob, name, opts)
} else {
var a = document.createElement('a')
a.href = blob
a.target = '_blank'
setTimeout(function () { click(a) })
}
} else {
navigator.msSaveOrOpenBlob(bom(blob, opts), name)
}
}
// Fallback to using FileReader and a popup
: function saveAs (blob, name, opts, popup) {
// Open a popup immediately do go around popup blocker
// Mostly only available on user interaction and the fileReader is async so...
popup = popup || open('', '_blank')
if (popup) {
popup.document.title =
popup.document.body.innerText = 'downloading...'
}
if (typeof blob === 'string') return download(blob, name, opts)
var force = blob.type === 'application/octet-stream'
var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent)
if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && typeof FileReader !== 'undefined') {
// Safari doesn't allow downloading of blob URLs
var reader = new FileReader()
reader.onloadend = function () {
var url = reader.result
url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;')
if (popup) popup.location.href = url
else location = url
popup = null // reverse-tabnabbing #460
}
reader.readAsDataURL(blob)
} else {
var URL = _global.URL || _global.webkitURL
var url = URL.createObjectURL(blob)
if (popup) popup.location = url
else location.href = url
popup = null // reverse-tabnabbing #460
setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s
}
}
)
_global.saveAs = saveAs.saveAs = saveAs
if (typeof module !== 'undefined') {
module.exports = saveAs;
}

14
js/button.js Normal file
View File

@@ -0,0 +1,14 @@
addEventListener("load", () => {
const onAnimationFinished = (e) => {
e.target.remove();
};
const onClick = (e, btn) => {
const clickElement = document.createElement("div");
clickElement.className = "click";
clickElement.addEventListener("animationend", onAnimationFinished);
btn.appendChild(clickElement);
};
for (const btn of document.getElementsByClassName("btn")) {
btn.addEventListener("click", (e) => onClick(e, btn) );
};
});

109
js/main.js Normal file
View File

@@ -0,0 +1,109 @@
const VK_PATTERN = (new TextEncoder()).encode("vkDestroyInstance");
const YUZU_PATTERN = (new TextEncoder()).encode("yuzu Emulator");
addEventListener("load", () => {
const input = document.getElementById("input");
const button = document.getElementById("upload");
input.addEventListener("change", (e) => {
if (e.target.files.length) {
handleFile(e.target.files[0]);
}
});
button.addEventListener("click", () => input.click());
button.addEventListener("drop", (e) => {
e.preventDefault();
button.classList.remove("dragover");
if (e.dataTransfer.files.length) {
handleFile(e.dataTransfer.files[0]);
}
});
button.addEventListener("dragover", (e) => {
e.preventDefault();
button.classList.add("dragover");
});
button.addEventListener("dragleave", (e) => {
button.classList.remove("dragover");
});
});
/**
* @param {File} file
*/
function handleFile(file) {
const filename = file.name ?? "yuzu.exe";
const reader = new FileReader();
reader.onload = (e) => {
const buff = e.target.result;
const view = new DataView(buff);
const patternLen = VK_PATTERN.byteLength;
const buffLen = buff.byteLength;
// Find the pattern
let foundIndex = -1;
for (let i = 0; i <= buffLen - patternLen; i++) {
let found = true;
for (let j = 0; j < patternLen; j++) {
if (view.getUint8(i + j) !== VK_PATTERN[j]) {
found = false;
break;
}
}
if (found) {
foundIndex = i;
break;
}
}
if (foundIndex == -1) {
console.error("Could not find pattern in file");
alert("Could not find pattern in file");
return;
}
// Walk backwards until we hit the start of the Emulator string
let startIndex = -1;
let emuLen = 0;
for (let i = foundIndex - 2;; i--) { // skip over first 0 byte right before current index
if (view.getUint8(i) == 0) {
startIndex = i + 1;
break;
}
emuLen++;
}
const yuzuLen = YUZU_PATTERN.byteLength;
if (emuLen < yuzuLen) {
console.error("Cannot patch emulator with smaller default name then yuzu");
alert("Cannot patch emulator with smaller default name then yuzu");
return;
}
if (emuLen == yuzuLen) {
let isYuzu = true;
for (let i = 0; i < emuLen; i++) {
if (view.getUint8(startIndex + i) != YUZU_PATTERN[i]) {
isYuzu = false;
break;
}
}
if (isYuzu) {
console.error("Either this is an already patched fork or its real yuzu");
alert("Either this is an already patched fork or its real yuzu");
return;
}
}
for (let i = 0; i < emuLen; i++) {
view.setUint8(startIndex + i, YUZU_PATTERN[i] || 0);
}
const blobPatched = new Blob([buff]);
saveAs(blobPatched, filename.replace(".exe", "_patched.exe"));
}
reader.readAsArrayBuffer(file);
}