Skip to content

Commit fdb0fbe

Browse files
committed
Fixed some external GUI bugs. Added extra functionalility to h2 invulnerability to fix fall-timer-disappearing glitch. Fixed h2 checkpoint injection crash. Fixed multilevelpointer issue where GetLastError could give you the second-last-error instead.
1 parent c8764b9 commit fdb0fbe

File tree

12 files changed

+303
-41
lines changed

12 files changed

+303
-41
lines changed

HCMExternal/Converters/DifficultyConverter.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
2525
{ 2, "Heroic" },
2626
{ 3, "Legendary" },
2727
};
28-
2928

3029

31-
return (string) DifficultyMap[(int)value];
30+
31+
return DifficultyMap.ElementAtOrDefault((int)value).Value ?? "Invalid";
32+
3233
}
3334

3435
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)

HCMExternal/Converters/LevelImageConverter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
2121
if (valueString == null)
2222
return "???";
2323

24-
24+
2525
// So I'd like this to check what the current tab index is directly, but haven't figured out how.
2626
// ConverterParameter won't seem to work since this is from a control under the tab control.
2727
// For now we'll used the saved setting which should always be accurate.

HCMExternal/Services/Interproc/InterprocService.cs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -162,16 +162,20 @@ public InterprocService(CheckpointViewModel checkpointViewModel)
162162
private (string, string) getGameSFData(HaloTabEnum game)
163163
{
164164
// Not sure which of these methods is the most reliable
165-
Log.Verbose("AppContext.BaseDirectory: " + AppContext.BaseDirectory
166-
+ "\nSystem.AppDomain.CurrentDomain.BaseDirectory: " + System.AppDomain.CurrentDomain.BaseDirectory
167-
+ "\nSystem.Reflection.Assembly.GetExecutingAssembly().Location: " + System.Reflection.Assembly.GetExecutingAssembly().Location
168-
+ "\nDirectory.GetCurrentDirectory(): " + Directory.GetCurrentDirectory()
169-
);
165+
//Log.Verbose("AppContext.BaseDirectory: " + AppContext.BaseDirectory
166+
// + "\nSystem.AppDomain.CurrentDomain.BaseDirectory: " + System.AppDomain.CurrentDomain.BaseDirectory
167+
// + "\nSystem.Reflection.Assembly.GetExecutingAssembly().Location: " + System.Reflection.Assembly.GetExecutingAssembly().Location
168+
// + "\nDirectory.GetCurrentDirectory(): " + Directory.GetCurrentDirectory()
169+
// );
170+
171+
Log.Verbose("Current directory: " + Directory.GetCurrentDirectory());
170172
var currentBaseDirectory = Directory.GetCurrentDirectory();
171173

172-
var rootFolder = currentBaseDirectory + @"Saves\" + Dictionaries.GameToRootFolderPath[game];
174+
var rootFolder = currentBaseDirectory + @"\Saves\" + Dictionaries.GameToRootFolderPath[game];
173175
var dir = Settings.Default.LastSelectedFolder[(int)game]; // need to try catch this and return root folder on failure.
174-
176+
177+
Log.Verbose("The last selected folder for game: " + game + " was " + Settings.Default.LastSelectedFolder[(int)game]);
178+
175179
if (dir == null) // check if dir is real and exists
176180
{
177181
Log.Error("getGameSFData: dir was null at Settings.Default.LastSelectedFolder[game] with game == " + game + ", as int: " + (int)game);
@@ -183,7 +187,7 @@ public InterprocService(CheckpointViewModel checkpointViewModel)
183187
Log.Verbose("so returning " + Dictionaries.GameToRootFolderPath[game] + ", " + rootFolder);
184188
return (Dictionaries.GameToRootFolderPath[game], rootFolder); // return Root folder if there's a problem.
185189
}
186-
Log.Verbose("getGameSFData: returning " + Path.GetDirectoryName(dir) + ", " + dir + " for game " + game);
190+
Log.Verbose("getGameSFData: returning " + Path.GetFileName(dir) + ", " + dir + " for game " + game);
187191
return (Path.GetFileName(dir), dir);
188192
}
189193

@@ -214,6 +218,15 @@ private void CheckpointViewModel_PropertyChanged(object? sender, System.Componen
214218
var HRsf = getGameSFData(HaloTabEnum.HaloReach);
215219
var H4sf = getGameSFData(HaloTabEnum.Halo4);
216220

221+
Log.Information("Updating save folder shared memory with: \n" +
222+
H1sf.Item2 + "\n" +
223+
H2sf.Item2 + "\n" +
224+
H3sf.Item2 + "\n" +
225+
ODsf.Item2 + "\n" +
226+
HRsf.Item2 + "\n" +
227+
H4sf.Item2 + "\n"
228+
);
229+
217230
Log.Verbose("sending new sf info");
218231
var sf = CheckpointViewModel.SelectedSaveFolder;
219232
Log.Verbose(string.Format("Sending new saveFolder info to internal: {0}", sf == null ? "null!" : sf.SaveFolderPath));

HCMExternal/ViewModels/CheckpointViewModel.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,10 @@ void CheckpointViewModel_PropertyChanged(object? sender, System.ComponentModel.P
236236
switch (e.PropertyName)
237237
{
238238
case nameof(SelectedGame):
239+
HCMExternal.Properties.Settings.Default.LastSelectedGameTab = (int)this.SelectedGame;
239240
RefreshSaveFolderTree();
240241
RefreshCheckpointList();
242+
241243
break;
242244

243245
case nameof(SelectedCheckpoint):
@@ -395,7 +397,13 @@ public void FolderChanged(object sender, RoutedPropertyChangedEventArgs<object>
395397
if (Directory.Exists(saveFolder.SaveFolderPath))
396398
{
397399
Trace.WriteLine("valid new saveFolder, so changing internal selection and inserting into lastSelectedFolder list.");
398-
Properties.Settings.Default.LastSelectedFolder.Insert((int)SelectedGame, saveFolder.SaveFolderPath);
400+
Log.Verbose("New lastSelectedFolder for game " + this.SelectedGame + " is " + saveFolder.SaveFolderPath);
401+
402+
Properties.Settings.Default.LastSelectedFolder[(int)SelectedGame] = saveFolder.SaveFolderPath;
403+
// Properties.Settings.Default.LastSelectedFolder.Insert(, saveFolder.SaveFolderPath);
404+
405+
Log.Verbose("This should be the same value as:" + Properties.Settings.Default.LastSelectedFolder[(int)SelectedGame]);
406+
399407
this.SelectedSaveFolder = saveFolder;
400408
this.RefreshCheckpointList();
401409

HCMExternal/Views/Controls/CheckpointListControl.xaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,11 @@
3535
<MenuItem Header="Inject"
3636
Command="{Binding Path=Parent.DataContext.Inject,
3737
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}" />
38-
38+
3939
<MenuItem Header="Rename"
4040
Command="{Binding Path=Parent.DataContext.RenameCheckpoint,
4141
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}" />
4242

43-
4443
<MenuItem Header="Change version data"
4544
Command="{Binding Path=Parent.DataContext.ReVersionCheckpoint,
4645
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}" />

HCMInternal/InjectCheckpoint.h

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class InjectCheckpoint : public IOptionalCheat {
7575
auto currentCheckpoint = sharedMem->getInjectInfo();
7676

7777
if (currentCheckpoint.selectedCheckpointNull) throw HCMRuntimeException("Can't inject - no checkpoint selected!");
78-
if ((GameState)currentCheckpoint.selectedCheckpointGame != this->mImplGame) throw HCMRuntimeException(std::format("Can't inject - checkpoint from wrong game! Expected: {}, Actual: {}", mImplGame.toString(), ((GameState)currentCheckpoint.selectedCheckpointGame).toString()));
78+
if ((GameState)currentCheckpoint.selectedCheckpointGame != this->mImplGame) throw HCMRuntimeException(std::format("Can't inject - checkpoint from wrong game! Expected: {}, Actual: {}\n(Make sure you switch HCMExternal to the correct game tab)", mImplGame.toString(), ((GameState)currentCheckpoint.selectedCheckpointGame).toString()));
7979

8080

8181
//TODO: load correct level if level not aligned
@@ -181,6 +181,7 @@ class InjectCheckpoint : public IOptionalCheat {
181181
{
182182
bool firstCheckpoint;
183183
mDoubleRevertFlag->readData(&firstCheckpoint);
184+
PLOG_DEBUG << "Double revert flag value: " << firstCheckpoint;
184185
firstCheckpoint ? mCheckpointLocation1->resolve(&checkpointLoc) : mCheckpointLocation2->resolve(&checkpointLoc);
185186
PLOG_DEBUG << "using checkpoint location " << (firstCheckpoint ? "A" : "B") << " @0x" << std::hex << (uint64_t)checkpointLoc;
186187
}
@@ -263,9 +264,14 @@ class InjectCheckpoint : public IOptionalCheat {
263264
if (mInjectRequirements->BSP)
264265
{
265266
PLOG_VERBOSE << "setting BSP data";
266-
std::vector<byte> currentBSPData;
267-
auto err = memcpy_s(currentBSPData.data(), mBSPdata->length, (void*)(checkpointLoc + mBSPdata->offset), mBSPdata->length);
268-
if (err) throw HCMRuntimeException(std::format("error copying bsp data! code: {}", err));
267+
268+
PLOG_VERBOSE << "mBSPdata->length " << mBSPdata->length;
269+
PLOG_VERBOSE << "mBSPdata->offset " << mBSPdata->offset;
270+
PLOG_VERBOSE << "checkpointLoc + mBSPdata->offset " << std::hex << (uintptr_t)(checkpointLoc + mBSPdata->offset);
271+
272+
byte* rawCurrentBSPData = (byte*)(checkpointLoc + mBSPdata->offset);
273+
std::vector<byte> currentBSPData (rawCurrentBSPData, rawCurrentBSPData + mBSPdata->length);
274+
269275
if (mInjectRequirements->singleCheckpoint)
270276
{
271277
mLoadedBSP1->writeArrayData(currentBSPData.data(), currentBSPData.size());
@@ -274,7 +280,21 @@ class InjectCheckpoint : public IOptionalCheat {
274280
{
275281
bool firstCheckpoint;
276282
mDoubleRevertFlag->readData(&firstCheckpoint);
277-
firstCheckpoint ? mLoadedBSP1->writeArrayData(currentBSPData.data(), currentBSPData.size()) : mLoadedBSP2->writeArrayData(currentBSPData.data(), currentBSPData.size());
283+
PLOG_VERBOSE << "firstCheckpoint? " << firstCheckpoint;
284+
285+
auto loadedBSPToWrite = firstCheckpoint ? mLoadedBSP1 : mLoadedBSP2;
286+
287+
#if HCM_DEBUG
288+
// attempting to debug a H2 crash
289+
uintptr_t loadedBSPLoc;
290+
if (!loadedBSPToWrite->resolve(&loadedBSPLoc)) throw HCMRuntimeException(std::format("Failed to resolve BSP data: {}", MultilevelPointer::GetLastError()));
291+
PLOG_VERBOSE << "loadedBSPLoc: " << std::hex << loadedBSPLoc;
292+
byte currentLoadedBSP;
293+
if (!loadedBSPToWrite->readData(&currentLoadedBSP)) throw HCMRuntimeException(std::format("Failed to read BSP data: {}", MultilevelPointer::GetLastError()));
294+
PLOG_VERBOSE << "currentLoadedBSP " << currentLoadedBSP;
295+
#endif
296+
if (!loadedBSPToWrite->writeArrayData(currentBSPData.data(), currentBSPData.size())) throw HCMRuntimeException(std::format("Failed to write BSP data: {}", MultilevelPointer::GetLastError()));
297+
PLOG_VERBOSE << "successfully set BSP data";
278298
}
279299
}
280300

@@ -295,6 +315,7 @@ class InjectCheckpoint : public IOptionalCheat {
295315
}
296316
catch (HCMRuntimeException ex)
297317
{
318+
PLOG_VERBOSE << "error!" << ex.what();
298319
runtimeExceptions->handleMessage(ex);
299320
}
300321

@@ -338,7 +359,11 @@ class InjectCheckpoint : public IOptionalCheat {
338359
{
339360
mBSPdata = ptr->getData< std::shared_ptr<offsetLengthPair>>("BSPdata", game);
340361
mLoadedBSP1 = ptr->getData< std::shared_ptr<MultilevelPointer>>("loadedBSP1", game);
341-
if (!mInjectRequirements->singleCheckpoint) mLoadedBSP2 = ptr->getData< std::shared_ptr<MultilevelPointer>>("loadedBSP2", game);
362+
if (!mInjectRequirements->singleCheckpoint)
363+
{
364+
mLoadedBSP2 = ptr->getData< std::shared_ptr<MultilevelPointer>>("loadedBSP2", game);
365+
}
366+
342367
}
343368

344369
try

HCMInternal/InternalPointerData.xml

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,7 +1446,7 @@
14461446
<Version Version="1.3272.0.0" Game="Halo2">
14471447
<Module>halo2.dll</Module>
14481448
<Offsets>
1449-
<Offset>0xE6EDA7</Offset>
1449+
<Offset>0xE6FE68</Offset>
14501450
</Offsets>
14511451
</Version>
14521452

@@ -1932,7 +1932,7 @@
19321932
<Module>halo2.dll</Module>
19331933
<Offsets>
19341934
<Offset>0x01651CF0</Offset>
1935-
<Offset>0x0</Offset>
1935+
<Offset>0x400000</Offset>
19361936
</Offsets>
19371937
</Version>
19381938
</VersionedEntry>
@@ -1963,7 +1963,7 @@
19631963
<Module>halo2.dll</Module>
19641964
<Offsets>
19651965
<Offset>0x01651CF0</Offset>
1966-
<Offset>0x400000</Offset>
1966+
<Offset>0x0</Offset>
19671967
</Offsets>
19681968
</Version>
19691969
</VersionedEntry>
@@ -3129,6 +3129,34 @@
31293129
</Version>
31303130
</VersionedEntry>
31313131

3132+
<!-- fall timer invulnerability handled by seperate function for h2-->
3133+
<VersionedEntry Name="fallTimerInvulnerabilityFunction" Type="MultilevelPointer::ModuleOffset">
3134+
<Version Version="1.3272.0.0" Game="Halo2">
3135+
<Module>halo2.dll</Module>
3136+
<Offsets>
3137+
<Offset>0x925C38</Offset>
3138+
</Offsets>
3139+
</Version>
3140+
</VersionedEntry>
3141+
3142+
<VersionedEntry Name="fallTimerInvulnerabilityFunctionContext" Type="MidhookContextInterpreter">
3143+
<Version Version="All" Game="Halo2">
3144+
<Parameters>
3145+
<unitDatum>rsi</unitDatum>
3146+
</Parameters>
3147+
</Version>
3148+
</VersionedEntry>
3149+
3150+
<VersionedEntry Name="fallTimerInvulnerabilityFunctionFlagSetter" Type="MidhookFlagInterpreter">
3151+
<Version Version="All" Game="Halo2">
3152+
<rflag>carry</rflag>
3153+
<value>true</value>
3154+
</Version>
3155+
</VersionedEntry>
3156+
3157+
<!-- #region invulnerability-->
3158+
3159+
31323160
<!--very close to print message stuff-->
31333161
<VersionedEntry Name="boardingText" Type="MultilevelPointer::ModuleOffset">
31343162
<Version Version="1.2448.0.0" Game="Halo2">
@@ -5300,6 +5328,7 @@
53005328
</Version>
53015329

53025330

5331+
<!--this is wrong?-->
53035332
<Version Version="1.3272.0.0" Game="Halo2">
53045333
<Module>halo2.dll</Module>
53055334
<Offsets>

0 commit comments

Comments
 (0)