├── .github ├── dependabot.yml └── workflows │ └── build.yaml ├── .gitignore ├── README.md ├── img ├── icon.ico ├── large.bmp └── small.bmp └── inno.iss /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: "/" 5 | schedule: 6 | interval: weekly 7 | open-pull-requests-limit: 99 8 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: Build Installer 2 | 3 | on: 4 | push: 5 | 6 | jobs: 7 | build: 8 | if: ${{ github.repository_owner == 'sklauncher' }} 9 | runs-on: windows-latest 10 | outputs: 11 | jar-checksum: ${{ steps.jar-hash.outputs.checksum }} 12 | installer-checksum: ${{ steps.installer-hash.outputs.checksum }} 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | # The JAR file is not stored in the repository, so we need to download it. 18 | # Since the download uses a one-time URL, we keep a direct link in the repository secrets. 19 | # However, this link always points to the universal JAR URL from the latest release 20 | # (checksum verification follows in the next step). 21 | - name: Download JAR 22 | run: | 23 | Invoke-WebRequest -Uri "${{ secrets.JAR_URL }}" -OutFile "SKlauncher.jar" 24 | shell: pwsh 25 | 26 | - name: Display and capture checksum of JAR 27 | id: jar-hash 28 | run: | 29 | $hash = (Get-FileHash SKlauncher.jar -Algorithm SHA256).Hash 30 | Write-Host "JAR SHA256: $hash" 31 | Add-Content $env:GITHUB_OUTPUT "checksum=$hash" 32 | shell: pwsh 33 | 34 | # Note: Currently InnoSetup on chocolatey is outdated 35 | # - name: Install InnoSetup 36 | # run: | 37 | # choco install innosetup --no-progress 38 | 39 | - uses: MinoruSekine/setup-scoop@v4.0.1 40 | with: 41 | buckets: nonportable 42 | apps: innosetup-np 43 | 44 | - name: Download 7zip CLI 45 | run: | 46 | Invoke-WebRequest -Uri "https://www.7-zip.org/a/7z2409-extra.7z" -OutFile "7z-extra.7z" 47 | & 'C:\Program Files\7-Zip\7z.exe' e 7z-extra.7z -o"." 7za.exe -r -y 48 | Remove-Item 7z-extra.7z 49 | shell: pwsh 50 | 51 | - name: Compile Installer 52 | run: | 53 | & 'C:\Program Files (x86)\Inno Setup 6\ISCC.exe' /O"." inno.iss 54 | shell: pwsh 55 | 56 | - name: Upload Artifacts 57 | uses: actions/upload-artifact@v4 58 | with: 59 | name: SKlauncher-Installer 60 | path: "*_Setup.exe" 61 | 62 | - name: Display and capture checksum of Installer 63 | id: installer-hash 64 | run: | 65 | $hash = (Get-FileHash *_Setup.exe -Algorithm SHA256).Hash 66 | Write-Host "Installer SHA256: $hash" 67 | Add-Content $env:GITHUB_OUTPUT "checksum=$hash" 68 | shell: pwsh 69 | 70 | update_latest_release: 71 | name: Upload build to Latest Release 72 | if: github.event_name != 'pull_request' 73 | needs: build 74 | runs-on: ubuntu-latest 75 | permissions: 76 | contents: write 77 | 78 | steps: 79 | - name: Set up variables 80 | id: vars 81 | run: | 82 | echo "date_now=$(date --rfc-3339=seconds)" >> "${GITHUB_OUTPUT}" 83 | 84 | - name: Download build artifacts from previous job 85 | uses: actions/download-artifact@v4 86 | with: 87 | path: artifacts 88 | 89 | - name: Delete the existing latest pre-release 90 | run: | 91 | gh release delete latest --cleanup-tag --yes --repo $GITHUB_REPOSITORY || echo "Release 'latest' not found, continuing..." 92 | env: 93 | GITHUB_TOKEN: ${{ github.token }} 94 | 95 | - name: Create a new latest build release 96 | uses: ncipollo/release-action@v1 97 | with: 98 | allowUpdates: true 99 | artifactErrorsFailBuild: true 100 | artifacts: artifacts/*/* 101 | body: | 102 | **This is an automatically generated latest build of SKlauncher.** 103 | **⚠️ This is a development build and may be unstable. ⚠️** 104 | **Use at your own risk.** 105 | 106 | ## Build Information 107 | - **Build date:** `${{ steps.vars.outputs.date_now }}` 108 | - **Commit:** ${{ github.sha }} 109 | - **Triggered by:** ${{ github.event_name }} 110 | 111 | ## Checksums 112 | - **JAR SHA256:** `${{ needs.build.outputs.jar-checksum }}` 113 | - **Installer SHA256:** `${{ needs.build.outputs.installer-checksum }}` 114 | name: Latest Build 115 | prerelease: true 116 | removeArtifacts: true 117 | tag: latest -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | *.exe 4 | *.jar -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # SKinstaller 4 | **Official installer for SKlauncher on Windows** 5 | 6 |
7 | 8 | ## :hammer: Building from Source 9 | ### Prerequisites 10 | - [Inno Setup 6](https://jrsoftware.org/isinfo.php) - Stable Release 11 | - [SKlauncher](https://skmedix.pl/) - Download .jar file 12 | - [7-Zip](https://www.7-zip.org/) - Download 7-Zip Extra 13 | 14 | ### Build Steps 15 | 1. Clone the repository 16 | 2. Move `SKlauncher-VERSION.jar` to the repository folder and rename it to `SKlauncher.jar` 17 | 3. Move `7za.exe` to the repository folder 18 | 4. Open `inno.iss` with *Inno Setup* and finally click on **Compile** 19 | -------------------------------------------------------------------------------- /img/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sklauncher/installer/2b18cdf383c0c0fabf2924cf5b0afc6c170e58d7/img/icon.ico -------------------------------------------------------------------------------- /img/large.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sklauncher/installer/2b18cdf383c0c0fabf2924cf5b0afc6c170e58d7/img/large.bmp -------------------------------------------------------------------------------- /img/small.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sklauncher/installer/2b18cdf383c0c0fabf2924cf5b0afc6c170e58d7/img/small.bmp -------------------------------------------------------------------------------- /inno.iss: -------------------------------------------------------------------------------- 1 | #define AppName "SKlauncher" 2 | #define AppURL "https://skmedix.pl" 3 | #define AppVersion "3.2.12.0" 4 | #define AppVersionPretty "3.2.12" 5 | #define AppVersionShort "3.2" 6 | #define AppAuthor "skmedix.pl" 7 | #define AppDir "sklauncher" 8 | #define JREVersion "21.0.6+7" 9 | #define JREFolder "jdk-21.0.6+7-jre" 10 | #define JRESHA256 "707c981a4ff9e680a9ea5d6f625eafe8bc47e1f89140a67d761fde24fc02ab49" 11 | #define JavaFXVersion "22.0.2" 12 | #define MainJarFile "SKlauncher.jar" 13 | 14 | [Setup] 15 | AppId={{A151427E-7A46-4D6D-8534-C4C04BADA77A} 16 | AppName={#AppName} {#AppVersionShort} 17 | AppVersion={#AppVersion} 18 | AppPublisher={#AppAuthor} 19 | AppPublisherURL={#AppURL} 20 | AppSupportURL={#AppURL} 21 | AppUpdatesURL={#AppURL} 22 | VersionInfoVersion={#AppVersion} 23 | DefaultDirName={userappdata}\{#AppDir} 24 | DisableProgramGroupPage=no 25 | DefaultGroupName={#AppName} 26 | PrivilegesRequired=lowest 27 | OutputBaseFilename={#AppName}_{#AppVersionPretty}_Setup 28 | SetupIconFile=img/icon.ico 29 | UninstallDisplayIcon={app}\icon.ico 30 | UninstallDisplayName={#AppName} {#AppVersionShort} 31 | ; start - https://stackoverflow.com/a/77553798 32 | Compression=zip 33 | SolidCompression=no 34 | ; stop - https://stackoverflow.com/a/77553798 35 | WizardStyle=modern 36 | WizardSmallImageFile=img/small.bmp 37 | WizardImageFile=img/large.bmp 38 | ExtraDiskSpaceRequired=52428800 39 | DisableWelcomePage=no 40 | DisableDirPage=auto 41 | ArchitecturesAllowed=x64compatible 42 | ArchitecturesInstallIn64BitMode=x64compatible 43 | DirExistsWarning=no 44 | 45 | [Files] 46 | Source: "{#MainJarFile}"; DestDir: "{app}"; Flags: ignoreversion 47 | Source: "img\icon.ico"; DestDir: "{app}"; Flags: ignoreversion 48 | Source: "7za.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall 49 | Source: "{tmp}\jre.zip"; DestDir: "{tmp}"; Flags: external deleteafterinstall 50 | 51 | [Icons] 52 | Name: "{group}\{#AppName}"; Filename: "{app}\jre\bin\javaw.exe"; Parameters: "-Xmx512M -jar ""{app}\{#MainJarFile}"""; IconFilename: "{app}\icon.ico"; WorkingDir: "{app}" 53 | Name: "{userdesktop}\{#AppName}"; Filename: "{app}\jre\bin\javaw.exe"; Parameters: "-Xmx512M -jar ""{app}\{#MainJarFile}"""; IconFilename: "{app}\icon.ico"; WorkingDir: "{app}" 54 | Name: "{group}\Uninstall {#AppName}"; Filename: "{uninstallexe}"; IconFilename: "{app}\icon.ico" 55 | 56 | [Install] 57 | Name: "JavaFXCopy"; Description: "Copy JavaFX files"; Types: full; Flags: fixed 58 | 59 | [Messages] 60 | WelcomeLabel1=Welcome to the installation of {#AppName}! 61 | WelcomeLabel2=This will install {#AppName} on your computer.%n%nIt is recommended that you close all other applications before continuing. 62 | 63 | [Dirs] 64 | Name: "{userappdata}\.minecraft\{#AppDir}" 65 | Name: "{userappdata}\.minecraft\{#AppDir}\javafx" 66 | 67 | [Code] 68 | var 69 | DownloadPage: TDownloadWizardPage; 70 | DownloadError: String; 71 | JavaFXModules: array[0..5] of string; 72 | 73 | function OnDownloadProgress(Url, FileName: String; Progress, ProgressMax: Int64): Boolean; 74 | begin 75 | if Progress = ProgressMax then 76 | Log(Format('Successfully downloaded file to {tmp}: %s', [FileName])); 77 | Result := True; 78 | end; 79 | 80 | procedure InitializeWizard; 81 | begin 82 | DownloadPage := CreateDownloadPage(SetupMessage(msgWizardPreparing), SetupMessage(msgPreparingDesc), @OnDownloadProgress); 83 | 84 | JavaFXModules[0] := 'javafx-base'; 85 | JavaFXModules[1] := 'javafx-graphics'; 86 | JavaFXModules[2] := 'javafx-controls'; 87 | JavaFXModules[3] := 'javafx-media'; 88 | JavaFXModules[4] := 'javafx-swing'; 89 | JavaFXModules[5] := 'javafx-web'; 90 | end; 91 | 92 | function GetJavaFXDownloadURL(Module: String; IsSHA1: Boolean): String; 93 | var 94 | BaseURL: String; 95 | begin 96 | BaseURL := 'https://repo1.maven.org/maven2/org/openjfx/' + Module + '/' + '{#JavaFXVersion}' + '/' + Module + '-' + '{#JavaFXVersion}'; 97 | 98 | if IsSHA1 then 99 | Result := BaseURL + '-win.jar.sha1' 100 | else 101 | Result := BaseURL + '-win.jar'; 102 | 103 | Log('Generated URL: ' + Result); 104 | end; 105 | 106 | function LoadSHA1(const FileName: String; var SHA1: String): Boolean; 107 | var 108 | LoadedString: AnsiString; 109 | begin 110 | Result := False; 111 | SHA1 := ''; 112 | 113 | if FileExists(FileName) then 114 | begin 115 | if LoadStringFromFile(FileName, LoadedString) then 116 | begin 117 | SHA1 := Trim(String(LoadedString)); 118 | Result := True; 119 | Log('Successfully loaded SHA1 from: ' + FileName + ' - Value: ' + SHA1); 120 | end 121 | else 122 | Log('Failed to load content from SHA1 file: ' + FileName); 123 | end 124 | else 125 | Log('SHA1 file not found: ' + FileName); 126 | end; 127 | 128 | procedure RenameJRE; 129 | begin 130 | Log('Renaming jre directory'); 131 | if not RenameFile(ExpandConstant('{app}\\{#JREFolder}'), ExpandConstant('{app}\\jre')) then begin 132 | Log('Failed to rename jre folder'); 133 | end; 134 | end; 135 | 136 | function NextButtonClick(CurPageID: Integer): Boolean; 137 | var 138 | ErrorMsg: String; 139 | i: Integer; 140 | URL: String; 141 | begin 142 | Result := True; 143 | 144 | if CurPageID = wpReady then begin 145 | DownloadPage.Clear; 146 | 147 | Log('Starting download process...'); 148 | 149 | // Add JRE download 150 | Log('Adding JRE download to queue...'); 151 | DownloadPage.Add('https://github.com/adoptium/temurin21-binaries/releases/download/jdk-{#JREVersion}/OpenJDK21U-jre_x64_windows_hotspot_{#StringChange(JREVersion, '+', '_')}.zip', 152 | 'jre.zip', '{#JRESHA256}'); 153 | 154 | // Add JavaFX module downloads 155 | for i := 0 to 5 do begin 156 | URL := GetJavaFXDownloadURL(JavaFXModules[i], False); 157 | Log('Adding JavaFX module to queue: ' + URL); 158 | DownloadPage.Add(URL, 'javafx-' + IntToStr(i) + '.jar', ''); 159 | 160 | URL := GetJavaFXDownloadURL(JavaFXModules[i], True); 161 | Log('Adding JavaFX SHA1 to queue: ' + URL); 162 | DownloadPage.Add(URL, 'javafx-' + IntToStr(i) + '.jar.sha1', ''); 163 | end; 164 | 165 | DownloadPage.Show; 166 | try 167 | try 168 | Log('Starting downloads...'); 169 | DownloadPage.Download; 170 | Log('Downloads completed successfully'); 171 | except 172 | if DownloadPage.AbortedByUser then begin 173 | Log('Download aborted by user.'); 174 | ErrorMsg := 'Download was cancelled. SKlauncher requires Java and JavaFX to function. Setup cannot continue.'; 175 | end else begin 176 | DownloadError := GetExceptionMessage; 177 | Log('Download error: ' + DownloadError); 178 | ErrorMsg := 'Failed to download required files: ' + DownloadError + #13#10 + 179 | 'SKlauncher requires Java and JavaFX to function. Please check your internet connection and try again.'; 180 | end; 181 | SuppressibleMsgBox(ErrorMsg, mbCriticalError, MB_OK, IDOK); 182 | Result := False; 183 | end; 184 | finally 185 | DownloadPage.Hide; 186 | end; 187 | end; 188 | end; 189 | 190 | procedure CopyJavaFXFiles; 191 | var 192 | i: Integer; 193 | SourceFile, SourceSHA1, DestFile, DestSHA1, DestDir: String; 194 | begin 195 | Log('Starting JavaFX files copy process...'); 196 | 197 | DestDir := ExpandConstant('{userappdata}\.minecraft\{#AppDir}\javafx'); 198 | Log('Destination directory: ' + DestDir); 199 | 200 | // Ensure the destination directory exists 201 | if not DirExists(DestDir) then 202 | begin 203 | Log('Creating destination directory...'); 204 | if ForceDirectories(DestDir) then 205 | Log('Successfully created directory: ' + DestDir) 206 | else 207 | Log('Failed to create directory: ' + DestDir); 208 | end; 209 | 210 | for i := 0 to 5 do begin 211 | SourceFile := ExpandConstant('{tmp}\javafx-' + IntToStr(i) + '.jar'); 212 | SourceSHA1 := ExpandConstant('{tmp}\javafx-' + IntToStr(i) + '.jar.sha1'); 213 | DestFile := DestDir + '\' + JavaFXModules[i] + '-{#JavaFXVersion}-win.jar'; 214 | DestSHA1 := DestFile + '.sha1'; 215 | 216 | Log('Processing JavaFX module ' + IntToStr(i) + ':'); 217 | Log(' Source: ' + SourceFile); 218 | Log(' Source SHA1: ' + SourceSHA1); 219 | Log(' Destination: ' + DestFile); 220 | Log(' Destination SHA1: ' + DestSHA1); 221 | 222 | if FileExists(SourceFile) then begin 223 | if CopyFile(SourceFile, DestFile, False) then 224 | Log(' Successfully copied JavaFX module') 225 | else 226 | Log(' Failed to copy JavaFX module'); 227 | 228 | if FileExists(SourceSHA1) then begin 229 | if CopyFile(SourceSHA1, DestSHA1, False) then 230 | Log(' Successfully copied SHA1 file') 231 | else 232 | Log(' Failed to copy SHA1 file'); 233 | end else 234 | Log(' SHA1 file not found: ' + SourceSHA1); 235 | end else 236 | Log(' Source file not found: ' + SourceFile); 237 | end; 238 | 239 | Log('JavaFX files copy process completed'); 240 | end; 241 | 242 | procedure DoInstall; 243 | begin 244 | RenameJRE; 245 | CopyJavaFXFiles; 246 | end; 247 | 248 | [Run] 249 | Filename: "{tmp}\7za.exe"; Parameters: "x -y {tmp}\jre.zip"; WorkingDir: "{app}"; AfterInstall: DoInstall; StatusMsg: "Extracting Java Runtime..."; Flags: runhidden runascurrentuser 250 | 251 | ; Launch the JAR file after installation 252 | Filename: "{app}\jre\bin\javaw.exe"; Parameters: "-Xmx512M -jar ""{app}\{#MainJarFile}"""; Description: "{cm:LaunchProgram,{#AppName}}"; Flags: nowait postinstall skipifsilent 253 | 254 | [UninstallDelete] 255 | Type: filesandordirs; Name: "{app}\jre" 256 | Type: filesandordirs; Name: "{userappdata}\.minecraft\{#AppDir}" 257 | Type: filesandordirs; Name: "{userappdata}\.minecraft\{#AppDir}\javafx" --------------------------------------------------------------------------------