-
Notifications
You must be signed in to change notification settings - Fork 0
/
Octodad.cs
414 lines (378 loc) · 16.6 KB
/
Octodad.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Timers;
using System.Windows.Forms;
using Microsoft.Win32;
namespace Octodad
{
class Octodad
{
Process pOctodad { get; set; }
System.Timers.Timer tLoadingTimer { get; set; }
long lFirstLoadMessage { get; set; }
long lLastLoadMessage { get; set; }
public string strCurrentLevel { get; set; }
public long lLoadingTimes { get; set; }
public Octodad()
{
// no current level
strCurrentLevel = "";
// Initialise load timer
tLoadingTimer = new System.Timers.Timer(2000);
tLoadingTimer.Enabled = false;
tLoadingTimer.Elapsed += LoadingTimer_Elapsed;
// Start the game
StartOctodad();
}
void LoadingTimer_Elapsed(object sender, ElapsedEventArgs e)
{
// Stop our loading timer
tLoadingTimer.Stop();
// Calculate how long the loading time took
long lLoadTime = lLastLoadMessage - lFirstLoadMessage;
// Add the loading time on
lLoadingTimes += lLoadTime;
// Print the loading time in seconds
Console.WriteLine("Loading time for current level: {0} seconds, total time {1}", lLoadTime / 1000.0f, lLoadingTimes / 1000.0f );
}
eLevelID GetLevelIDFromName(String strBuffer)
{
// Maps level names to level IDs
if ("Church_Main.irr" == strBuffer)
{
return eLevelID.Church;
}
else if ("House_Main.irr" == strBuffer)
{
return eLevelID.Home;
}
else if ("OpeningCredits.irr" == strBuffer)
{
return eLevelID.OpeningCredits;
}
else if ("Grocery_Main.irr" == strBuffer)
{
return eLevelID.Grocery;
}
else if ("Aquarium_Hub.irr" == strBuffer)
{
return eLevelID.Aquarium_Hub;
}
else if ("Kelp_Main.irr" == strBuffer)
{
return eLevelID.Kelp;
}
else if ("Aquarium_Dark_Main.irr" == strBuffer)
{
return eLevelID.Aqurium_Deep_Sea;
}
else if ("Aquarium_Amazon_Main.irr" == strBuffer)
{
return eLevelID.Amazon;
}
else if ("Boat_Main.irr" == strBuffer)
{
return eLevelID.Boat;
}
else if ("Aquarium_Swimming_Main.irr" == strBuffer)
{
return eLevelID.Aquarium_Swimming;
}
else if ("Stealth_Main.irr" == strBuffer)
{
return eLevelID.Stealth;
}
else if ("Cafeteria_Main.irr" == strBuffer)
{
return eLevelID.Cafeteria;
}
else if ("EndingCredits.irr" == strBuffer)
{
return eLevelID.Credits;
}
else if ("MainScreen_Background.irr" == strBuffer)
{
return eLevelID.MainMenu;
}
return eLevelID.Unknown;
}
public void StartOctodad()
{
// Start our octodad starting thread
Thread pThread = new Thread(StartOctodadThread);
// Needs to be STA for open file dialog
pThread.SetApartmentState ( ApartmentState.STA );
// Start our thread
pThread.Start();
// Make sure our thread is still running
if (pThread.ThreadState == System.Threading.ThreadState.Running)
{
// wait for the process to launch
while (pOctodad == null)
{
// Wait 200ms
Thread.Sleep(200);
// if we abort during startup
if (pThread.ThreadState != System.Threading.ThreadState.Running)
{
// return
return;
}
}
// Wait for the game to exit
pOctodad.WaitForExit();
}
}
public static bool FindGame ( )
{
// Create an open file dialog
OpenFileDialog pOpenFileDialog = new OpenFileDialog();
// Set our initial directory to hopefully a steam directory or just the C drive if not
if (File.Exists("C:\\Program Files (x86)\\Steam\\SteamApps\\common\\Octodad Dadliest Catch\\"))
pOpenFileDialog.InitialDirectory = "C:\\Program Files (x86)\\Steam\\SteamApps\\common\\Octodad Dadliest Catch\\";
else if (File.Exists("C:\\Program Files (x86)\\Steam\\SteamApps\\common\\Octodad Dadliest Catch\\"))
pOpenFileDialog.InitialDirectory = "C:\\Program Files\\Steam\\SteamApps\\common\\Octodad Dadliest Catch\\";
else
pOpenFileDialog.InitialDirectory = "C:\\";
// Filter anything but octodad
pOpenFileDialog.Filter = "Octodad Game (OctodadDadliestCatch.exe)|OctodadDadliestCatch.exe";
// Set the title
pOpenFileDialog.Title = "Please find the Octodad Executable";
// Disable multi select
pOpenFileDialog.Multiselect = false;
// make sure it exists
pOpenFileDialog.CheckFileExists = true;
// if everything is okay
if (pOpenFileDialog.ShowDialog() == DialogResult.OK)
{
// set a registry entry
RegistryKey rkLocation = Registry.CurrentUser.OpenSubKey("Software", true).CreateSubKey("OctodadLauncher");
rkLocation.SetValue("Location", pOpenFileDialog.FileName);
rkLocation.Flush();
// Success
return true;
}
else
{
// Something went wrong possibly user abort
return false;
}
}
public void StartOctodadThread()
{
// Set our location to blank for now
String strLocation = "";
try
{
// Open our registry key
RegistryKey rkLocation = Registry.CurrentUser.OpenSubKey("Software").OpenSubKey ("OctodadLauncher");
// Get our location
strLocation = (String)rkLocation.GetValue("Location");
}
catch (Exception)
{
// Ask the user for the game path
if (FindGame())
{
// Open our registry key
RegistryKey rkLocation = Registry.CurrentUser.OpenSubKey("Software").OpenSubKey("OctodadLauncher");
// Get our location
strLocation = (String)rkLocation.GetValue("Location");
}
else
{
// Something went wrong possibly user abort
return;
}
}
// if the path is valid and the location ends with the right executable name
if (!File.Exists(strLocation) || !strLocation.EndsWith("OctodadDadliestCatch.exe"))
{
// Ask the user for the game path
if ( FindGame() )
{
// Open our registry key
RegistryKey rkLocation = Registry.CurrentUser.OpenSubKey("Software").OpenSubKey("OctodadLauncher");
// Get our location
strLocation = (String)rkLocation.GetValue("Location");
}
else
{
// Something went wrong possibly user abort
return;
}
}
try
{
// Start our process
ProcessStartInfo pStartInfo = new ProcessStartInfo(strLocation)
{
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false,
WorkingDirectory = Path.GetDirectoryName(strLocation)
};
// Start a new process
pOctodad = new Process();
// pass the start info
pOctodad.StartInfo = pStartInfo;
// Start the game
pOctodad.Start();
// Fire off a thread to process the console
Thread pThread = new Thread(ProcessConsole);
// Start the thread
pThread.Start();
}
catch
{
// Find the game
FindGame();
// Restart at the top of this method
StartOctodadThread();
}
}
public void ProcessConsole()
{
// Create a stopwatch with which to time the overhead of this
Stopwatch stopWatch = new Stopwatch();
// were we previously at the main menu
bool bPreviouslyMainMenu = false;
// previous level is now unkown
eLevelID PreviousLevel = eLevelID.Unknown;
// Inf game loop
while (pOctodad.HasExited == false)
{
// Read a line from the output
String strLine = pOctodad.StandardOutput.ReadLine();
// game probably quit
if (strLine == null)
return;
// if the length isn't greater than 47 we aren't a loading message
if (strLine.Length > 47 && strLine[0] == '~' && strLine[5] == '~')
{
// Restart the stopwatch
stopWatch.Restart();
// Get the sub string to ignore the useless parts (mainly path)
strCurrentLevel = strLine.Substring ( 47 );
// get the level from the name
eLevelID Level = GetLevelIDFromName(strCurrentLevel);
// if the level is church and we just came from the menu reset
if ( Level == eLevelID.Church && bPreviouslyMainMenu )
{
// Start a reset the run thread
Thread pThread = new Thread(new ThreadStart(SendKey.ResetRun));
// run the thread
pThread.Start();
// Set the previous level to this level
PreviousLevel = eLevelID.Unknown;
// set the first loading messageto now
lFirstLoadMessage = Environment.TickCount;
// reset our loading time to 0
lLoadingTimes = 0;
#if DEBUG
// print we started the level
Console.WriteLine("Starting level: " + strCurrentLevel.Substring ( 0, strCurrentLevel.Length - 4 ) );
// print we reset the split
Console.WriteLine("Reset splitting on level: " + strCurrentLevel.Substring(0, strCurrentLevel.Length - 4));
#endif
// Start a loading timer
tLoadingTimer.Start();
// we aren't previously at the main menu
bPreviouslyMainMenu = false;
}
else
{
#if DEBUG
// print we started the level
Console.WriteLine("Starting level: " + strCurrentLevel.Substring(0, strCurrentLevel.Length - 4) + " from: " + PreviousLevel.ToString());
#endif
// we aren't previously at the main menu
bPreviouslyMainMenu = false;
if (PreviousLevel == Level)
{
// print we aren't going to split and why
Console.WriteLine("Split refused on level: " + strCurrentLevel.Substring ( 0, strCurrentLevel.Length - 4 ) + " already in this level" );
// same level, don't go any further and restart the loop from the top
continue;
}
// ignore main menu
// Ignore home because it's skipped by credits
// amazon is ignored because it is skipped by going to hub
// deep sea is ignored because it is skipped by going into hub
// boat is ignored because it is skipped by going into hub
// Handle checking previous level such that it splits properly for hub
if (Level == eLevelID.MainMenu || Level == eLevelID.Home
|| Level == eLevelID.Amazon || Level == eLevelID.Aqurium_Deep_Sea || Level == eLevelID.Boat
|| ( Level == eLevelID.Aquarium_Hub && PreviousLevel != eLevelID.Amazon && PreviousLevel != eLevelID.Grocery && PreviousLevel != eLevelID.Kelp && PreviousLevel != eLevelID.Aqurium_Deep_Sea) )
{
// don't remember main menu as previous as this causes issues with the above checks
if (Level != eLevelID.MainMenu)
{
// store our previous level
PreviousLevel = Level;
}
else
{
// looks like we are the main menu, remember that
bPreviouslyMainMenu = true;
}
// print we aren't going to split and why
Console.WriteLine("Split refused on level: " + strCurrentLevel.Substring ( 0, strCurrentLevel.Length - 4 ) + " from: " + PreviousLevel.ToString ( ) );
// don't skip, restart the loop from the top
continue;
}
else if (Level == eLevelID.Credits)
{
// Finished
// previous level is now unknown
PreviousLevel = eLevelID.Unknown;
// Print the loading time in seconds
Console.WriteLine("Loading time over entire run: {0} seconds", lLoadingTimes / 1000.0f);
}
// store our previous level
PreviousLevel = Level;
// reset our first loading message
lFirstLoadMessage = Environment.TickCount;
// Create a split press thread
Thread pThread = new Thread(new ThreadStart(SendKey.SplitRun));
// Start the thread
pThread.Start();
// Start our loading timer
tLoadingTimer.Start();
#if DEBUG
// print we split the level
Console.WriteLine("Splitting on level: " + strCurrentLevel.Substring ( 0, strCurrentLevel.Length - 4 ) );
// print what level this is
Console.WriteLine(strCurrentLevel);
// reset the stopwatch
stopWatch.Stop();
// calculate the overhead
long lOverheadTime = stopWatch.ElapsedTicks;
// format the overhead
String strElapsedTime = String.Format("Autosplit overhead: {0} us", lOverheadTime / (Stopwatch.Frequency / (1000L * 1000L)));
// print the overhead
Console.WriteLine(strElapsedTime);
#endif
}
}
// if the loading timer is enabled and this is a loaded message
else if (tLoadingTimer.Enabled && strLine.StartsWith("Loaded "))
{
// set our last load message to now
lLastLoadMessage = Environment.TickCount;
// restart the loading timer
tLoadingTimer.Stop();
tLoadingTimer.Start();
//Console.WriteLine(strLine);
}
}
}
}
}