Skip to content

Commit d329296

Browse files
committed
fix keybinding, better listener notify
1 parent 8f6e6cc commit d329296

File tree

10 files changed

+252
-85
lines changed

10 files changed

+252
-85
lines changed

compile_commands.json

Lines changed: 14 additions & 14 deletions
Large diffs are not rendered by default.

src/red4ext/Hooks/ApplyOverrides.cpp

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,26 +8,52 @@ UserMapping::RawMappingCollection * UserMapping::GetMappingCollection(CName mapN
88
return call(this, mapName);
99
}
1010

11-
bool Manager::Override(
11+
void UserMapping::ClearRuntimeDataOnRawMappings() {
12+
static UniRelocFunc<decltype(&UserMapping::ClearRuntimeDataOnRawMappings)> call(4196866905);
13+
return call(this);
14+
}
15+
16+
// bool Manager::CheckOverrideConflicts(CName contextName, unsigned short key, DynArray<OverridableMapping> & conflicts) const {
17+
// static UniRelocFunc<decltype(&Manager::CheckOverrideConflicts)> call(1600530764);
18+
// return call(this, contextName, key, conflicts);
19+
// }
20+
21+
Manager::OverrideStatus Manager::Override(
1222
// CName contextName,
1323
Overridable overridableUI,
14-
uint16_t inputKey
24+
uint16_t inputKey,
25+
uint32_t callNumber
1526
) {
16-
bool status = false;
17-
for (auto & action : this->contextManager->actions.values) {
18-
for (auto & mapName : action->data.mapNames) {
27+
uint32_t status = NotFound;
28+
// CheckForOverrideConflicts
29+
this->contextManager->userMapping->ClearRuntimeDataOnRawMappings();
30+
for (const auto & action : this->contextManager->actions.values) {
31+
for (const auto & mapName : action->data.mapNames) {
1932
auto mappingCollection = this->contextManager->userMapping->GetMappingCollection(mapName);
33+
// CheckForOverrideConflicts
34+
if (!mappingCollection || mappingCollection->needs_update == 1)
35+
continue;
36+
mappingCollection->needs_update = 1;
37+
// Override
2038
for (auto & mapping : mappingCollection->mappings) {
2139
if (mapping.overridableUI == overridableUI) {
2240
if (mapping.key16 != inputKey) {
2341
mapping.key16 = inputKey;
42+
status |= Replaced;
43+
if (callNumber > 1) {
44+
// game::input::Manager::HandleVarChange
45+
if (this->lastOverrideStaus <= 1)
46+
this->lastOverrideStaus = 1;
47+
this->overrideSet = 1;
48+
}
49+
} else {
50+
status |= NotReplaced;
2451
}
25-
status = true;
2652
}
2753
}
2854
}
2955
}
30-
return status;
56+
return (Manager::OverrideStatus)status;
3157
}
3258

3359
decltype(&ApplyOverrides) ApplyOverrides_Original;
@@ -37,3 +63,33 @@ void ApplyOverrides(Manager * manager) {
3763
ModSettings::ModSettings::AddOverrides(manager);
3864
ApplyOverrides_Original(manager);
3965
}
66+
67+
// REGISTER_HOOK_HASH(bool, 1120015283, Override, ContextManager* cm, CName name, unsigned int ui, unsigned short key) {
68+
// return Override_Original(cm, name, ui, key);
69+
// }
70+
71+
REGISTER_HOOK_HASH(bool, 3298233196, SkipKey, uint32_t key) {
72+
return SkipKey_Original(key) && !((key - (uint32_t)EInputKey::IK_Pad_First) <= 0x13);
73+
}
74+
75+
// #include <RED4ext/Scripting/Natives/Generated/ink/SettingsSelectorControllerKeyBinding.hpp>
76+
77+
// REGISTER_HOOK_HASH(void, 1256790244, ListenForInput, ink::SettingsSelectorControllerKeyBinding * self) {
78+
// ListenForInput_Original(self);
79+
// return;
80+
// }
81+
82+
// REGISTER_HOOK_HASH(void, 1693129953, UnregisterRawInputLambda, ink::SettingsSelectorControllerKeyBinding * self) {
83+
// UnregisterRawInputLambda_Original(self);
84+
// return;
85+
// }
86+
87+
// REGISTER_HOOK_HASH(uint64_t, 3729004759, ListenForInputCallback,
88+
// WeakHandle<ink::SettingsSelectorControllerKeyBinding> self,
89+
// EInputKey key, // EInputKey
90+
// uint64_t type, // type
91+
// float duration
92+
// ) {
93+
// auto og = ListenForInputCallback_Original(self, key, type, duration);
94+
// return og;
95+
// }

src/red4ext/Hooks/ApplyOverrides.hpp

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,19 @@ struct UserMapping {
3434
uint32_t unk28;
3535
uint32_t unk2C;
3636
};
37+
RED4EXT_ASSERT_SIZE(Mapping, 0x30);
3738

3839
struct MappingCollection {
3940
DynArray<Mapping> actions;
4041
};
4142

4243
struct RawMappingCollection {
4344
DynArray<Mapping> mappings;
44-
uint8_t has_update;
45+
uint8_t needs_update;
4546
};
4647

4748
RawMappingCollection * GetMappingCollection(CName);
49+
void ClearRuntimeDataOnRawMappings();
4850

4951
};
5052

@@ -90,8 +92,18 @@ struct ContextManager {
9092
DynArray<void*> unk120;
9193
};
9294

95+
struct OverridableMapping {
96+
97+
};
98+
9399
struct Manager {
94-
bool Override(
100+
enum OverrideStatus {
101+
NotFound = 0,
102+
NotReplaced = 1,
103+
Replaced = 2
104+
};
105+
106+
OverrideStatus Override(
95107
// set in XML with <context name="[contextName]">
96108
// uses separate "Settings*" context names, specifically for key binding in settings
97109
// goes into userSettings group name as "/key_bindings/[contextName]"
@@ -100,18 +112,27 @@ struct Manager {
100112
// needs to exist in [contextName], but not tied to it
101113
// (cannot override keys differently in different contexts)
102114
Overridable overridableUI,
103-
uint16_t inputKey);
115+
uint16_t inputKey,
116+
uint32_t callNumber);
104117

105-
void * __vftable;
106-
void *managerBackend;
107-
ContextManager *contextManager;
108-
uint64_t unk18;
109-
uint64_t contextMutex;
110-
uint32_t unk28;
111-
uint32_t lastOverrideStaus;
112-
DynArray<void*> validators;
113-
DynArray<void*> unk40;
114-
uint64_t listener_id;
118+
// bool CheckOverrideConflicts(
119+
// CName,
120+
// unsigned short,
121+
// DynArray<OverridableMapping> &) const;
122+
123+
124+
void * __vftable;
125+
void *managerBackend;
126+
ContextManager *contextManager;
127+
uint32_t unk18;
128+
uint8_t unk1C;
129+
uint8_t overrideSet;
130+
uint64_t contextMutex;
131+
uint32_t unk28;
132+
int32_t lastOverrideStaus;
133+
DynArray<void*> validators;
134+
DynArray<void*> unk40;
135+
uint64_t listener_id;
115136
};
116137

117138
void ApplyOverrides(Manager * manager);

src/red4ext/IRuntimeVariable.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ IRuntimeVariable::IRuntimeVariable(ScriptProperty* prop) : IRuntimeVariable() {
1616
this->updatePolicy = user::EConfigVarUpdatePolicy::ConfirmationRequired;
1717
this->name = prop->name;
1818
char str[0x100];
19-
std::sprintf(str, "/mods/%s/%s", prop->parent->name.ToString(), this->name.ToString());
19+
// std::sprintf(str, "/mods/%s/%s", prop->parent->name.ToString(), this->name.ToString());
20+
std::sprintf(str, "/mods/%s", prop->parent->name.ToString());
2021
this->groupPath = CNamePool::Add(str);
2122

2223
// prop->ReadProperty("ModSettings.updatePolicy", &updatePolicy, user::EConfigVarUpdatePolicy::ConfirmationRequired);
@@ -31,7 +32,8 @@ IRuntimeVariable::IRuntimeVariable(CName className, CName propertyName, CName di
3132
this->name = propertyName;
3233
this->displayName = displayName;
3334
char str[0x100];
34-
std::sprintf(str, "/mods/%s/%s", className.ToString(), propertyName.ToString());
35+
std::sprintf(str, "/mods/%s", className.ToString());
36+
// std::sprintf(str, "/mods/%s/%s", className.ToString(), propertyName.ToString());
3537
this->groupPath = CNamePool::Add(str);
3638
this->description = description;
3739
this->order = order;

src/red4ext/ModSettings.cpp

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,9 @@ DynArray<Handle<IScriptable>> ModSettings::GetVars(CName modName, CName category
278278
}
279279
}
280280
}
281-
std::sort(variables.begin(), variables.end());
281+
std::sort(variables.begin(), variables.end(), [=](ModVariable*& a, ModVariable*& b) {
282+
return a->GetOrder() < b->GetOrder();
283+
});
282284
for (auto const variable : variables) {
283285
auto configVar = variable->ToConfigVar();
284286
if (configVar) {
@@ -289,6 +291,8 @@ DynArray<Handle<IScriptable>> ModSettings::GetVars(CName modName, CName category
289291
return array;
290292
}
291293

294+
uint32_t applyOverridesCallNumber = 0;
295+
292296
void ModSettings::AddOverrides(Manager* manager) {
293297
gameinputManager = manager;
294298
for (const auto &[modName, mod] : modSettings.mods) {
@@ -299,14 +303,15 @@ void ModSettings::AddOverrides(Manager* manager) {
299303
if (variable->type->GetName() == "EInputKey") {
300304
auto name = variable->name.ToString();
301305
auto key = *(EInputKey*)variable->runtimeVar->GetValuePtr();
302-
if (!manager->Override(name, (uint16_t)key)) {
306+
if (manager->Override(name, (uint16_t)key, applyOverridesCallNumber) == Manager::OverrideStatus::NotFound) {
303307
sdk->logger->WarnF(pluginHandle, "overridableUI \"%s\" not found (%s, %s)", name, modName.ToString(), className.ToString());
304308
}
305309
}
306310
}
307311
}
308312
}
309313
}
314+
applyOverridesCallNumber++;
310315
}
311316

312317
void ModSettings::WriteToFile() {
@@ -360,10 +365,10 @@ void ModSettings::ReadFromFile() {
360365

361366
void ModSettings::AcceptChanges() {
362367
ModSettings::WriteToFile();
363-
modSettings.changeMade = false;
364-
modSettings.NotifyListeners();
365368
if (gameinputManager != nullptr)
366369
ApplyOverrides(gameinputManager);
370+
modSettings.changeMade = false;
371+
modSettings.NotifyListeners();
367372
}
368373

369374
void ModSettings::RestoreDefaults(CName modName) {
@@ -409,6 +414,48 @@ void ModSettings::NotifyListeners() {
409414
}
410415
}
411416

417+
void ModSettings::NotifyListenersChanged(CName aGroupPath, CName aVarName) {
418+
std::shared_lock _(listeners_lock);
419+
for (auto &[id, listener] : this->listeners) {
420+
if (listener) {
421+
auto instance = listener.Lock();
422+
auto func = instance->GetType()->GetFunction("OnVarChanged");
423+
424+
if (func) {
425+
RED4ext::StackArgs_t args;
426+
RED4ext::CName groupPath = aGroupPath;
427+
RED4ext::CName varName = aVarName;
428+
args.emplace_back(RED4ext::CRTTISystem::Get()->GetType("CName"), &groupPath);
429+
args.emplace_back(RED4ext::CRTTISystem::Get()->GetType("CName"), &varName);
430+
RED4ext::ExecuteFunction(instance, func, nullptr, args);
431+
}
432+
} else {
433+
// remove?
434+
}
435+
}
436+
}
437+
438+
void ModSettings::NotifyListenersValidated(CName aGroupPath, CName aVarName) {
439+
std::shared_lock _(listeners_lock);
440+
for (auto &[id, listener] : this->listeners) {
441+
if (listener) {
442+
auto instance = listener.Lock();
443+
auto func = instance->GetType()->GetFunction("OnVarValidated");
444+
445+
if (func) {
446+
RED4ext::StackArgs_t args;
447+
RED4ext::CName groupPath = aGroupPath;
448+
RED4ext::CName varName = aVarName;
449+
args.emplace_back(RED4ext::CRTTISystem::Get()->GetType("CName"), &groupPath);
450+
args.emplace_back(RED4ext::CRTTISystem::Get()->GetType("CName"), &varName);
451+
RED4ext::ExecuteFunction(instance, func, nullptr, args);
452+
}
453+
} else {
454+
// remove?
455+
}
456+
}
457+
}
458+
412459
void ModSettings::RegisterListenerToModifications(const Handle<IScriptable> &listener) {
413460
if (listener) {
414461
std::unique_lock _(modSettings.listeners_lock);

src/red4ext/ModSettings.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ class ModSettings : public IScriptable {
6060

6161

6262
void NotifyListeners();
63+
void NotifyListenersChanged(CName, CName);
64+
void NotifyListenersValidated(CName, CName);
6365

6466
bool changeMade = false;
6567

src/red4ext/RuntimeVariable.hpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,12 +96,18 @@ template <typename T> struct RuntimeVariable : public IRuntimeVariable {
9696

9797
virtual inline void __fastcall UpdateValue(void *value) override {
9898
valueInput = *(T *)value;
99+
99100
auto ms = ModSettings::GetInstance();
100-
ms->changeMade = true;
101-
ms->NotifyListeners();
101+
ms->changeMade |= valueInput != valueValidated;
102+
ms->NotifyListenersChanged(this->groupPath, this->name);
102103
}
103104

104-
virtual inline void __fastcall ApplyChange() override { valueValidated = valueInput; }
105+
virtual inline void __fastcall ApplyChange() override {
106+
valueValidated = valueInput;
107+
108+
auto ms = ModSettings::GetInstance();
109+
ms->NotifyListenersValidated(this->groupPath, this->name);
110+
}
105111

106112
virtual inline void __fastcall RevertChange() override { valueInput = valueValidated; }
107113

src/redscript/mod_settings/ModSettingsMainGameController.reds

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ public class ModStngsMainGameController extends gameuiSettingsMenuGameController
2323
private let m_data: array<SettingsCategory>;
2424
private let m_menusList: array<CName>;
2525
private let m_eventsList: array<CName>;
26-
private let m_settingsListener: ref<ModSettingsVarListener>;
27-
private let m_settingsNotificationListener: ref<ModSettingsNotificationListener>;
26+
// private let m_settingsListener: ref<ModSettingsVarListener>;
27+
// private let m_settingsNotificationListener: ref<ModSettingsNotificationListener>;
2828
private let m_settings: ref<UserSettings>;
2929
private let m_isPreGame: Bool;
3030
private let m_benchmarkNotificationToken: ref<inkGameNotificationToken>;
@@ -142,11 +142,11 @@ public class ModStngsMainGameController extends gameuiSettingsMenuGameController
142142
}
143143
}
144144
145-
public final func OnVarModified(groupPath: CName, varName: CName, varType: ConfigVarType, reason: ConfigChangeReason) -> Void {
145+
public func OnVarChanged(groupPath: CName, varName: CName) -> Void {
146146
let i: Int32;
147147
let item: ref<SettingsSelectorController>;
148148
let size: Int32;
149-
// Log("[VAR] modified groupPath: " + NameToString(groupPath) + " varName: " + NameToString(varName));
149+
// LogChannel(n"DEBUG", "[VAR] modified groupPath: " + NameToString(groupPath) + " varName: " + NameToString(varName));
150150
size = ArraySize(this.m_settingsElements);
151151
this.CheckButtons();
152152
i = 0;
@@ -497,7 +497,14 @@ public class ModStngsMainGameController extends gameuiSettingsMenuGameController
497497
let description: String;
498498
let params: ref<inkTextParams>;
499499
let updatePolicy: ConfigVarUpdatePolicy;
500-
let currentItem: wref<SettingsSelectorController> = evt.GetCurrentTarget().GetController() as SettingsSelectorController;
500+
if !IsDefined(evt) {
501+
return false;
502+
}
503+
let target = evt.GetCurrentTarget();
504+
if !IsDefined(target) {
505+
return false;
506+
}
507+
let currentItem = target.GetController() as SettingsSelectorController;
501508
if IsDefined(currentItem) {
502509
descriptionName = currentItem.GetDescription();
503510
description = GetLocalizedTextByKey(descriptionName);
@@ -575,7 +582,7 @@ public class ModStngsMainGameController extends gameuiSettingsMenuGameController
575582
currentItem.Setup(currentSettingsItem, this.m_isPreGame);
576583
currentItem.RegisterToCallback(n"OnHoverOver", this, n"OnSettingHoverOver");
577584
currentItem.RegisterToCallback(n"OnHoverOut", this, n"OnSettingHoverOut");
578-
currentItem.Refresh();
585+
// currentItem.Refresh();
579586
ArrayPush(this.m_settingsElements, currentItem);
580587
};
581588
};
@@ -591,6 +598,7 @@ public class ModStngsMainGameController extends gameuiSettingsMenuGameController
591598
let settingsSubCategory: SettingsCategory;
592599
ArrayClear(this.m_settingsElements);
593600
inkCompoundRef.RemoveAllChildren(this.m_settingsOptionsList);
601+
inkTextRef.SetText(this.m_descriptionText, "");
594602
inkWidgetRef.SetVisible(this.m_descriptionText, false);
595603
if idx < 0 {
596604
idx = this.m_selectorCtrl.GetToggledIndex();

0 commit comments

Comments
 (0)