mirror of
				https://github.com/OpenFusionProject/Client.git
				synced 2025-10-31 03:10:11 +00:00 
			
		
		
		
	Compare commits
	
		
			50 Commits
		
	
	
		
			1.4.3
			...
			d52e149192
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | d52e149192 | ||
|   | 16a158906d | ||
|   | 7f9c5d90a1 | ||
|   | 17f194810c | ||
|   | 87072b0789 | ||
|   | e933bc52fe | ||
|   | 1078778e16 | ||
|   | 5dca39a17e | ||
|   | 0eca42cdf8 | ||
|   | fa0bdd7b1a | ||
|   | feafd8d17f | ||
|   | 6a7b029539 | ||
|   | 171177b606 | ||
|   | 1c2cf41e97 | ||
|   | 0201f11333 | ||
|   | a859590ef9 | ||
|   | 356e811bac | ||
|   | cdabb36639 | ||
|   | 547ca778b0 | ||
|   | 6bae0d1ff6 | ||
|   | 11f0c61a67 | ||
|   | 1d78bc2d9b | ||
|   | c78a3e5ada | ||
|   | c05e9c0dcd | ||
|   | e1ef76744a | ||
|   | 04aea6059e | ||
|   | 600b33a230 | ||
|   | 48efd00a4a | ||
|   | f28c9c0bb8 | ||
|   | e3f16d8fc9 | ||
|   | 6f7f1655b9 | ||
|   | 597e80b112 | ||
|   | 79bdba74a5 | ||
|   | 16a99f86c7 | ||
|   | 05af8a3f9e | ||
|   | 27f0992b52 | ||
|   | 132b725922 | ||
|   | b5ab9aad2d | ||
|   | 01ee292d10 | ||
|   | 2183106c73 | ||
|   | db7370ca41 | ||
|   | ec0fc87dcd | ||
|   | cef8c1de93 | ||
|   | b73329c6de | ||
|   | 2e7dc51aa1 | ||
|   | 3fc6cabe33 | ||
|   | 71e4694ff6 | ||
|   | 76f4a05287 | ||
|   | 97144aad59 | ||
|   | 4a465ca689 | 
							
								
								
									
										19
									
								
								.editorconfig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								.editorconfig
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| # top-most EditorConfig file | ||||
| root = true | ||||
|  | ||||
| # Unix-style newlines with a newline ending every file | ||||
| [*] | ||||
| end_of_line = lf | ||||
| insert_final_newline = true | ||||
|  | ||||
| # 4 space indentation | ||||
| [*.js, *.css, *.html, *.json] | ||||
| indent_style = space | ||||
| indent_size = 4 | ||||
|  | ||||
| # Don't enforce anything in vendored code | ||||
| [*.min.*] | ||||
| end_of_line = unset | ||||
| insert_final_newline = unset | ||||
| indent_style = unset | ||||
| indent_style = unset | ||||
							
								
								
									
										3
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							| @@ -3,3 +3,6 @@ | ||||
| *.js    text eol=lf | ||||
| *.json  text eol=lf | ||||
| *.md    text eol=lf | ||||
|  | ||||
| defaults/* linguist-vendored | ||||
| lib/* linguist-vendored | ||||
|   | ||||
							
								
								
									
										47
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								.github/workflows/build.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| name: Publish Build | ||||
|  | ||||
| on: | ||||
|   push: | ||||
|     branches: [ "main" ] | ||||
|     tags: '*' | ||||
|  | ||||
| permissions: | ||||
|   contents: write | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|     runs-on: windows-2022 | ||||
|  | ||||
|     steps: | ||||
|     - uses: actions/checkout@v4 | ||||
|       with: | ||||
|         fetch-depth: 0 | ||||
|     - name: Set up Node.js 20.x | ||||
|       uses: actions/setup-node@v4 | ||||
|       with: | ||||
|         node-version: 20.x | ||||
|         cache: 'npm' | ||||
|     - name: Install dependencies | ||||
|       run: npm install | ||||
|     - name: Pack into zip and create installer | ||||
|       run: npm run dist | ||||
|     - name: Upload Artifacts | ||||
|       uses: actions/upload-artifact@master | ||||
|       with: | ||||
|         path: dist | ||||
|  | ||||
|   publish-release: | ||||
|     if: contains(github.ref, 'refs/tags/') | ||||
|     runs-on: ubuntu-latest | ||||
|     needs: build | ||||
|      | ||||
|     steps: | ||||
|     - name: Download artifact | ||||
|       uses: actions/download-artifact@master | ||||
|     - name: Create release | ||||
|       uses: ncipollo/release-action@v1 | ||||
|       with: | ||||
|         artifacts: "artifact/*-ia32-win.zip,artifact/*.exe" | ||||
|       env: | ||||
|         GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|         GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -8,4 +8,8 @@ version | ||||
| resources/app/files/rankurl.txt | ||||
| node_modules/ | ||||
| dist/ | ||||
| UnityBugReporter.exe | ||||
| UnityBugReporter.exe | ||||
| cache_handler/*/ | ||||
| extra/ | ||||
| *.sh | ||||
| yarn.lock | ||||
| @@ -1,6 +1,6 @@ | ||||
| MIT License | ||||
|  | ||||
| Copyright (c) 2020-2023 OpenFusion Contributors | ||||
| Copyright (c) 2020-2024 OpenFusion Contributors | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| # OpenFusionClient | ||||
|  | ||||
| [](https://github.com/OpenFusionProject/OpenFusionClient/releases/latest) [](https://discord.gg/DYavckB)[](https://github.com/OpenFusionProject/OpenFusionClient/blob/master/LICENSE.md) | ||||
| [](https://github.com/OpenFusionProject/OpenFusionClient/releases/latest) [](https://discord.gg/DYavckB)[](https://github.com/OpenFusionProject/OpenFusionClient/blob/master/LICENSE.md) | ||||
|  | ||||
| An Electron app that allows you to easily join FusionFall servers. | ||||
|  | ||||
|   | ||||
| @@ -80,6 +80,11 @@ body { | ||||
|     background-repeat: repeat; | ||||
| } | ||||
|  | ||||
| .btn-warning { | ||||
|     background-image: url("../../assets/img/btn-warning-bg.png"); | ||||
|     background-repeat: repeat; | ||||
| } | ||||
|  | ||||
| #of-aboutmodal > .modal-dialog > .modal-content { | ||||
|     background-color: #093363; | ||||
|     border-color: #6699ff; | ||||
| @@ -105,6 +110,36 @@ body { | ||||
|     border-color: #6699ff; | ||||
| } | ||||
|  | ||||
| #of-editcacheconfigmodal > .modal-dialog > .modal-content { | ||||
|     background-color: #093363; | ||||
|     border-color: #6699ff; | ||||
| } | ||||
|  | ||||
| #of-editconfigmodal > .modal-dialog > .modal-content { | ||||
|     background-color: #093363; | ||||
|     border-color: #6699ff; | ||||
| } | ||||
|  | ||||
| #of-addversionmodal > .modal-dialog > .modal-content { | ||||
|     background-color: #093363; | ||||
|     border-color: #6699ff; | ||||
| } | ||||
|  | ||||
| #of-editversionmodal > .modal-dialog > .modal-content { | ||||
|     background-color: #093363; | ||||
|     border-color: #6699ff; | ||||
| } | ||||
|  | ||||
| #of-deleteversionmodal > .modal-dialog > .modal-content { | ||||
|     background-color: #093363; | ||||
|     border-color: #6699ff; | ||||
| } | ||||
|  | ||||
| #of-restoreversionsmodal > .modal-dialog > .modal-content { | ||||
|     background-color: #093363; | ||||
|     border-color: #6699ff; | ||||
| } | ||||
|  | ||||
| .form-control, | ||||
| .form-control:focus { | ||||
|     border-color: #0099ff; | ||||
| @@ -118,6 +153,14 @@ select { | ||||
|     color: #fff; | ||||
| } | ||||
|  | ||||
| .modal { | ||||
|     overflow-y: auto; | ||||
| } | ||||
|  | ||||
| .invalidinput { | ||||
|     border-color: #ff0000; | ||||
| } | ||||
|  | ||||
| button:disabled { | ||||
|     cursor: not-allowed; | ||||
|     pointer-events: all !important; | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								assets/img/btn-warning-bg.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/img/btn-warning-bg.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 514 B | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 72 KiB | 
| @@ -1,10 +1,8 @@ | ||||
| // You're kind of ruining the surprise by reading this, but whatever | ||||
| var today = new Date(); | ||||
|  | ||||
| // Check Christmas season: Date constructor in Javascript uses an index | ||||
| // so 11 is Dec. of this year, and 12 is Jan. of the next | ||||
| var christmasBegin = new Date(today.getFullYear(), 11, 23); | ||||
| var christmasEnd = new Date(today.getFullYear(), 12, 8); | ||||
| var christmasBegin = new Date(today.getFullYear(), 11, 21); | ||||
| var christmasEnd = new Date(today.getFullYear(), 11, 31); | ||||
| var sf; | ||||
|  | ||||
| if (today >= christmasBegin && today <= christmasEnd) { | ||||
|   | ||||
| @@ -1,11 +1,28 @@ | ||||
| // TODO: path.join in this file, pass in json paths from index.js | ||||
| var remote = require("remote"); | ||||
| var remotefs = remote.require("fs-extra"); | ||||
| var dns = remote.require("dns"); | ||||
| var path = remote.require("path"); | ||||
| var dialog = remote.require("dialog"); | ||||
| var net = remote.require("net"); | ||||
| var spawn = require("child_process").spawn; | ||||
|  | ||||
| var userData = remote.require("app").getPath("userData"); | ||||
| var configPath = path.join(userData, "config.json"); | ||||
| var serversPath = path.join(userData, "servers.json"); | ||||
| var versionsPath = path.join(userData, "versions.json"); | ||||
| var cacheRoot = path.join( | ||||
|     userData, | ||||
|     "/../../LocalLow/Unity/Web Player/Cache" | ||||
| ); | ||||
| var offlineRootDefault = path.join(cacheRoot, "Offline"); | ||||
| var offlineRoot = offlineRootDefault; | ||||
|  | ||||
| var cdnString = "http://cdn.dexlabs.systems/ff/big"; | ||||
|  | ||||
| var userDir = remote.require("app").getPath("userData"); | ||||
| var versionArray; | ||||
| var serverArray; | ||||
| var cacheSizes; | ||||
| var defaultHashes; | ||||
| var config; | ||||
|  | ||||
| function enableServerListButtons() { | ||||
| @@ -26,10 +43,34 @@ function disableServerListButtons() { | ||||
|     $("#of-deleteserver-button").prop("disabled", true); | ||||
| } | ||||
|  | ||||
| function enableVersionAddButton() { | ||||
|     $("#of-addversion-button").removeClass("disabled"); | ||||
|     $("#of-addversion-button").prop("disabled", false); | ||||
| } | ||||
|  | ||||
| function enableVersionListButtons() { | ||||
|     $("#of-editversion-button").removeClass("disabled"); | ||||
|     $("#of-editversion-button").prop("disabled", false); | ||||
|     $("#of-deleteversion-button").removeClass("disabled"); | ||||
|     $("#of-deleteversion-button").prop("disabled", false); | ||||
| } | ||||
|  | ||||
| function disableVersionAddButton() { | ||||
|     $("#of-addversion-button").addClass("disabled"); | ||||
|     $("#of-addversion-button").prop("disabled", true); | ||||
| } | ||||
|  | ||||
| function disableVersionListButtons() { | ||||
|     $("#of-editversion-button").addClass("disabled"); | ||||
|     $("#of-editversion-button").prop("disabled", true); | ||||
|     $("#of-deleteversion-button").addClass("disabled"); | ||||
|     $("#of-deleteversion-button").prop("disabled", true); | ||||
| } | ||||
|  | ||||
| function getAppVersion() { | ||||
|     appVersion = remote.require("app").getVersion(); | ||||
|  | ||||
|     // simplify version, ex. 1.4.0 -> 1.4, | ||||
|     // Simplify version, ex. 1.4.0 -> 1.4, | ||||
|     // but only if a revision number isn't present | ||||
|     if (appVersion.endsWith(".0")) { | ||||
|         return appVersion.substr(0, appVersion.length - 2); | ||||
| @@ -43,10 +84,38 @@ function setAppVersionText() { | ||||
|     $("#of-versionnumber").text("v" + getAppVersion()); | ||||
| } | ||||
|  | ||||
| function validateServerSave(modalName) { | ||||
|     // works everytime a key is entered into the server save form | ||||
|     var descInput = document.getElementById(modalName + "server-descinput"); | ||||
|     var ipInput = document.getElementById(modalName + "server-ipinput"); | ||||
|     var button = document.getElementById(modalName + "server-savebutton"); | ||||
|     var valid = true; | ||||
|  | ||||
|     descInput.classList.remove("invalidinput"); | ||||
|     ipInput.classList.remove("invalidinput"); | ||||
|  | ||||
|     if ( | ||||
|         descInput.value.length < parseInt(descInput.getAttribute("minlength")) || | ||||
|         descInput.value.length > parseInt(descInput.getAttribute("maxlength")) | ||||
|     ) { | ||||
|         descInput.classList.add("invalidinput"); | ||||
|         valid = false; | ||||
|     } | ||||
|  | ||||
|     if (!(new RegExp(ipInput.getAttribute("pattern"))).test(ipInput.value)) { | ||||
|         ipInput.classList.add("invalidinput"); | ||||
|         valid = false; | ||||
|     } | ||||
|  | ||||
|     if (valid) { | ||||
|         button.removeAttribute("disabled"); | ||||
|     } else { | ||||
|         button.setAttribute("disabled", ""); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function addServer() { | ||||
|     var jsonToModify = JSON.parse( | ||||
|         remotefs.readFileSync(userDir + "\\servers.json") | ||||
|     ); | ||||
|     var jsonToModify = JSON.parse(remotefs.readFileSync(serversPath)); | ||||
|  | ||||
|     var server = {}; | ||||
|     server["uuid"] = uuidv4(); | ||||
| @@ -63,17 +132,12 @@ function addServer() { | ||||
|  | ||||
|     jsonToModify["servers"].push(server); | ||||
|  | ||||
|     remotefs.writeFileSync( | ||||
|         userDir + "\\servers.json", | ||||
|         JSON.stringify(jsonToModify, null, 4) | ||||
|     ); | ||||
|     remotefs.writeFileSync(serversPath, JSON.stringify(jsonToModify, null, 4)); | ||||
|     loadServerList(); | ||||
| } | ||||
|  | ||||
| function editServer() { | ||||
|     var jsonToModify = JSON.parse( | ||||
|         remotefs.readFileSync(userDir + "\\servers.json") | ||||
|     ); | ||||
|     var jsonToModify = JSON.parse(remotefs.readFileSync(serversPath)); | ||||
|     $.each(jsonToModify["servers"], function (key, value) { | ||||
|         if (value["uuid"] == getSelectedServer()) { | ||||
|             value["description"] = | ||||
| @@ -90,17 +154,12 @@ function editServer() { | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     remotefs.writeFileSync( | ||||
|         userDir + "\\servers.json", | ||||
|         JSON.stringify(jsonToModify, null, 4) | ||||
|     ); | ||||
|     remotefs.writeFileSync(serversPath, JSON.stringify(jsonToModify, null, 4)); | ||||
|     loadServerList(); | ||||
| } | ||||
|  | ||||
| function deleteServer() { | ||||
|     var jsonToModify = JSON.parse( | ||||
|         remotefs.readFileSync(userDir + "\\servers.json") | ||||
|     ); | ||||
|     var jsonToModify = JSON.parse(remotefs.readFileSync(serversPath)); | ||||
|     var result = jsonToModify["servers"].filter(function (obj) { | ||||
|         return obj.uuid === getSelectedServer(); | ||||
|     })[0]; | ||||
| @@ -109,26 +168,174 @@ function deleteServer() { | ||||
|  | ||||
|     jsonToModify["servers"].splice(resultindex, 1); | ||||
|  | ||||
|     remotefs.writeFileSync( | ||||
|         userDir + "\\servers.json", | ||||
|         JSON.stringify(jsonToModify, null, 4) | ||||
|     ); | ||||
|     remotefs.writeFileSync(serversPath, JSON.stringify(jsonToModify, null, 4)); | ||||
|     loadServerList(); | ||||
| } | ||||
|  | ||||
| function restoreDefaultServers() { | ||||
|     remotefs.copySync( | ||||
|         __dirname + "\\defaults\\servers.json", | ||||
|         userDir + "\\servers.json" | ||||
|         path.join(__dirname, "/defaults/servers.json"), | ||||
|         serversPath | ||||
|     ); | ||||
|     loadServerList(); | ||||
| } | ||||
|  | ||||
| function loadGameVersions() { | ||||
|     var versionJson = JSON.parse( | ||||
|         remotefs.readFileSync(userDir + "\\versions.json") | ||||
| function validateVersionSave(modalName) { | ||||
|     // works everytime a key is entered into the version save form | ||||
|     var nameInput = document.getElementById(modalName + "version-nameinput"); | ||||
|     var urlInput = document.getElementById(modalName + "version-urlinput"); | ||||
|     var button = document.getElementById(modalName + "version-savebutton"); | ||||
|     var valid = true; | ||||
|  | ||||
|     nameInput.classList.remove("invalidinput"); | ||||
|     urlInput.classList.remove("invalidinput"); | ||||
|  | ||||
|     var matchingVersions = versionArray.filter(function (obj) { | ||||
|         return obj.name === nameInput.value; | ||||
|     }); | ||||
|     var allowedMatches = (modalName === "edit") ? 1 : 0; | ||||
|  | ||||
|     if ( | ||||
|         matchingVersions.length > allowedMatches || | ||||
|         !(new RegExp(nameInput.getAttribute("pattern"))).test(nameInput.value) | ||||
|     ) { | ||||
|         nameInput.classList.add("invalidinput"); | ||||
|         valid = false; | ||||
|     } | ||||
|  | ||||
|     if (!(new RegExp(urlInput.getAttribute("pattern"))).test(urlInput.value)) { | ||||
|         urlInput.classList.add("invalidinput"); | ||||
|         valid = false; | ||||
|     } | ||||
|  | ||||
|     if (valid) { | ||||
|         button.removeAttribute("disabled"); | ||||
|     } else { | ||||
|         button.setAttribute("disabled", ""); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function addVersion() { | ||||
|     var jsonToModify = JSON.parse(remotefs.readFileSync(versionsPath)); | ||||
|  | ||||
|     var version = {}; | ||||
|     version["name"] = | ||||
|         $("#addversion-nameinput").val().length == 0 | ||||
|             ? "custom-build-" + uuidv4().substring(0, 8) | ||||
|             : $("#addversion-nameinput").val(); | ||||
|     version["url"] = | ||||
|         $("#addversion-urlinput").val().length == 0 | ||||
|             ? cdnString + "/" + version["name"] + "/" | ||||
|             : $("#addversion-urlinput").val(); | ||||
|  | ||||
|     var matchingVersions = jsonToModify["versions"].filter(function (obj) { | ||||
|         return obj.name === version["name"]; | ||||
|     }); | ||||
|  | ||||
|     if (matchingVersions.length > 0) return; | ||||
|  | ||||
|     jsonToModify["versions"].unshift(version); | ||||
|  | ||||
|     remotefs.writeFileSync(versionsPath, JSON.stringify(jsonToModify, null, 4)); | ||||
|     loadCacheList(); | ||||
|     handleCache("hash-check", version["name"]); | ||||
| } | ||||
|  | ||||
| function editVersion() { | ||||
|     var jsonToModify = JSON.parse(remotefs.readFileSync(versionsPath)); | ||||
|     var editedVersionString = null; | ||||
|  | ||||
|     $.each(jsonToModify["versions"], function (key, value) { | ||||
|         if (value["name"] == getSelectedVersion() && !defaultHashes.hasOwnProperty(value["name"])) { | ||||
|             value["name"] = | ||||
|                 $("#editversion-nameinput").val().length == 0 | ||||
|                     ? value["name"] | ||||
|                     : $("#editversion-nameinput").val(); | ||||
|             value["url"] = | ||||
|                 $("#editversion-urlinput").val().length == 0 | ||||
|                     ? value["url"] | ||||
|                     : $("#editversion-urlinput").val(); | ||||
|             editedVersionString = value["name"]; | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     if (!editedVersionString) return; | ||||
|  | ||||
|     remotefs.writeFileSync(versionsPath, JSON.stringify(jsonToModify, null, 4)); | ||||
|     loadCacheList(); | ||||
|     handleCache("hash-check", editedVersionString); | ||||
| } | ||||
|  | ||||
| function deleteVersion() { | ||||
|     var jsonToModify = JSON.parse(remotefs.readFileSync(versionsPath)); | ||||
|  | ||||
|     var result = jsonToModify["versions"].filter(function (obj) { | ||||
|         return obj.name === getSelectedVersion(); | ||||
|     })[0]; | ||||
|  | ||||
|     if (defaultHashes.hasOwnProperty(result.name)) return; | ||||
|  | ||||
|     var resultindex = jsonToModify["versions"].indexOf(result); | ||||
|  | ||||
|     jsonToModify["versions"].splice(resultindex, 1); | ||||
|  | ||||
|     remotefs.writeFileSync(versionsPath, JSON.stringify(jsonToModify, null, 4)); | ||||
|     loadCacheList(); | ||||
|     delete cacheSizes[result.name]; | ||||
| } | ||||
|  | ||||
| function restoreDefaultVersions() { | ||||
|     remotefs.copySync( | ||||
|         path.join(__dirname, "/defaults/versions.json"), | ||||
|         versionsPath | ||||
|     ); | ||||
|     loadCacheList(); | ||||
|     handleCache("hash-check"); | ||||
| } | ||||
|  | ||||
| function editConfig() { | ||||
|     var jsonToModify = JSON.parse(remotefs.readFileSync(configPath)); | ||||
|  | ||||
|     jsonToModify["autoupdate-check"] = $("#editconfig-autoupdate").prop("checked"); | ||||
|     jsonToModify["cache-swapping"] = $("#editconfig-cacheswapping").prop("checked"); | ||||
|     jsonToModify["enable-offline-cache"] = $("#editconfig-enableofflinecache").prop("checked"); | ||||
|     jsonToModify["verify-offline-cache"] = $("#editconfig-verifyofflinecache").prop("checked"); | ||||
|  | ||||
|     var dirInput = $("#editconfig-offlinecachelocation:text").val(); | ||||
|     var shouldChangeRoot = ( | ||||
|         remotefs.existsSync(dirInput) && | ||||
|         remotefs.statSync(dirInput).isDirectory() | ||||
|     ); | ||||
|  | ||||
|     jsonToModify["offline-cache-location"] = shouldChangeRoot ? dirInput : offlineRoot; | ||||
|  | ||||
|     remotefs.writeFileSync(configPath, JSON.stringify(jsonToModify, null, 4)); | ||||
|  | ||||
|     loadConfig(); | ||||
|     // check all offline caches if the offline root changes | ||||
|     if (shouldChangeRoot) handleCache("hash-check", null, "offline"); | ||||
| } | ||||
|  | ||||
| function validateCacheLocation() { | ||||
|     var input = document.getElementById("editconfig-offlinecachelocation"); | ||||
|     var button = document.getElementById("editconfig-savebutton"); | ||||
|  | ||||
|     input.classList.remove("invalidinput"); | ||||
|     button.removeAttribute("disabled"); | ||||
|  | ||||
|     if (!remotefs.existsSync(input.value) || !remotefs.statSync(input.value).isDirectory()) { | ||||
|         input.classList.add("invalidinput"); | ||||
|         button.setAttribute("disabled", ""); | ||||
|     } | ||||
| } | ||||
|  | ||||
| function loadGameVersions() { | ||||
|     var versionJson = remotefs.readJsonSync(versionsPath); | ||||
|     versionArray = versionJson["versions"]; | ||||
|  | ||||
|     $("#addserver-versionselect").empty(); | ||||
|     $("#editserver-versionselect").empty(); | ||||
|  | ||||
|     $.each(versionArray, function (key, value) { | ||||
|         $(new Option(value.name, "val")).appendTo("#addserver-versionselect"); | ||||
|         $(new Option(value.name, "val")).appendTo("#editserver-versionselect"); | ||||
| @@ -136,18 +343,27 @@ function loadGameVersions() { | ||||
| } | ||||
|  | ||||
| function loadConfig() { | ||||
|     // load config object globally | ||||
|     config = JSON.parse(remotefs.readFileSync(userDir + "\\config.json")); | ||||
|     // Load config object globally | ||||
|     config = remotefs.readJsonSync(configPath); | ||||
|  | ||||
|     $("#editconfig-autoupdate").prop("checked", config["autoupdate-check"]); | ||||
|     $("#editconfig-cacheswapping").prop("checked", config["cache-swapping"]); | ||||
|     $("#editconfig-enableofflinecache").prop("checked", config["enable-offline-cache"]); | ||||
|     $("#editconfig-verifyofflinecache").prop("checked", config["verify-offline-cache"]); | ||||
|  | ||||
|     // alter offline root globally | ||||
|     offlineRoot = config["offline-cache-location"] || offlineRootDefault; | ||||
|     $("#editconfig-offlinecachelocation:text").val(offlineRoot); | ||||
|  | ||||
|     validateCacheLocation(); | ||||
| } | ||||
|  | ||||
| function loadServerList() { | ||||
|     var serverJson = JSON.parse( | ||||
|         remotefs.readFileSync(userDir + "\\servers.json") | ||||
|     ); | ||||
|     var serverJson = remotefs.readJsonSync(serversPath); | ||||
|     serverArray = serverJson["servers"]; | ||||
|  | ||||
|     deselectServer(); // Remove selection and disable buttons until another server is selected | ||||
|     $(".server-listing-entry").remove(); // Clear out old stuff, if any | ||||
|     disableServerListButtons(); // Disable buttons until another server is selected | ||||
|  | ||||
|     if (serverArray.length > 0) { | ||||
|         // Servers were found in the JSON | ||||
| @@ -173,63 +389,372 @@ function loadServerList() { | ||||
|     } | ||||
| } | ||||
|  | ||||
| function performCacheSwap(newVersion) { | ||||
|     var cacheRoot = userDir + "\\..\\..\\LocalLow\\Unity\\Web Player\\Cache"; | ||||
|     var currentCache = cacheRoot + "\\Fusionfall"; | ||||
|     var newCache = cacheRoot + "\\" + newVersion; | ||||
|     var record = userDir + "\\.lastver"; | ||||
| function loadCacheList() { | ||||
|     // we might want to use a new version right away, so reload them | ||||
|     loadGameVersions(); | ||||
|  | ||||
|     // if cache renaming would result in a no-op (ex. launching the same version | ||||
|     // two times), then skip it. this avoids permissions errors with multiple clients | ||||
|     // load default hashes.json for reference while running the cache handler | ||||
|     if (!defaultHashes) { | ||||
|         defaultHashes = remotefs.readJsonSync(path.join( | ||||
|             __dirname, | ||||
|             "/defaults/hashes.json" | ||||
|         )); | ||||
|     } | ||||
|  | ||||
|     deselectVersion(); // Remove selection and disable buttons until another server is selected | ||||
|     $(".cache-listing-entry").remove(); // Clear out old stuff, if any | ||||
|  | ||||
|     $.each(versionArray, function (key, value) { | ||||
|         var row = document.createElement("tr"); | ||||
|         row.className = "cache-listing-entry" | ||||
|         row.setAttribute("id", value.name); | ||||
|  | ||||
|         var cellVersion = document.createElement("td"); | ||||
|         cellVersion.textContent = value.name; | ||||
|         cellVersion.className = "text-monospace"; | ||||
|  | ||||
|         var cellPlayableCache = getCacheInfoCell(value.name, "playable"); | ||||
|         var cellOfflineCache = getCacheInfoCell(value.name, "offline"); | ||||
|  | ||||
|         row.appendChild(cellVersion); | ||||
|         row.appendChild(cellPlayableCache); | ||||
|         row.appendChild(cellOfflineCache); | ||||
|  | ||||
|         $("#cache-tablebody").append(row); | ||||
|     }); | ||||
|  | ||||
|     // simulate a cache handler run so that the buttons update properly | ||||
|     storageLoadingStart(); | ||||
|     storageLoadingUpdate(cacheSizes); | ||||
|     storageLoadingComplete(cacheSizes); | ||||
| } | ||||
|  | ||||
| function getCacheElemID(versionString, cacheMode, elementName) { | ||||
|     return [versionString, cacheMode, "cache", elementName].filter(function (value) { | ||||
|         return typeof value !== "undefined"; | ||||
|     }).join("-"); | ||||
| } | ||||
|  | ||||
| function getCacheButtonID(versionString, cacheMode, buttonMode) { | ||||
|     return [getCacheElemID(versionString, cacheMode), buttonMode, "button"].join("-"); | ||||
| } | ||||
|  | ||||
| function getCacheLabelText(sizes) { | ||||
|     if (!sizes || sizes.total === 0) | ||||
|         return "?.?? GB / ?.?? GB"; | ||||
|  | ||||
|     var gb = 1 << 30; | ||||
|     var labelText = (sizes.intact / gb).toFixed(2) + " / " + (sizes.total / gb).toFixed(2) + " GB"; | ||||
|  | ||||
|     if (sizes.altered > 0) { | ||||
|         labelText += "<br/>(" + (sizes.altered / gb).toFixed(2) + " GB Altered)"; | ||||
|     } | ||||
|  | ||||
|     return labelText; | ||||
| } | ||||
|  | ||||
| function getCacheInfoCell(versionString, cacheMode) { | ||||
|     var divID = getCacheElemID(versionString, cacheMode, "div"); | ||||
|     var labelID = getCacheElemID(versionString, cacheMode, "label"); | ||||
|  | ||||
|     var settings = { | ||||
|         download: { | ||||
|             icon: "fas fa-download", | ||||
|             class: "btn btn-success mr-1", | ||||
|             tooltip: "Download Cache" | ||||
|         }, | ||||
|         fix: { | ||||
|             icon: "fas fa-hammer", | ||||
|             class: "btn btn-warning mr-1", | ||||
|             tooltip: "Fix Altered Files in Cache" | ||||
|         }, | ||||
|         delete: { | ||||
|             icon: "fas fa-trash-alt", | ||||
|             class: "btn btn-danger mr-1", | ||||
|             tooltip: "Delete Cache" | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     var cellCache = document.createElement("td"); | ||||
|     var divCacheAll = document.createElement("div"); | ||||
|  | ||||
|     var labelCache = document.createElement("label"); | ||||
|     labelCache.setAttribute("id", labelID); | ||||
|     labelCache.setAttribute("for", divID); | ||||
|     // pull existing info from cacheSizes when available | ||||
|     labelCache.innerHTML = getCacheLabelText( | ||||
|         (cacheSizes && cacheSizes[versionString]) ? | ||||
|         cacheSizes[versionString][cacheMode] : | ||||
|         null | ||||
|     ); | ||||
|  | ||||
|     var divCacheButtons = document.createElement("div"); | ||||
|     divCacheButtons.setAttribute("id", labelID); | ||||
|  | ||||
|     $.each(settings, function (buttonMode, config) { | ||||
|         // only delete allowed for playable game caches | ||||
|         if (cacheMode === "playable" && buttonMode !== "delete") { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         var buttonID = getCacheButtonID(versionString, cacheMode, buttonMode); | ||||
|  | ||||
|         var iconItalic = document.createElement("i"); | ||||
|         iconItalic.setAttribute("class", config.icon); | ||||
|  | ||||
|         var buttonCache = document.createElement("button"); | ||||
|         buttonCache.setAttribute("id", buttonID); | ||||
|         buttonCache.setAttribute("class", config.class); | ||||
|         buttonCache.setAttribute("title", config.tooltip); | ||||
|         buttonCache.setAttribute("type", "button"); | ||||
|         // handler setup | ||||
|         buttonCache.setAttribute("onclick", "handleCache(\"" + buttonMode + "\", \"" + versionString + "\", \"" + cacheMode + "\");"); | ||||
|         buttonCache.appendChild(iconItalic); | ||||
|  | ||||
|         divCacheButtons.appendChild(buttonCache); | ||||
|     }); | ||||
|  | ||||
|     divCacheAll.appendChild(labelCache); | ||||
|     divCacheAll.appendChild(divCacheButtons); | ||||
|     cellCache.appendChild(divCacheAll); | ||||
|  | ||||
|     return cellCache; | ||||
| } | ||||
|  | ||||
| function storageLoadingStart(vString, cMode) { | ||||
|     // determine which cache versions and modes to visually update | ||||
|     var versionStrings = []; | ||||
|     $.each(versionArray, function (key, value) { | ||||
|         if (vString) { | ||||
|             if (vString === value.name) | ||||
|                 versionStrings.push(value.name); | ||||
|         } else { | ||||
|             versionStrings.push(value.name); | ||||
|         } | ||||
|     }); | ||||
|     var cacheModes = (cMode) ? [cMode] : ["offline", "playable"]; | ||||
|  | ||||
|     // deselect and disable the add version button until they are re-enabled | ||||
|     deselectVersion(); | ||||
|     disableVersionAddButton(); | ||||
|  | ||||
|     // turn buttons into spinners | ||||
|     $.each(versionStrings, function (vKey, versionString) { | ||||
|         $.each(cacheModes, function (cKey, cacheMode) { | ||||
|             var buttonDelete = document.getElementById(getCacheButtonID(versionString, cacheMode, "delete")); | ||||
|             var buttonDownload = document.getElementById(getCacheButtonID(versionString, cacheMode, "download")); | ||||
|             var buttonFix = document.getElementById(getCacheButtonID(versionString, cacheMode, "fix")); | ||||
|  | ||||
|             if (!buttonDelete) return; | ||||
|  | ||||
|             buttonDelete.setAttribute("disabled", ""); | ||||
|             buttonDelete.children[0].setAttribute("class", "fas fa-spinner fa-spin fa-fw"); | ||||
|  | ||||
|             if (cacheMode === "offline") { | ||||
|                 buttonDownload.setAttribute("disabled", ""); | ||||
|                 buttonDownload.children[0].setAttribute("class", "fas fa-spinner fa-spin fa-fw"); | ||||
|  | ||||
|                 buttonFix.setAttribute("disabled", ""); | ||||
|                 buttonFix.children[0].setAttribute("class", "fas fa-spinner fa-spin fa-fw"); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function storageLoadingUpdate(allSizes) { | ||||
|     // update cacheSizes and display results | ||||
|     $.each(allSizes, function (versionString, vSizes) { | ||||
|         $.each(vSizes, function (cacheMode, sizes) { | ||||
|             var label = document.getElementById(getCacheElemID(versionString, cacheMode, "label")); | ||||
|  | ||||
|             cacheSizes = cacheSizes || {}; | ||||
|             cacheSizes[versionString] = cacheSizes[versionString] || {}; | ||||
|             cacheSizes[versionString][cacheMode] = sizes || {}; | ||||
|  | ||||
|             if (!label) return; | ||||
|  | ||||
|             label.innerHTML = getCacheLabelText(sizes); | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function storageLoadingComplete(allSizes) { | ||||
|     // re-enable buttons according to the sizes that were read | ||||
|     $.each(allSizes, function (versionString, vSizes) { | ||||
|         $.each(vSizes, function (cacheMode, sizes) { | ||||
|             var buttonDelete = document.getElementById(getCacheButtonID(versionString, cacheMode, "delete")); | ||||
|             var buttonDownload = document.getElementById(getCacheButtonID(versionString, cacheMode, "download")); | ||||
|             var buttonFix = document.getElementById(getCacheButtonID(versionString, cacheMode, "fix")); | ||||
|  | ||||
|             if (!buttonDelete) return; | ||||
|  | ||||
|             buttonDelete.children[0].setAttribute("class", "fas fa-trash-alt"); | ||||
|  | ||||
|             if (cacheMode === "offline") { | ||||
|                 buttonDownload.children[0].setAttribute("class", "fas fa-download"); | ||||
|                 buttonFix.children[0].setAttribute("class", "fas fa-hammer"); | ||||
|             } | ||||
|  | ||||
|             if (sizes.intact > 0 || sizes.altered > 0) { | ||||
|                 buttonDelete.removeAttribute("disabled"); | ||||
|  | ||||
|                 if (cacheMode === "offline") { | ||||
|                     buttonDownload.setAttribute("disabled", ""); | ||||
|  | ||||
|                     if (sizes.altered > 0 || sizes.intact < sizes.total) { | ||||
|                         buttonFix.removeAttribute("disabled"); | ||||
|                     } | ||||
|                 } | ||||
|             } else { | ||||
|                 buttonDelete.setAttribute("disabled", ""); | ||||
|  | ||||
|                 if (cacheMode === "offline") { | ||||
|                     buttonDownload.removeAttribute("disabled"); | ||||
|                     buttonFix.setAttribute("disabled", ""); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     // finally, re-enable the version add button | ||||
|     enableVersionAddButton(); | ||||
| } | ||||
|  | ||||
| function handleCache(operation, versionString, cacheMode, callback) { | ||||
|     // see if any versions match (could be undefined or null) | ||||
|     var versions = versionArray.filter(function (obj) { | ||||
|         return obj.name === versionString; | ||||
|     }); | ||||
|     // pull version url from the found object, if none found, use the default cdn link | ||||
|     var cdnRoot = (versions.length === 0) ? cdnString : versions[0].url; | ||||
|  | ||||
|     var lastSizes = { intact: 0, altered: 0, total: 0 }; | ||||
|     var buf = ""; | ||||
|  | ||||
|     // start loading on the given version and mode (could be undefined or null, which means 'all') | ||||
|     storageLoadingStart(versionString, cacheMode); | ||||
|  | ||||
|     // create the server and socket listener | ||||
|     var server = net.createServer(function (sock) { | ||||
|         sock.setEncoding("utf8"); | ||||
|  | ||||
|         sock.on("data", function (data) { | ||||
|             // read data until the next \n, and keep reading | ||||
|             // sometimes the updates are buffered, so there might be multiple objects | ||||
|             // per update, and partial objects as well | ||||
|             // buffer parsing allows us to handle these cases | ||||
|             buf += data; | ||||
|  | ||||
|             var end = buf.indexOf("\n"); | ||||
|  | ||||
|             while (end > 0) { | ||||
|                 var sub = buf.substring(0, end); | ||||
|                 buf = buf.substring(end + 1); | ||||
|  | ||||
|                 // run a storage update here | ||||
|                 lastSizes = JSON.parse(sub); | ||||
|                 storageLoadingUpdate(lastSizes); | ||||
|  | ||||
|                 end = buf.indexOf("\n"); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     // start listening on a randomly acquired port, and spawn cache handler when ready | ||||
|     server.listen(0, "localhost", function () { | ||||
|         spawn( | ||||
|             path.join(__dirname, "lib", "cache_handler.exe"), | ||||
|             [ | ||||
|                 "--operation", operation, | ||||
|                 // roots below contain version-agnostic main directories for caches | ||||
|                 "--playable-root", cacheRoot, | ||||
|                 "--offline-root", offlineRoot, | ||||
|                 "--user-dir", userData, | ||||
|                 // CDN root contains version-specific directory, unless cacheMode is "all" | ||||
|                 "--cdn-root", cdnRoot, | ||||
|                 "--cache-mode", cacheMode || "all", | ||||
|                 "--cache-version", versionString || "all", | ||||
|                 // learn port from the server object and tell the script where to connect | ||||
|                 "--port", server.address().port, | ||||
|                 // tell the script which versions and caches are official | ||||
|                 "--official-caches" | ||||
|             ].concat(Object.keys(defaultHashes)), | ||||
|             { | ||||
|                 stdio: "inherit" | ||||
|             } | ||||
|         ).on("exit", function (code, signal) { | ||||
|             if (code !== 0 || signal) { | ||||
|                 dialog.showErrorBox( | ||||
|                     "Sorry!", | ||||
|                     "Process \"" + operation + "\" failed with code " + code + " and signal " + signal + "." | ||||
|                 ); | ||||
|             } | ||||
|  | ||||
|             // when the script exits, close the server | ||||
|             server.close(); | ||||
|             // set button state accordingly | ||||
|             storageLoadingComplete(lastSizes); | ||||
|             // then run the given callback (if any) | ||||
|             if (callback) callback(lastSizes); | ||||
|         }); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| function performCacheSwap(newVersion) { | ||||
|     var currentCache = path.join(cacheRoot, "FusionFall"); | ||||
|     var newCache = path.join(cacheRoot, newVersion); | ||||
|     var record = path.join(userData, ".lastver"); | ||||
|  | ||||
|     // If cache renaming would result in a no-op (ex. launching the same version | ||||
|     // two times), then skip it. This avoids permissions errors with multiple clients | ||||
|     // (file/folder is already open in another process) | ||||
|     var skip = false; | ||||
|  | ||||
|     if (remotefs.existsSync(currentCache)) { | ||||
|         // cache already exists, find out what version it belongs to | ||||
|         // Cache already exists, find out what version it belongs to | ||||
|         if (remotefs.existsSync(record)) { | ||||
|             lastVersion = remotefs.readFileSync(record); | ||||
|             var lastVersion = remotefs.readFileSync(record, (encoding = "utf8")); | ||||
|             if (lastVersion != newVersion) { | ||||
|                 // Remove the directory we're trying to store the | ||||
|                 // existing cache to if it already exists for whatever | ||||
|                 // reason, as it would cause an EPERM error otherwise. | ||||
|                 // This is a no-op if the directory doesn't exist | ||||
|                 remotefs.removeSync(path.join(cacheRoot, lastVersion)); | ||||
|                 // Store old cache to named directory | ||||
|                 remotefs.renameSync( | ||||
|                     currentCache, | ||||
|                     cacheRoot + "\\" + lastVersion | ||||
|                     path.join(cacheRoot, lastVersion) | ||||
|                 ); | ||||
|             } else { | ||||
|                 console.log( | ||||
|                     "Cached version unchanged, renaming will be skipped" | ||||
|                 ); | ||||
|                 console.log("Cached version unchanged, skipping rename"); | ||||
|                 skip = true; | ||||
|             } | ||||
|             console.log("Current cache is " + lastVersion); | ||||
|         } else { | ||||
|             console.log( | ||||
|                 "Couldn't find last version record; cache may get overwritten" | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (remotefs.existsSync(newCache) || !skip) { | ||||
|         // rename saved cache to FusionFall | ||||
|     // Make note of what version we are launching for next launch | ||||
|     remotefs.writeFileSync(record, newVersion); | ||||
|  | ||||
|     if (remotefs.existsSync(newCache) && !skip) { | ||||
|         // Rename saved cache to FusionFall | ||||
|         remotefs.renameSync(newCache, currentCache); | ||||
|         console.log("Current cache swapped to " + newVersion); | ||||
|     } | ||||
|  | ||||
|     // make note of what version we are launching for next launch | ||||
|     remotefs.writeFileSync(record, newVersion); | ||||
| } | ||||
|  | ||||
| // For writing loginInfo.php, assetInfo.php, etc. | ||||
| function setGameInfo(serverUUID) { | ||||
|     var result = serverArray.filter(function (obj) { | ||||
| function prepGameInfo(serverUUID) { | ||||
|     var serverInfo = serverArray.filter(function (obj) { | ||||
|         return obj.uuid === serverUUID; | ||||
|     })[0]; | ||||
|     var gameVersion = versionArray.filter(function (obj) { | ||||
|         return obj.name === result.version; | ||||
|     var versionInfo = versionArray.filter(function (obj) { | ||||
|         return obj.name === serverInfo.version; | ||||
|     })[0]; | ||||
|  | ||||
|     // if cache swapping property exists AND is `true`, run cache swapping logic | ||||
|     // If cache swapping property exists AND is `true`, run cache swapping logic | ||||
|     if (config["cache-swapping"]) { | ||||
|         try { | ||||
|             performCacheSwap(gameVersion.name); | ||||
|             performCacheSwap(versionInfo.name); | ||||
|         } catch (ex) { | ||||
|             console.log( | ||||
|                 "Error when swapping cache, it may get overwritten:\n" + ex | ||||
| @@ -237,51 +762,83 @@ function setGameInfo(serverUUID) { | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     window.assetUrl = gameVersion.url; // game-client.js needs to access this | ||||
|     if (!config["enable-offline-cache"]) { | ||||
|         // if we always ignore the offline cache, just use the URL | ||||
|         setGameInfo(serverInfo, versionInfo.url); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     remotefs.writeFileSync(__dirname + "\\assetInfo.php", assetUrl); | ||||
|     if (result.hasOwnProperty("endpoint")) { | ||||
|         var httpEndpoint = result.endpoint.replace("https://", "http://"); | ||||
|     var offlinePath = path.join(offlineRoot, versionInfo.name); | ||||
|     var offlineURL = "file:///" + offlinePath.replace(/\\/g, "/") + "/"; | ||||
|  | ||||
|     if (config["verify-offline-cache"]) { | ||||
|         // if required, do a full hash check, and use the offline cache only if it is fully intact | ||||
|         handleCache("hash-check", versionInfo.name, "offline", function (sizes) { | ||||
|             var versionURL = (sizes.intact < sizes.total) ? versionInfo.url : offlineURL; | ||||
|             setGameInfo(serverInfo, versionURL); | ||||
|         }); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     // otherwise, if main.unity3d is present, use the offline cache | ||||
|     var mainPath = path.join(offlinePath, "main.unity3d"); | ||||
|     var versionURL = !remotefs.existsSync(mainPath) ? versionInfo.url : offlineURL; | ||||
|     setGameInfo(serverInfo, versionURL); | ||||
| } | ||||
|  | ||||
| // For writing loginInfo.php, assetInfo.php, etc. | ||||
| function setGameInfo(serverInfo, versionURL) { | ||||
|     // slash fix if people mess it up via text editors | ||||
|     var versionURLRoot = versionURL.endsWith("/") ? versionURL : versionURL + "/"; | ||||
|     window.assetUrl = versionURLRoot; // game-client.js needs to access this | ||||
|     console.log("Cache will expand from " + versionURLRoot); | ||||
|  | ||||
|     remotefs.writeFileSync(path.join(__dirname, "assetInfo.php"), assetUrl); | ||||
|     if (serverInfo.hasOwnProperty("endpoint")) { | ||||
|         var httpEndpoint = serverInfo.endpoint.replace("https://", "http://"); | ||||
|         remotefs.writeFileSync( | ||||
|             __dirname + "\\rankurl.txt", | ||||
|             path.join(__dirname, "rankurl.txt"), | ||||
|             httpEndpoint + "getranks" | ||||
|         ); | ||||
|         // Write these out too | ||||
|         remotefs.writeFileSync( | ||||
|             __dirname + "\\sponsor.php", | ||||
|             path.join(__dirname, "sponsor.php"), | ||||
|             httpEndpoint + "upsell/sponsor.png" | ||||
|         ); | ||||
|         remotefs.writeFileSync( | ||||
|             __dirname + "\\images.php", | ||||
|             path.join(__dirname, "images.php"), | ||||
|             httpEndpoint + "upsell/" | ||||
|         ); | ||||
|     } else { | ||||
|         // Remove/default the endpoint related stuff, this server won't be using it | ||||
|         if (remotefs.existsSync(__dirname + "\\rankurl.txt")) { | ||||
|             remotefs.unlinkSync(__dirname + "\\rankurl.txt"); | ||||
|         if (remotefs.existsSync(path.join(__dirname, "rankurl.txt"))) { | ||||
|             remotefs.unlinkSync(path.join(__dirname, "rankurl.txt")); | ||||
|             remotefs.writeFileSync( | ||||
|                 __dirname + "\\sponsor.php", | ||||
|                 path.join(__dirname, "sponsor.php"), | ||||
|                 "assets/img/welcome.png" | ||||
|             ); | ||||
|             remotefs.writeFileSync(__dirname + "\\images.php", "assets/img/"); | ||||
|             remotefs.writeFileSync( | ||||
|                 path.join(__dirname, "images.php"), | ||||
|                 "assets/img/" | ||||
|             ); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Server address parsing | ||||
|     var address; | ||||
|     var port; | ||||
|     var sepPos = result.ip.indexOf(":"); | ||||
|     var sepPos = serverInfo.ip.indexOf(":"); | ||||
|     if (sepPos > -1) { | ||||
|         address = result.ip.substr(0, sepPos); | ||||
|         port = result.ip.substr(sepPos + 1); | ||||
|         address = serverInfo.ip.substr(0, sepPos); | ||||
|         port = serverInfo.ip.substr(sepPos + 1); | ||||
|     } else { | ||||
|         address = result.ip; | ||||
|         address = serverInfo.ip; | ||||
|         port = 23000; // default | ||||
|     } | ||||
|  | ||||
|     // DNS resolution. there is no synchronous version for some stupid reason | ||||
|     if (!address.match(/^[0-9.]+$/)) | ||||
|         dns.lookup(address, family=4, function (err, resolvedAddress) { | ||||
|     if (!address.match(/^[0-9.]+$/)) { | ||||
|         dns.lookup(address, (family = 4), function (err, resolvedAddress) { | ||||
|             if (!err) { | ||||
|                 console.log("Resolved " + address + " to " + resolvedAddress); | ||||
|                 address = resolvedAddress; | ||||
| @@ -290,7 +847,7 @@ function setGameInfo(serverUUID) { | ||||
|             } | ||||
|             prepConnection(address, port); | ||||
|         }); | ||||
|     else { | ||||
|     } else { | ||||
|         console.log(address + " is an IP; skipping DNS lookup"); | ||||
|         prepConnection(address, port); | ||||
|     } | ||||
| @@ -299,7 +856,7 @@ function setGameInfo(serverUUID) { | ||||
| function prepConnection(address, port) { | ||||
|     var full = address + ":" + port; | ||||
|     console.log("Will connect to " + full); | ||||
|     remotefs.writeFileSync(__dirname + "\\loginInfo.php", full); | ||||
|     remotefs.writeFileSync(path.join(__dirname, "loginInfo.php"), full); | ||||
|     launchGame(); | ||||
| } | ||||
|  | ||||
| @@ -309,6 +866,11 @@ function getSelectedServer() { | ||||
|     return $("#server-tablebody > tr.bg-primary").prop("id"); | ||||
| } | ||||
|  | ||||
| // Returns the name of the version with the selected background color. | ||||
| function getSelectedVersion() { | ||||
|     return $("#cache-tablebody > tr.bg-primary").prop("id"); | ||||
| } | ||||
|  | ||||
| function connectToServer() { | ||||
|     // Get ID of the selected server, which corresponds to its UUID in the json | ||||
|     console.log("Connecting to server with UUID of " + getSelectedServer()); | ||||
| @@ -319,7 +881,7 @@ function connectToServer() { | ||||
|     $("#of-serverselector").fadeOut("slow", function () { | ||||
|         setTimeout(function () { | ||||
|             $("body,html").css("pointer-events", ""); | ||||
|             setGameInfo(getSelectedServer()); | ||||
|             prepGameInfo(getSelectedServer()); | ||||
|         }, 200); | ||||
|     }); | ||||
| } | ||||
| @@ -330,21 +892,47 @@ function deselectServer() { | ||||
|     $(".server-listing-entry").removeClass("bg-primary"); | ||||
| } | ||||
|  | ||||
| // If applicable, deselect currently selected version. | ||||
| function deselectVersion() { | ||||
|     disableVersionListButtons(); | ||||
|     $(".cache-listing-entry").removeClass("bg-primary"); | ||||
| } | ||||
|  | ||||
| // Select a server | ||||
| $("#server-table").on("click", ".server-listing-entry", function (event) { | ||||
|     enableServerListButtons(); | ||||
|     $(this).addClass("bg-primary").siblings().removeClass("bg-primary"); | ||||
| }); | ||||
|  | ||||
| // Select a version (if allowed) | ||||
| $("#cache-table").on("click", ".cache-listing-entry", function (event) { | ||||
|     // wait for the add button to be re-enabled first | ||||
|     if ($("#of-addversion-button").prop("disabled")) return; | ||||
|     // do not select default builds | ||||
|     if (defaultHashes.hasOwnProperty($(this).attr("id"))) return; | ||||
|  | ||||
|     enableVersionListButtons(); | ||||
|     $(this).addClass("bg-primary").siblings().removeClass("bg-primary"); | ||||
| }); | ||||
|  | ||||
| // QoL feature: if you double click on a server it will connect | ||||
| $("#server-table").on("dblclick", ".server-listing-entry", function (event) { | ||||
|     $(this).addClass("bg-primary").siblings().removeClass("bg-primary"); | ||||
|     connectToServer(); | ||||
| }); | ||||
|  | ||||
| $("#of-addservermodal").on("show.bs.modal", function (e) { | ||||
|     validateServerSave("add"); | ||||
| }); | ||||
|  | ||||
| $("#of-addversionmodal").on("show.bs.modal", function (e) { | ||||
|     validateVersionSave("add"); | ||||
| }); | ||||
|  | ||||
| $("#of-editservermodal").on("show.bs.modal", function (e) { | ||||
|     var jsonToModify = JSON.parse( | ||||
|         remotefs.readFileSync(userDir + "\\servers.json") | ||||
|     ); | ||||
|     // populate the edit modal with existing values | ||||
|     var jsonToModify = remotefs.readJsonSync(serversPath); | ||||
|  | ||||
|     $.each(jsonToModify["servers"], function (key, value) { | ||||
|         if (value["uuid"] == getSelectedServer()) { | ||||
|             $("#editserver-descinput")[0].value = value["description"]; | ||||
| @@ -359,11 +947,47 @@ $("#of-editservermodal").on("show.bs.modal", function (e) { | ||||
|             $("#editserver-versionselect")[0].selectedIndex = versionIndex; | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     validateServerSave("edit"); | ||||
| }); | ||||
|  | ||||
| $("#of-editversionmodal").on("show.bs.modal", function (e) { | ||||
|     // populate the edit modal with existing values | ||||
|     var jsonToModify = remotefs.readJsonSync(versionsPath); | ||||
|  | ||||
|     $.each(jsonToModify["versions"], function (key, value) { | ||||
|         if (value["name"] == getSelectedVersion()) { | ||||
|             $("#editversion-nameinput")[0].value = value["name"]; | ||||
|             $("#editversion-urlinput")[0].value = value["url"]; | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     validateVersionSave("edit"); | ||||
| }); | ||||
|  | ||||
| // Replace server name to delete | ||||
| $("#of-deleteservermodal").on("show.bs.modal", function (e) { | ||||
|     var result = serverArray.filter(function (obj) { | ||||
|         return obj.uuid === getSelectedServer(); | ||||
|     })[0]; | ||||
|     $("#deleteserver-servername").html(result.description); | ||||
| }); | ||||
|  | ||||
| // Replace version name to delete | ||||
| $("#of-deleteversionmodal").on("show.bs.modal", function (e) { | ||||
|     var result = versionArray.filter(function (obj) { | ||||
|         return obj.name === getSelectedVersion(); | ||||
|     })[0]; | ||||
|     $("#deleteversion-versionname").html(result.name); | ||||
| }); | ||||
|  | ||||
| // Run the global hash check once and only if the cache modal is ever shown | ||||
| $("#of-editcacheconfigmodal").on("show.bs.modal", function (e) { | ||||
|     if (!cacheSizes) handleCache("hash-check"); | ||||
| }); | ||||
|  | ||||
| // Keep all config values synced on modal show | ||||
| // Avoids cases where people forget that they changed the offline root but did not save | ||||
| $("#of-editconfigmodal").on("show.bs.modal", function (e) { | ||||
|     loadConfig(); | ||||
| }); | ||||
|   | ||||
| @@ -1,8 +1,32 @@ | ||||
| <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||||
| <asmv1:assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1" xmlns:asmv1="urn:schemas-microsoft-com:asm.v1" xmlns:asmv2="urn:schemas-microsoft-com:asm.v2" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"> | ||||
|   <assemblyIdentity type="win32" name="OpenFusion.Client" version="1.5.2.0" processorArchitecture="x86" /> | ||||
|   <dependency> | ||||
|     <dependentAssembly> | ||||
|       <assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"> | ||||
|       </assemblyIdentity> | ||||
|     </dependentAssembly> | ||||
|   </dependency> | ||||
|   <asmv3:trustInfo> | ||||
|     <security> | ||||
|       <requestedPrivileges> | ||||
|         <requestedExecutionLevel level="asInvoker" uiAccess="false"></requestedExecutionLevel> | ||||
|       </requestedPrivileges> | ||||
|     </security> | ||||
|   </asmv3:trustInfo> | ||||
|   <asmv3:application> | ||||
|     <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">  | ||||
|       <activeCodePage>UTF-8</activeCodePage>  | ||||
|       <dpiAware>true</dpiAware> | ||||
|     <asmv3:windowsSettings> | ||||
|       <activeCodePage xmlns="urn:schemas-microsoft-com:smi.2019.WindowsSettings">UTF-8</activeCodePage>  | ||||
|       <dpiAware xmlns="urn:schemas-microsoft-com:smi.2005.WindowsSettings">True/PM</dpiAware> | ||||
|     </asmv3:windowsSettings> | ||||
|   </asmv3:application> | ||||
| </assembly> | ||||
|   <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"> | ||||
|     <application> | ||||
|       <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"></supportedOS> | ||||
|       <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"></supportedOS> | ||||
|       <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"></supportedOS> | ||||
|       <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"></supportedOS> | ||||
|       <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"></supportedOS> | ||||
|     </application> | ||||
|   </compatibility> | ||||
| </asmv1:assembly> | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										1109
									
								
								cache_handler/cache_handler.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1109
									
								
								cache_handler/cache_handler.py
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										33
									
								
								cache_handler/cache_handler.spec
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								cache_handler/cache_handler.spec
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| # -*- mode: python ; coding: utf-8 -*- | ||||
|  | ||||
| block_cipher = None | ||||
|  | ||||
|  | ||||
| a = Analysis(['cache_handler.py'], | ||||
|              pathex=['Z:\\src'], | ||||
|              binaries=[], | ||||
|              datas=[], | ||||
|              hiddenimports=[], | ||||
|              hookspath=[], | ||||
|              runtime_hooks=[], | ||||
|              excludes=[], | ||||
|              win_no_prefer_redirects=False, | ||||
|              win_private_assemblies=False, | ||||
|              cipher=block_cipher, | ||||
|              noarchive=False) | ||||
| pyz = PYZ(a.pure, a.zipped_data, | ||||
|              cipher=block_cipher) | ||||
| exe = EXE(pyz, | ||||
|           a.scripts, | ||||
|           a.binaries, | ||||
|           a.zipfiles, | ||||
|           a.datas, | ||||
|           [], | ||||
|           name='cache_handler', | ||||
|           debug=False, | ||||
|           bootloader_ignore_signals=False, | ||||
|           strip=False, | ||||
|           upx=True, | ||||
|           upx_exclude=[], | ||||
|           runtime_tmpdir=None, | ||||
|           console=True ) | ||||
							
								
								
									
										4
									
								
								cache_handler/requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								cache_handler/requirements.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| aiofiles | ||||
| httpx | ||||
| beautifulsoup4 | ||||
| pyinstaller==3.5 | ||||
							
								
								
									
										4
									
								
								defaults/config.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								defaults/config.json
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,7 @@ | ||||
| { | ||||
|     "autoupdate-check": true, | ||||
|     "cache-swapping": true, | ||||
|     "last-version-initialized": "1.4" | ||||
|     "enable-offline-cache": false, | ||||
|     "verify-offline-cache": false, | ||||
|     "last-version-initialized": "1.6" | ||||
| } | ||||
|   | ||||
							
								
								
									
										35695
									
								
								defaults/hashes.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										35695
									
								
								defaults/hashes.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										449
									
								
								index.html
									
									
									
									
									
								
							
							
						
						
									
										449
									
								
								index.html
									
									
									
									
									
								
							| @@ -108,6 +108,30 @@ | ||||
|                         </button> | ||||
|                     </div> | ||||
|                     <div class="col-4 d-inline-flex justify-content-end"> | ||||
|                         <button | ||||
|                             class="btn btn-primary mr-1" | ||||
|                             data-toggle="modal" | ||||
|                             data-bs-tooltip="" | ||||
|                             data-placement="bottom" | ||||
|                             id="of-editconfig-button" | ||||
|                             type="button" | ||||
|                             title="Edit Configuration" | ||||
|                             data-target="#of-editconfigmodal" | ||||
|                         > | ||||
|                             <i class="fas fa-cog"></i> | ||||
|                         </button> | ||||
|                         <button | ||||
|                             class="btn btn-primary mr-1" | ||||
|                             data-toggle="modal" | ||||
|                             data-bs-tooltip="" | ||||
|                             data-placement="bottom" | ||||
|                             id="of-editcache-button" | ||||
|                             type="button" | ||||
|                             title="Edit Game Builds" | ||||
|                             data-target="#of-editcacheconfigmodal" | ||||
|                         > | ||||
|                             <i class="fas fa-database"></i> | ||||
|                         </button> | ||||
|                         <button | ||||
|                             class="btn btn-primary disabled" | ||||
|                             id="of-connect-button" | ||||
| @@ -149,7 +173,7 @@ | ||||
|                                 APP_VERSION_NUMBER | ||||
|                             </p> | ||||
|                             <p> | ||||
|                                 ©2020-2023 OpenFusion Contributors<br />OpenFusion | ||||
|                                 ©2020-2024 OpenFusion Contributors<br />OpenFusion | ||||
|                                 is licensed under MIT.<br /> | ||||
|                             </p> | ||||
|                             <a | ||||
| @@ -159,6 +183,13 @@ | ||||
|                                 data-target="#of-restoreserversmodal" | ||||
|                                 >Reset to Default Servers</a | ||||
|                             > | ||||
|                             <a | ||||
|                                 href="#of-restoreversionsmodal" | ||||
|                                 onclick="$('#of-aboutmodal').modal('toggle')" | ||||
|                                 data-toggle="modal" | ||||
|                                 data-target="#of-restoreversionsmodal" | ||||
|                                 >Reset to Default Game Builds</a | ||||
|                             > | ||||
|                         </div> | ||||
|                         <div class="modal-footer"> | ||||
|                             <div class="row flex-fill"> | ||||
| @@ -169,7 +200,7 @@ | ||||
|                                         data-bs-tooltip="" | ||||
|                                         type="button" | ||||
|                                         title="Github Page" | ||||
|                                         onclick="window.open('https://github.com/OpenFusionProject/OpenFusion','_blank');" | ||||
|                                         onclick="window.open('https://github.com/OpenFusionProject/OpenFusion','_blank');" | ||||
|                                     > | ||||
|                                         <i | ||||
|                                             class="fab fa-github" | ||||
| @@ -181,7 +212,7 @@ | ||||
|                                         data-bs-tooltip="" | ||||
|                                         type="button" | ||||
|                                         title="Discord Chat" | ||||
|                                         onclick="window.open('https://discord.gg/DYavckB','_blank');" | ||||
|                                         onclick="window.open('https://discord.gg/DYavckB','_blank');" | ||||
|                                     > | ||||
|                                         <i | ||||
|                                             class="fab fa-discord" | ||||
| @@ -238,6 +269,7 @@ | ||||
|                                     required="" | ||||
|                                     minlength="1" | ||||
|                                     maxlength="70" | ||||
|                                     oninput="validateServerSave('add')" | ||||
|                                 /><label for="addserver-ipinput" | ||||
|                                     >Server IP</label | ||||
|                                 ><input | ||||
| @@ -245,8 +277,10 @@ | ||||
|                                     type="text" | ||||
|                                     id="addserver-ipinput" | ||||
|                                     placeholder="127.0.0.1:23000" | ||||
|                                     value="127.0.0.1:23000" | ||||
|                                     required="" | ||||
|                                     pattern="^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]):[0-9]+$" | ||||
|                                     pattern="^([-a-zA-Z0-9]+\.)+[-a-zA-Z0-9]+:[0-9]+$" | ||||
|                                     oninput="validateServerSave('add')" | ||||
|                                 /><label for="addserver-versionselect" | ||||
|                                     >Game Version: </label | ||||
|                                 ><select | ||||
| @@ -254,6 +288,7 @@ | ||||
|                                     id="addserver-versionselect" | ||||
|                                     required="" | ||||
|                                     style="margin-left: -5px" | ||||
|                                     oninput="validateServerSave('add')" | ||||
|                                 ></select> | ||||
|                             </form> | ||||
|                         </div> | ||||
| @@ -310,7 +345,8 @@ | ||||
|                                     required="" | ||||
|                                     minlength="1" | ||||
|                                     maxlength="70" | ||||
|                                 /><label for="addserver-ipinput" | ||||
|                                     oninput="validateServerSave('edit')" | ||||
|                                 /><label for="editserver-ipinput" | ||||
|                                     >Server IP</label | ||||
|                                 ><input | ||||
|                                     class="form-control form-row w-75" | ||||
| @@ -318,7 +354,8 @@ | ||||
|                                     id="editserver-ipinput" | ||||
|                                     placeholder="127.0.0.1:23000" | ||||
|                                     required="" | ||||
|                                     pattern="^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]):[0-9]+$" | ||||
|                                     pattern="^([-a-zA-Z0-9]+\.)+[-a-zA-Z0-9]+:[0-9]+$" | ||||
|                                     oninput="validateServerSave('edit')" | ||||
|                                 /><label for="editserver-versionselect" | ||||
|                                     >Game Version: </label | ||||
|                                 ><select | ||||
| @@ -326,6 +363,7 @@ | ||||
|                                     id="editserver-versionselect" | ||||
|                                     required="" | ||||
|                                     style="margin-left: -5px" | ||||
|                                     oninput="validateServerSave('edit')" | ||||
|                                 ></select> | ||||
|                             </form> | ||||
|                         </div> | ||||
| @@ -339,7 +377,7 @@ | ||||
|                                 Cancel</button | ||||
|                             ><button | ||||
|                                 class="btn btn-primary border rounded border-primary btn-success border-success" | ||||
|                                 id="addserver-savebutton" | ||||
|                                 id="editserver-savebutton" | ||||
|                                 type="submit" | ||||
|                                 data-dismiss="modal" | ||||
|                                 form="editserver-form" | ||||
| @@ -432,7 +470,7 @@ | ||||
|                                 Cancel</button | ||||
|                             ><button | ||||
|                                 class="btn btn-primary border rounded border-primary btn-danger border-danger" | ||||
|                                 id="deleteserver-button" | ||||
|                                 id="restoreservers-button" | ||||
|                                 type="button" | ||||
|                                 data-dismiss="modal" | ||||
|                                 onclick="restoreDefaultServers();" | ||||
| @@ -443,6 +481,401 @@ | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div | ||||
|                 class="modal fade" | ||||
|                 role="dialog" | ||||
|                 tabindex="-1" | ||||
|                 id="of-editconfigmodal" | ||||
|             > | ||||
|                 <div class="modal-dialog modal-dialog-centered" role="document"> | ||||
|                     <div class="modal-content"> | ||||
|                         <div class="modal-header"> | ||||
|                             <h4 class="modal-title">Edit Configuration</h4> | ||||
|                             <button | ||||
|                                 type="button" | ||||
|                                 class="close" | ||||
|                                 data-dismiss="modal" | ||||
|                                 aria-label="Close" | ||||
|                             > | ||||
|                                 <span aria-hidden="true">×</span> | ||||
|                             </button> | ||||
|                         </div> | ||||
|                         <div class="modal-body"> | ||||
|                             <form id="editconfig-form" class="needs-validation"> | ||||
|                                 <label for="editconfig-autoupdate" | ||||
|                                     >Automatically update the client:</label | ||||
|                                 ><input | ||||
|                                     class="form-control form-row w-75" | ||||
|                                     type="checkbox" | ||||
|                                     id="editconfig-autoupdate" | ||||
|                                 /> | ||||
|                                 <label for="editconfig-cacheswapping" | ||||
|                                     >Swap game caches to avoid unnecessary downloads:</label | ||||
|                                 ><input | ||||
|                                     class="form-control form-row w-75" | ||||
|                                     type="checkbox" | ||||
|                                     id="editconfig-cacheswapping" | ||||
|                                 /> | ||||
|                                 <label for="editconfig-enableofflinecache" | ||||
|                                     >Use offline caches when they are available:</label | ||||
|                                 ><input | ||||
|                                     class="form-control form-row w-75" | ||||
|                                     type="checkbox" | ||||
|                                     id="editconfig-enableofflinecache" | ||||
|                                 /> | ||||
|                                 <label for="editconfig-verifyofflinecache" | ||||
|                                     >Verify offline caches every time they are loaded:</label | ||||
|                                 ><input | ||||
|                                     class="form-control form-row w-75" | ||||
|                                     type="checkbox" | ||||
|                                     id="editconfig-verifyofflinecache" | ||||
|                                 /> | ||||
|                                 <label for="editconfig-offlinecachelocation" | ||||
|                                     >Select Offline Cache Location:</label | ||||
|                                 ><input | ||||
|                                     class="form-control form-row w-75" | ||||
|                                     id="editconfig-offlinecachelocation" | ||||
|                                     type="text" | ||||
|                                     oninput="validateCacheLocation()" | ||||
|                                 /> | ||||
|                             </form> | ||||
|                         </div> | ||||
|                         <div class="modal-footer"> | ||||
|                             <button | ||||
|                                 class="btn btn-primary border rounded border-primary btn-danger border-danger" | ||||
|                                 id="editconfig-cancel" | ||||
|                                 type="button" | ||||
|                                 data-dismiss="modal" | ||||
|                             > | ||||
|                                 Cancel</button | ||||
|                             ><button | ||||
|                                 class="btn btn-primary border rounded border-primary btn-success border-success" | ||||
|                                 id="editconfig-savebutton" | ||||
|                                 type="submit" | ||||
|                                 data-dismiss="modal" | ||||
|                                 form="editconfig-form" | ||||
|                                 onclick="editConfig();" | ||||
|                             > | ||||
|                                 Save | ||||
|                             </button> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div | ||||
|                 class="modal fade" | ||||
|                 role="dialog" | ||||
|                 tabindex="-1" | ||||
|                 id="of-editcacheconfigmodal" | ||||
|             > | ||||
|                 <div class="modal-dialog modal-dialog-centered modal-lg" role="document"> | ||||
|                     <div class="modal-content"> | ||||
|                         <div class="modal-header"> | ||||
|                             <h4 class="modal-title">Edit Game Builds</h4> | ||||
|                             <button | ||||
|                                 type="button" | ||||
|                                 class="close" | ||||
|                                 data-dismiss="modal" | ||||
|                                 aria-label="Close" | ||||
|                             > | ||||
|                                 <span aria-hidden="true">×</span> | ||||
|                             </button> | ||||
|                         </div> | ||||
|                         <div class="modal-body"> | ||||
|                             <div | ||||
|                                 class="row row-cols-2 d-xl-flex justify-content-center justify-content-xl-start" | ||||
|                                 id="of-versionbuttons" | ||||
|                                 style="padding-bottom: 16px" | ||||
|                             > | ||||
|                                 <div | ||||
|                                     class="col-4 text-left d-inline-flex justify-content-xl-start" | ||||
|                                     id="cache-buttons" | ||||
|                                 > | ||||
|                                     <button | ||||
|                                         class="btn btn-success mr-1" | ||||
|                                         data-toggle="modal" | ||||
|                                         data-bs-tooltip="" | ||||
|                                         data-placement="bottom" | ||||
|                                         id="of-addversion-button" | ||||
|                                         type="button" | ||||
|                                         title="Add Version" | ||||
|                                         data-target="#of-addversionmodal" | ||||
|                                         onclick="deselectVersion()" | ||||
|                                     > | ||||
|                                         <i class="fas fa-plus"></i> | ||||
|                                     </button> | ||||
|                                     <button | ||||
|                                         class="btn btn-primary mr-1 disabled" | ||||
|                                         data-toggle="modal" | ||||
|                                         data-bs-tooltip="" | ||||
|                                         data-placement="bottom" | ||||
|                                         id="of-editversion-button" | ||||
|                                         type="button" | ||||
|                                         title="Edit Version" | ||||
|                                         data-target="#of-editversionmodal" | ||||
|                                         disabled="" | ||||
|                                     > | ||||
|                                         <i class="fas fa-edit"></i> | ||||
|                                     </button> | ||||
|                                     <button | ||||
|                                         class="btn btn-danger mr-1 disabled" | ||||
|                                         data-toggle="modal" | ||||
|                                         data-bs-tooltip="" | ||||
|                                         data-placement="bottom" | ||||
|                                         id="of-deleteversion-button" | ||||
|                                         type="button" | ||||
|                                         title="Delete Version" | ||||
|                                         data-target="#of-deleteversionmodal" | ||||
|                                         disabled="" | ||||
|                                     > | ||||
|                                         <i class="fas fa-trash-alt"></i> | ||||
|                                     </button> | ||||
|                                 </div> | ||||
|                             </div> | ||||
|                             <div | ||||
|                                 class="table-responsive text-center border rounded border-primary" | ||||
|                                 id="cache-table" | ||||
|                             > | ||||
|                                 <table class="table table-striped table-hover mb-0"> | ||||
|                                     <thead> | ||||
|                                         <tr> | ||||
|                                             <th>Game Version</th> | ||||
|                                             <th>Game Cache</th> | ||||
|                                             <th>Offline Cache</th> | ||||
|                                         </tr> | ||||
|                                     </thead> | ||||
|                                     <tbody id="cache-tablebody"> | ||||
|                                     </tbody> | ||||
|                                 </table> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div | ||||
|                 class="modal fade" | ||||
|                 role="dialog" | ||||
|                 tabindex="-1" | ||||
|                 id="of-addversionmodal" | ||||
|             > | ||||
|                 <div class="modal-dialog modal-dialog-centered" role="document"> | ||||
|                     <div class="modal-content"> | ||||
|                         <div class="modal-header"> | ||||
|                             <h4 class="modal-title">Add Server</h4> | ||||
|                             <button | ||||
|                                 type="button" | ||||
|                                 class="close" | ||||
|                                 data-dismiss="modal" | ||||
|                                 aria-label="Close" | ||||
|                             > | ||||
|                                 <span aria-hidden="true">×</span> | ||||
|                             </button> | ||||
|                         </div> | ||||
|                         <div class="modal-body"> | ||||
|                             <form id="addversion-form" class="needs-validation"> | ||||
|                                 <label for="addversion-nameinput" | ||||
|                                     >Version Name</label | ||||
|                                 ><input | ||||
|                                     class="form-control form-row w-75" | ||||
|                                     type="text" | ||||
|                                     id="addversion-nameinput" | ||||
|                                     placeholder="custom-build-000" | ||||
|                                     required="" | ||||
|                                     pattern="^[-a-zA-Z0-9_]{1,70}$" | ||||
|                                     oninput="validateVersionSave('add')" | ||||
|                                 /><label for="addversion-urlinput" | ||||
|                                     >Version URL</label | ||||
|                                 ><input | ||||
|                                     class="form-control form-row w-75" | ||||
|                                     type="text" | ||||
|                                     id="addversion-urlinput" | ||||
|                                     placeholder="http://cdn.dexlabs.systems/custom-build-000/" | ||||
|                                     required="" | ||||
|                                     pattern="^(https?|file):\/\/\/?([-a-zA-Z0-9@:%._\+~#= ]{1,256}\/){1,64}$" | ||||
|                                     oninput="validateVersionSave('add')" | ||||
|                                 /> | ||||
|                             </form> | ||||
|                         </div> | ||||
|                         <div class="modal-footer"> | ||||
|                             <button | ||||
|                                 class="btn btn-primary border rounded border-primary btn-danger border-danger" | ||||
|                                 id="addversion-cancel" | ||||
|                                 type="button" | ||||
|                                 data-dismiss="modal" | ||||
|                             > | ||||
|                                 Cancel</button | ||||
|                             ><button | ||||
|                                 class="btn btn-primary border rounded border-primary btn-success border-success" | ||||
|                                 id="addversion-savebutton" | ||||
|                                 type="submit" | ||||
|                                 data-dismiss="modal" | ||||
|                                 form="addversion-form" | ||||
|                                 onclick="addVersion();" | ||||
|                             > | ||||
|                                 Save | ||||
|                             </button> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div | ||||
|                 class="modal fade" | ||||
|                 role="dialog" | ||||
|                 tabindex="-1" | ||||
|                 id="of-editversionmodal" | ||||
|             > | ||||
|                 <div class="modal-dialog modal-dialog-centered" role="document"> | ||||
|                     <div class="modal-content"> | ||||
|                         <div class="modal-header"> | ||||
|                             <h4 class="modal-title">Edit Version</h4> | ||||
|                             <button | ||||
|                                 type="button" | ||||
|                                 class="close" | ||||
|                                 data-dismiss="modal" | ||||
|                                 aria-label="Close" | ||||
|                             > | ||||
|                                 <span aria-hidden="true">×</span> | ||||
|                             </button> | ||||
|                         </div> | ||||
|                         <div class="modal-body"> | ||||
|                             <form id="editversion-form" class="needs-validation"> | ||||
|                                 <label for="editversion-nameinput" | ||||
|                                     >Version Name</label | ||||
|                                 ><input | ||||
|                                     class="form-control form-row w-75" | ||||
|                                     type="text" | ||||
|                                     id="editversion-nameinput" | ||||
|                                     placeholder="custom-build-000" | ||||
|                                     required="" | ||||
|                                     pattern="^[-a-zA-Z0-9_]{1,70}$" | ||||
|                                     oninput="validateVersionSave('edit')" | ||||
|                                 /><label for="editversion-urlinput" | ||||
|                                     >Version URL</label | ||||
|                                 ><input | ||||
|                                     class="form-control form-row w-75" | ||||
|                                     type="text" | ||||
|                                     id="editversion-urlinput" | ||||
|                                     placeholder="http://cdn.dexlabs.systems/custom-build-000/" | ||||
|                                     required="" | ||||
|                                     pattern="^(https?|file):\/\/\/?([-a-zA-Z0-9@:%._\+~#= ]{1,256}\/){1,64}$" | ||||
|                                     oninput="validateVersionSave('edit')" | ||||
|                                 /> | ||||
|                             </form> | ||||
|                         </div> | ||||
|                         <div class="modal-footer"> | ||||
|                             <button | ||||
|                                 class="btn btn-primary border rounded border-primary btn-danger border-danger" | ||||
|                                 id="editversion-cancel" | ||||
|                                 type="button" | ||||
|                                 data-dismiss="modal" | ||||
|                             > | ||||
|                                 Cancel</button | ||||
|                             ><button | ||||
|                                 class="btn btn-primary border rounded border-primary btn-success border-success" | ||||
|                                 id="editversion-savebutton" | ||||
|                                 type="submit" | ||||
|                                 data-dismiss="modal" | ||||
|                                 form="editversion-form" | ||||
|                                 onclick="editVersion();" | ||||
|                             > | ||||
|                                 Save | ||||
|                             </button> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div | ||||
|                 class="modal fade" | ||||
|                 role="dialog" | ||||
|                 tabindex="-1" | ||||
|                 id="of-deleteversionmodal" | ||||
|             > | ||||
|                 <div class="modal-dialog modal-dialog-centered" role="document"> | ||||
|                     <div class="modal-content"> | ||||
|                         <div class="modal-header"> | ||||
|                             <h4 class="modal-title">Are you sure?</h4> | ||||
|                             <button | ||||
|                                 type="button" | ||||
|                                 class="close" | ||||
|                                 data-dismiss="modal" | ||||
|                                 aria-label="Close" | ||||
|                             > | ||||
|                                 <span aria-hidden="true">×</span> | ||||
|                             </button> | ||||
|                         </div> | ||||
|                         <div class="modal-body"> | ||||
|                             <p class="lead"> | ||||
|                                 Do you really want to delete<br />"<a | ||||
|                                     id="deleteversion-versionname" | ||||
|                                     >VERSION_NAME</a | ||||
|                                 >"?<br /><br />You could always re-add it later. | ||||
|                             </p> | ||||
|                         </div> | ||||
|                         <div class="modal-footer"> | ||||
|                             <button | ||||
|                                 class="btn btn-primary border rounded border-primary" | ||||
|                                 type="button" | ||||
|                                 data-dismiss="modal" | ||||
|                             > | ||||
|                                 Cancel</button | ||||
|                             ><button | ||||
|                                 class="btn btn-primary border rounded border-primary btn-danger border-danger" | ||||
|                                 id="deleteversion-button" | ||||
|                                 type="button" | ||||
|                                 data-dismiss="modal" | ||||
|                                 onclick="deleteVersion();" | ||||
|                             > | ||||
|                                 Yes, Delete | ||||
|                             </button> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div | ||||
|                 class="modal fade" | ||||
|                 role="dialog" | ||||
|                 tabindex="-1" | ||||
|                 id="of-restoreversionsmodal" | ||||
|             > | ||||
|                 <div class="modal-dialog modal-dialog-centered" role="document"> | ||||
|                     <div class="modal-content"> | ||||
|                         <div class="modal-header"> | ||||
|                             <h4 class="modal-title">Are you sure?</h4> | ||||
|                             <button | ||||
|                                 type="button" | ||||
|                                 class="close" | ||||
|                                 data-dismiss="modal" | ||||
|                                 aria-label="Close" | ||||
|                             > | ||||
|                                 <span aria-hidden="true">×</span> | ||||
|                             </button> | ||||
|                         </div> | ||||
|                         <div class="modal-body"> | ||||
|                             <p class="lead"> | ||||
|                                 Do you really want to restore the default | ||||
|                                 versions? | ||||
|                             </p> | ||||
|                         </div> | ||||
|                         <div class="modal-footer"> | ||||
|                             <button | ||||
|                                 class="btn btn-primary border rounded border-primary" | ||||
|                                 type="button" | ||||
|                                 data-dismiss="modal" | ||||
|                             > | ||||
|                                 Cancel</button | ||||
|                             ><button | ||||
|                                 class="btn btn-primary border rounded border-primary btn-danger border-danger" | ||||
|                                 id="restoreversions-button" | ||||
|                                 type="button" | ||||
|                                 data-dismiss="modal" | ||||
|                                 onclick="restoreDefaultVersions();" | ||||
|                             > | ||||
|                                 Yes, Restore | ||||
|                             </button> | ||||
|                         </div> | ||||
|                     </div> | ||||
|                 </div> | ||||
|             </div> | ||||
|             <div id="of-versionnumberdiv"> | ||||
|                 <a | ||||
|                     id="of-versionnumber" | ||||
|   | ||||
							
								
								
									
										47
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								index.js
									
									
									
									
									
								
							| @@ -8,10 +8,8 @@ var path = require("path"); | ||||
| var BrowserWindow = require("browser-window"); | ||||
| var mainWindow = null; | ||||
|  | ||||
| var userData = app.getPath("userData"); | ||||
| var unityHomeDir = path.join(__dirname, "../../WebPlayer"); | ||||
|  | ||||
| // if running in non-packaged / development mode, this dir will be slightly different | ||||
| // If running in non-packaged / development mode, this dir will be slightly different | ||||
| if (process.env.npm_node_execpath) { | ||||
|     unityHomeDir = path.join(app.getAppPath(), "/build/WebPlayer"); | ||||
| } | ||||
| @@ -20,31 +18,28 @@ process.env["UNITY_HOME_DIR"] = unityHomeDir; | ||||
| process.env["UNITY_DISABLE_PLUGIN_UPDATES"] = "yes"; | ||||
|  | ||||
| app.commandLine.appendSwitch("enable-npapi"); | ||||
| app.commandLine.appendSwitch("load-plugin", path.join(unityHomeDir, "/loader/npUnity3D32.dll")); | ||||
| app.commandLine.appendSwitch( | ||||
|     "load-plugin", | ||||
|     path.join(unityHomeDir, "/loader/npUnity3D32.dll") | ||||
| ); | ||||
| app.commandLine.appendSwitch("no-proxy-server"); | ||||
|  | ||||
| var configPath = path.join(userData, "/config.json"); | ||||
| var serversPath = path.join(userData, "/servers.json"); | ||||
| var versionsPath = path.join(userData, "/versions.json"); | ||||
| var userData = app.getPath("userData"); | ||||
| var configPath = path.join(userData, "config.json"); | ||||
| var serversPath = path.join(userData, "servers.json"); | ||||
| var versionsPath = path.join(userData, "versions.json"); | ||||
| var hashPath = path.join(userData, "hashes.json"); | ||||
|  | ||||
| function initialSetup(firstTime) { | ||||
|     // Display a small window to inform the user that the app is working | ||||
|     setupWindow = new BrowserWindow({ | ||||
|         width: 275, | ||||
|         height: 450, | ||||
|         resizable: false, | ||||
|         center: true, | ||||
|         frame: false, | ||||
|     }); | ||||
|     if (!firstTime) { | ||||
|         // migration from pre-1.4 | ||||
|         // Migration from pre-1.6 | ||||
|         // Back everything up, just in case | ||||
|         setupWindow.loadUrl("file://" + __dirname + "/initial-setup.html"); | ||||
|         fs.copySync(configPath, configPath + ".bak"); | ||||
|         fs.copySync(serversPath, serversPath + ".bak"); | ||||
|         fs.copySync(versionsPath, versionsPath + ".bak"); | ||||
|         if (fs.existsSync(configPath)) fs.copySync(configPath, configPath + ".bak"); | ||||
|         if (fs.existsSync(serversPath)) fs.copySync(serversPath, serversPath + ".bak"); | ||||
|         if (fs.existsSync(versionsPath)) fs.copySync(versionsPath, versionsPath + ".bak"); | ||||
|         if (fs.existsSync(hashPath)) fs.copySync(hashPath, hashPath + ".bak"); | ||||
|     } else { | ||||
|         // first-time setup | ||||
|         // First-time setup | ||||
|         // Copy default servers | ||||
|         fs.copySync( | ||||
|             path.join(__dirname, "/defaults/servers.json"), | ||||
| @@ -55,9 +50,9 @@ function initialSetup(firstTime) { | ||||
|     // Copy default versions and config | ||||
|     fs.copySync(path.join(__dirname, "/defaults/versions.json"), versionsPath); | ||||
|     fs.copySync(path.join(__dirname, "/defaults/config.json"), configPath); | ||||
|     fs.copySync(path.join(__dirname, "/defaults/hashes.json"), hashPath); | ||||
|  | ||||
|     console.log("JSON files copied."); | ||||
|     setupWindow.destroy(); | ||||
|     showMainWindow(); | ||||
| } | ||||
|  | ||||
| @@ -86,7 +81,7 @@ app.on("ready", function () { | ||||
|         height: 720, | ||||
|         show: false, | ||||
|         "web-preferences": { | ||||
|             plugins: true | ||||
|             plugins: true, | ||||
|         }, | ||||
|     }); | ||||
|     mainWindow.setMinimumSize(640, 480); | ||||
| @@ -98,8 +93,8 @@ app.on("ready", function () { | ||||
|             initialSetup(true); | ||||
|         } else { | ||||
|             var config = fs.readJsonSync(configPath); | ||||
|             if (!config["last-version-initialized"]) { | ||||
|                 console.log("Pre-1.4 config detected. Running migration."); | ||||
|             if (config["last-version-initialized"] !== "1.6") { | ||||
|                 console.log("Pre-1.6 config detected. Running migration."); | ||||
|                 initialSetup(false); | ||||
|             } else { | ||||
|                 showMainWindow(); | ||||
| @@ -136,6 +131,7 @@ function showMainWindow() { | ||||
|         mainWindow.webContents.executeJavaScript("loadConfig();"); | ||||
|         mainWindow.webContents.executeJavaScript("loadGameVersions();"); | ||||
|         mainWindow.webContents.executeJavaScript("loadServerList();"); | ||||
|         mainWindow.webContents.executeJavaScript("loadCacheList();"); | ||||
|     }); | ||||
|  | ||||
|     mainWindow.webContents.on("plugin-crashed", function () { | ||||
| @@ -149,7 +145,6 @@ function showMainWindow() { | ||||
|  | ||||
|     mainWindow.webContents.on("will-navigate", function (event, url) { | ||||
|         event.preventDefault(); | ||||
|         // TODO: showMessageBox rather than showErrorBox? | ||||
|         switch (url) { | ||||
|             case "https://audience.fusionfall.com/ff/regWizard.do?_flowId=fusionfall-registration-flow": | ||||
|                 var errorMessage = | ||||
|   | ||||
| @@ -1,40 +0,0 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|     <head> | ||||
|         <title>OpenFusion: Initial Setup</title> | ||||
|     </head> | ||||
|     <body | ||||
|         style=" | ||||
|             overflow: hidden; | ||||
|             background-color: #000; | ||||
|             user-select: none; | ||||
|             -webkit-user-select: none; | ||||
|         " | ||||
|     > | ||||
|         <center> | ||||
|             <div> | ||||
|                 <img src="assets/img/of-3.png" width="256" /> | ||||
|                 <div> | ||||
|                     <img src="assets/img/spinner.gif" width="50px" /> | ||||
|                 </div> | ||||
|                 <div style="margin-top: 15px"> | ||||
|                     <p | ||||
|                         style=" | ||||
|                             text-shadow: 1px 1px 8px #4349c4; | ||||
|                             color: #4a76b7; | ||||
|                             font-size: 18px; | ||||
|                             font-family: -apple-system, BlinkMacSystemFont, | ||||
|                                 'Segoe UI', Roboto, 'Helvetica Neue', Arial, | ||||
|                                 'Noto Sans', sans-serif, 'Apple Color Emoji', | ||||
|                                 'Segoe UI Emoji', 'Segoe UI Symbol', | ||||
|                                 'Noto Color Emoji'; | ||||
|                         " | ||||
|                     > | ||||
|                         OpenFusion is setting up...<br />Please wait - this | ||||
|                         should take <br />less than a minute. | ||||
|                     </p> | ||||
|                 </div> | ||||
|             </div> | ||||
|         </center> | ||||
|     </body> | ||||
| </html> | ||||
							
								
								
									
										
											BIN
										
									
								
								lib/cache_handler.exe
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								lib/cache_handler.exe
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @@ -1,12 +1,12 @@ | ||||
| { | ||||
|     "name": "OpenFusionClient", | ||||
|     "version": "1.4.1", | ||||
|     "version": "1.5.2", | ||||
|     "lockfileVersion": 2, | ||||
|     "requires": true, | ||||
|     "packages": { | ||||
|         "": { | ||||
|             "name": "OpenFusionClient", | ||||
|             "version": "1.4.1", | ||||
|             "version": "1.5.2", | ||||
|             "hasInstallScript": true, | ||||
|             "license": "MIT", | ||||
|             "dependencies": { | ||||
|   | ||||
| @@ -1,13 +1,13 @@ | ||||
| { | ||||
|     "name": "OpenFusionClient", | ||||
|     "version": "1.4.3", | ||||
|     "version": "1.5.2", | ||||
|     "description": "OpenFusionClient", | ||||
|     "main": "index.js", | ||||
|     "scripts": { | ||||
|         "postinstall": "npx patch-package && npm explore electron-prebuilt -- npm run postinstall", | ||||
|         "start": "electron .", | ||||
|         "pack": "electron-builder --win --ia32 --dir", | ||||
|         "dist": "electron-builder --win --ia32", | ||||
|         "dist": "electron-builder --win --ia32 --publish=never", | ||||
|         "prettier": "npx prettier --write ." | ||||
|     }, | ||||
|     "author": "OpenFusion Contributors", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user