├── .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"
--------------------------------------------------------------------------------