├── .gitignore
├── GameLauncher.sln
├── GameLauncher
├── App.xaml
├── App.xaml.cs
├── AssemblyInfo.cs
├── GameLauncher.csproj
├── MainWindow.xaml
├── MainWindow.xaml.cs
└── images
│ ├── Icon.ico
│ └── LauncherBackground.png
├── Licence.txt
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.vspscc
94 | *.vssscc
95 | .builds
96 | *.pidb
97 | *.svclog
98 | *.scc
99 |
100 | # Chutzpah Test files
101 | _Chutzpah*
102 |
103 | # Visual C++ cache files
104 | ipch/
105 | *.aps
106 | *.ncb
107 | *.opendb
108 | *.opensdf
109 | *.sdf
110 | *.cachefile
111 | *.VC.db
112 | *.VC.VC.opendb
113 |
114 | # Visual Studio profiler
115 | *.psess
116 | *.vsp
117 | *.vspx
118 | *.sap
119 |
120 | # Visual Studio Trace Files
121 | *.e2e
122 |
123 | # TFS 2012 Local Workspace
124 | $tf/
125 |
126 | # Guidance Automation Toolkit
127 | *.gpState
128 |
129 | # ReSharper is a .NET coding add-in
130 | _ReSharper*/
131 | *.[Rr]e[Ss]harper
132 | *.DotSettings.user
133 |
134 | # TeamCity is a build add-in
135 | _TeamCity*
136 |
137 | # DotCover is a Code Coverage Tool
138 | *.dotCover
139 |
140 | # AxoCover is a Code Coverage Tool
141 | .axoCover/*
142 | !.axoCover/settings.json
143 |
144 | # Coverlet is a free, cross platform Code Coverage Tool
145 | coverage*[.json, .xml, .info]
146 |
147 | # Visual Studio code coverage results
148 | *.coverage
149 | *.coveragexml
150 |
151 | # NCrunch
152 | _NCrunch_*
153 | .*crunch*.local.xml
154 | nCrunchTemp_*
155 |
156 | # MightyMoose
157 | *.mm.*
158 | AutoTest.Net/
159 |
160 | # Web workbench (sass)
161 | .sass-cache/
162 |
163 | # Installshield output folder
164 | [Ee]xpress/
165 |
166 | # DocProject is a documentation generator add-in
167 | DocProject/buildhelp/
168 | DocProject/Help/*.HxT
169 | DocProject/Help/*.HxC
170 | DocProject/Help/*.hhc
171 | DocProject/Help/*.hhk
172 | DocProject/Help/*.hhp
173 | DocProject/Help/Html2
174 | DocProject/Help/html
175 |
176 | # Click-Once directory
177 | publish/
178 |
179 | # Publish Web Output
180 | *.[Pp]ublish.xml
181 | *.azurePubxml
182 | # Note: Comment the next line if you want to checkin your web deploy settings,
183 | # but database connection strings (with potential passwords) will be unencrypted
184 | *.pubxml
185 | *.publishproj
186 |
187 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
188 | # checkin your Azure Web App publish settings, but sensitive information contained
189 | # in these scripts will be unencrypted
190 | PublishScripts/
191 |
192 | # NuGet Packages
193 | *.nupkg
194 | # NuGet Symbol Packages
195 | *.snupkg
196 | # The packages folder can be ignored because of Package Restore
197 | **/[Pp]ackages/*
198 | # except build/, which is used as an MSBuild target.
199 | !**/[Pp]ackages/build/
200 | # Uncomment if necessary however generally it will be regenerated when needed
201 | #!**/[Pp]ackages/repositories.config
202 | # NuGet v3's project.json files produces more ignorable files
203 | *.nuget.props
204 | *.nuget.targets
205 |
206 | # Microsoft Azure Build Output
207 | csx/
208 | *.build.csdef
209 |
210 | # Microsoft Azure Emulator
211 | ecf/
212 | rcf/
213 |
214 | # Windows Store app package directories and files
215 | AppPackages/
216 | BundleArtifacts/
217 | Package.StoreAssociation.xml
218 | _pkginfo.txt
219 | *.appx
220 | *.appxbundle
221 | *.appxupload
222 |
223 | # Visual Studio cache files
224 | # files ending in .cache can be ignored
225 | *.[Cc]ache
226 | # but keep track of directories ending in .cache
227 | !?*.[Cc]ache/
228 |
229 | # Others
230 | ClientBin/
231 | ~$*
232 | *~
233 | *.dbmdl
234 | *.dbproj.schemaview
235 | *.jfm
236 | *.pfx
237 | *.publishsettings
238 | orleans.codegen.cs
239 |
240 | # Including strong name files can present a security risk
241 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
242 | #*.snk
243 |
244 | # Since there are multiple workflows, uncomment next line to ignore bower_components
245 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
246 | #bower_components/
247 |
248 | # RIA/Silverlight projects
249 | Generated_Code/
250 |
251 | # Backup & report files from converting an old project file
252 | # to a newer Visual Studio version. Backup files are not needed,
253 | # because we have git ;-)
254 | _UpgradeReport_Files/
255 | Backup*/
256 | UpgradeLog*.XML
257 | UpgradeLog*.htm
258 | ServiceFabricBackup/
259 | *.rptproj.bak
260 |
261 | # SQL Server files
262 | *.mdf
263 | *.ldf
264 | *.ndf
265 |
266 | # Business Intelligence projects
267 | *.rdl.data
268 | *.bim.layout
269 | *.bim_*.settings
270 | *.rptproj.rsuser
271 | *- [Bb]ackup.rdl
272 | *- [Bb]ackup ([0-9]).rdl
273 | *- [Bb]ackup ([0-9][0-9]).rdl
274 |
275 | # Microsoft Fakes
276 | FakesAssemblies/
277 |
278 | # GhostDoc plugin setting file
279 | *.GhostDoc.xml
280 |
281 | # Node.js Tools for Visual Studio
282 | .ntvs_analysis.dat
283 | node_modules/
284 |
285 | # Visual Studio 6 build log
286 | *.plg
287 |
288 | # Visual Studio 6 workspace options file
289 | *.opt
290 |
291 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
292 | *.vbw
293 |
294 | # Visual Studio LightSwitch build output
295 | **/*.HTMLClient/GeneratedArtifacts
296 | **/*.DesktopClient/GeneratedArtifacts
297 | **/*.DesktopClient/ModelManifest.xml
298 | **/*.Server/GeneratedArtifacts
299 | **/*.Server/ModelManifest.xml
300 | _Pvt_Extensions
301 |
302 | # Paket dependency manager
303 | .paket/paket.exe
304 | paket-files/
305 |
306 | # FAKE - F# Make
307 | .fake/
308 |
309 | # CodeRush personal settings
310 | .cr/personal
311 |
312 | # Python Tools for Visual Studio (PTVS)
313 | __pycache__/
314 | *.pyc
315 |
316 | # Cake - Uncomment if you are using it
317 | # tools/**
318 | # !tools/packages.config
319 |
320 | # Tabs Studio
321 | *.tss
322 |
323 | # Telerik's JustMock configuration file
324 | *.jmconfig
325 |
326 | # BizTalk build output
327 | *.btp.cs
328 | *.btm.cs
329 | *.odx.cs
330 | *.xsd.cs
331 |
332 | # OpenCover UI analysis results
333 | OpenCover/
334 |
335 | # Azure Stream Analytics local run output
336 | ASALocalRun/
337 |
338 | # MSBuild Binary and Structured Log
339 | *.binlog
340 |
341 | # NVidia Nsight GPU debugger configuration file
342 | *.nvuser
343 |
344 | # MFractors (Xamarin productivity tool) working folder
345 | .mfractor/
346 |
347 | # Local History for Visual Studio
348 | .localhistory/
349 |
350 | # BeatPulse healthcheck temp database
351 | healthchecksdb
352 |
353 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
354 | MigrationBackup/
355 |
356 | # Ionide (cross platform F# VS Code tools) working folder
357 | .ionide/
358 |
359 | # Fody - auto-generated XML schema
360 | FodyWeavers.xsd
--------------------------------------------------------------------------------
/GameLauncher.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.30002.166
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GameLauncher", "GameLauncher\GameLauncher.csproj", "{7FA3FB14-7943-4E38-820E-77E2BA28283E}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {7FA3FB14-7943-4E38-820E-77E2BA28283E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {7FA3FB14-7943-4E38-820E-77E2BA28283E}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {7FA3FB14-7943-4E38-820E-77E2BA28283E}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {7FA3FB14-7943-4E38-820E-77E2BA28283E}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {46025548-AD18-4CB9-94E6-E4BEAE038A5F}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/GameLauncher/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/GameLauncher/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace GameLauncher
10 | {
11 | ///
12 | /// Interaction logic for App.xaml
13 | ///
14 | public partial class App : Application
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/GameLauncher/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | [assembly: ThemeInfo(
4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
5 | //(used if a resource is not found in the page,
6 | // or application resource dictionaries)
7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
8 | //(used if a resource is not found in the page,
9 | // app, or any theme specific resource dictionaries)
10 | )]
11 |
--------------------------------------------------------------------------------
/GameLauncher/GameLauncher.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | netcoreapp3.1
6 | true
7 | images\Icon.ico
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/GameLauncher/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/GameLauncher/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.IO.Compression;
6 | using System.Net;
7 | using System.Windows;
8 |
9 | namespace GameLauncher
10 | {
11 | enum LauncherStatus
12 | {
13 | ready,
14 | failed,
15 | downloadingGame,
16 | downloadingUpdate
17 | }
18 |
19 | ///
20 | /// Interaction logic for MainWindow.xaml
21 | ///
22 | public partial class MainWindow : Window
23 | {
24 | private string rootPath;
25 | private string versionFile;
26 | private string gameZip;
27 | private string gameExe;
28 |
29 | private LauncherStatus _status;
30 | internal LauncherStatus Status
31 | {
32 | get => _status;
33 | set
34 | {
35 | _status = value;
36 | switch (_status)
37 | {
38 | case LauncherStatus.ready:
39 | PlayButton.Content = "Play";
40 | break;
41 | case LauncherStatus.failed:
42 | PlayButton.Content = "Update Failed - Retry";
43 | break;
44 | case LauncherStatus.downloadingGame:
45 | PlayButton.Content = "Downloading Game";
46 | break;
47 | case LauncherStatus.downloadingUpdate:
48 | PlayButton.Content = "Downloading Update";
49 | break;
50 | default:
51 | break;
52 | }
53 | }
54 | }
55 |
56 | public MainWindow()
57 | {
58 | InitializeComponent();
59 |
60 | rootPath = Directory.GetCurrentDirectory();
61 | versionFile = Path.Combine(rootPath, "Version.txt");
62 | gameZip = Path.Combine(rootPath, "Build.zip");
63 | gameExe = Path.Combine(rootPath, "Build", "Pirate Game.exe");
64 | }
65 |
66 | private void CheckForUpdates()
67 | {
68 | if (File.Exists(versionFile))
69 | {
70 | Version localVersion = new Version(File.ReadAllText(versionFile));
71 | VersionText.Text = localVersion.ToString();
72 |
73 | try
74 | {
75 | WebClient webClient = new WebClient();
76 | Version onlineVersion = new Version(webClient.DownloadString("https://drive.google.com/uc?export=download&id=1R3GT_VINzmNoXKtvnvuJw6C86-k3Jr5s"));
77 |
78 | if (onlineVersion.IsDifferentThan(localVersion))
79 | {
80 | InstallGameFiles(true, onlineVersion);
81 | }
82 | else
83 | {
84 | Status = LauncherStatus.ready;
85 | }
86 | }
87 | catch (Exception ex)
88 | {
89 | Status = LauncherStatus.failed;
90 | MessageBox.Show($"Error checking for game updates: {ex}");
91 | }
92 | }
93 | else
94 | {
95 | InstallGameFiles(false, Version.zero);
96 | }
97 | }
98 |
99 | private void InstallGameFiles(bool _isUpdate, Version _onlineVersion)
100 | {
101 | try
102 | {
103 | WebClient webClient = new WebClient();
104 | if (_isUpdate)
105 | {
106 | Status = LauncherStatus.downloadingUpdate;
107 | }
108 | else
109 | {
110 | Status = LauncherStatus.downloadingGame;
111 | _onlineVersion = new Version(webClient.DownloadString("https://drive.google.com/uc?export=download&id=1R3GT_VINzmNoXKtvnvuJw6C86-k3Jr5s"));
112 | }
113 |
114 | webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadGameCompletedCallback);
115 | webClient.DownloadFileAsync(new Uri("https://drive.google.com/uc?export=download&id=1SNA_3P5wVp4tZi5NKhiGAAD6q4ilbaaf"), gameZip, _onlineVersion);
116 | }
117 | catch (Exception ex)
118 | {
119 | Status = LauncherStatus.failed;
120 | MessageBox.Show($"Error installing game files: {ex}");
121 | }
122 | }
123 |
124 | private void DownloadGameCompletedCallback(object sender, AsyncCompletedEventArgs e)
125 | {
126 | try
127 | {
128 | string onlineVersion = ((Version)e.UserState).ToString();
129 | ZipFile.ExtractToDirectory(gameZip, rootPath, true);
130 | File.Delete(gameZip);
131 |
132 | File.WriteAllText(versionFile, onlineVersion);
133 |
134 | VersionText.Text = onlineVersion;
135 | Status = LauncherStatus.ready;
136 | }
137 | catch (Exception ex)
138 | {
139 | Status = LauncherStatus.failed;
140 | MessageBox.Show($"Error finishing download: {ex}");
141 | }
142 | }
143 |
144 | private void Window_ContentRendered(object sender, EventArgs e)
145 | {
146 | CheckForUpdates();
147 | }
148 |
149 | private void PlayButton_Click(object sender, RoutedEventArgs e)
150 | {
151 | if (File.Exists(gameExe) && Status == LauncherStatus.ready)
152 | {
153 | ProcessStartInfo startInfo = new ProcessStartInfo(gameExe);
154 | startInfo.WorkingDirectory = Path.Combine(rootPath, "Build");
155 | Process.Start(startInfo);
156 |
157 | Close();
158 | }
159 | else if (Status == LauncherStatus.failed)
160 | {
161 | CheckForUpdates();
162 | }
163 | }
164 | }
165 |
166 | struct Version
167 | {
168 | internal static Version zero = new Version(0, 0, 0);
169 |
170 | private short major;
171 | private short minor;
172 | private short subMinor;
173 |
174 | internal Version(short _major, short _minor, short _subMinor)
175 | {
176 | major = _major;
177 | minor = _minor;
178 | subMinor = _subMinor;
179 | }
180 | internal Version(string _version)
181 | {
182 | string[] versionStrings = _version.Split('.');
183 | if (versionStrings.Length != 3)
184 | {
185 | major = 0;
186 | minor = 0;
187 | subMinor = 0;
188 | return;
189 | }
190 |
191 | major = short.Parse(versionStrings[0]);
192 | minor = short.Parse(versionStrings[1]);
193 | subMinor = short.Parse(versionStrings[2]);
194 | }
195 |
196 | internal bool IsDifferentThan(Version _otherVersion)
197 | {
198 | if (major != _otherVersion.major)
199 | {
200 | return true;
201 | }
202 | else
203 | {
204 | if (minor != _otherVersion.minor)
205 | {
206 | return true;
207 | }
208 | else
209 | {
210 | if (subMinor != _otherVersion.subMinor)
211 | {
212 | return true;
213 | }
214 | }
215 | }
216 | return false;
217 | }
218 |
219 | public override string ToString()
220 | {
221 | return $"{major}.{minor}.{subMinor}";
222 | }
223 | }
224 | }
225 |
--------------------------------------------------------------------------------
/GameLauncher/images/Icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tom-weiland/csharp-game-launcher/66c85ff71cee322373383c7d25e42b7b5d2f7066/GameLauncher/images/Icon.ico
--------------------------------------------------------------------------------
/GameLauncher/images/LauncherBackground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tom-weiland/csharp-game-launcher/66c85ff71cee322373383c7d25e42b7b5d2f7066/GameLauncher/images/LauncherBackground.png
--------------------------------------------------------------------------------
/Licence.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Tom Weiland
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # C# Game Launcher Tutorial
2 | This is the source code for the launcher that we build in my [game launcher tutorial](https://youtu.be/JIjZQo03YdA) on YouTube.
3 |
4 | **Note:** in order for this to work you will need to replace the download links in the MainWindow.xaml.cs file. If you're hosting files on Google Drive like we did in the tutorial, you can use [this](https://sites.google.com/site/gdocs2direct/) to convert sharing links into direct-download links.
5 |
6 | [YouTube Channel](https://tomweiland.net/youtube)\
7 | [My Blog](https://tomweiland.net/)\
8 | [Instagram](https://tomweiland.net/instagram)\
9 | [](https://ko-fi.com/Y8Y21O02J)
--------------------------------------------------------------------------------