合并本地领先源码:旧UI、GM疲劳燃烧、白金徽章孔、宠物修复、支援兵普攻开关
This commit is contained in:
1 parent
f2debaf9bf
commit
70b3c5a6dc
57 files changed
+4256
-30
No files matched your search
@@ -261,6 +261,14 @@ bool CompanionEquipmentProbeEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
// 支援兵普攻开关:启动器在客户端目录放置 90CN_basic_attack.disabled。
|
||||
// 只影响 CompanionBasicAttack 回退程序,12 格技能程序不变。
|
||||
bool CompanionBasicAttackEnabled() {
|
||||
static const bool disabled =
|
||||
CompanionFlagFilePresent(L"90CN_basic_attack.disabled");
|
||||
return !disabled;
|
||||
}
|
||||
|
||||
bool CompanionEquipmentApplyEnabled() {
|
||||
// Production default: the mode1 equipment rows are replayed for every
|
||||
// companion APC. A disable flag exists for a one-restart rollback.
|
||||
@@ -1924,6 +1932,42 @@ bool ApplyDynamicRuntimeKeyPrograms(
|
||||
return false;
|
||||
}
|
||||
|
||||
// 关闭普攻时把 CompanionBasicAttack 的技能码改成空占位码,
|
||||
// 只禁用技能冷却后的普攻回退,不触碰 0..11 的 12 格技能程序。
|
||||
if (!CompanionBasicAttackEnabled()) {
|
||||
void* basicProgram =
|
||||
programs[Contract::kBasicAttackProgramIndex];
|
||||
std::uint8_t* basic =
|
||||
reinterpret_cast<std::uint8_t*>(basicProgram);
|
||||
if (basic) {
|
||||
std::uintptr_t basicBegin =
|
||||
*reinterpret_cast<std::uintptr_t*>(
|
||||
basic +
|
||||
g_native.kRuntimeKeyProgramBytecodeBeginOffset);
|
||||
std::uintptr_t basicEnd =
|
||||
*reinterpret_cast<std::uintptr_t*>(
|
||||
basic +
|
||||
g_native.kRuntimeKeyProgramBytecodeEndOffset);
|
||||
std::uintptr_t basicCapacity =
|
||||
*reinterpret_cast<std::uintptr_t*>(
|
||||
basic +
|
||||
g_native.kRuntimeKeyProgramBytecodeCapacityOffset);
|
||||
if (basicBegin && basicEnd >= basicBegin &&
|
||||
basicCapacity >= basicEnd &&
|
||||
basicEnd - basicBegin >=
|
||||
g_native.kRuntimeKeySkillCodeOffset + 4) {
|
||||
*reinterpret_cast<std::uint32_t*>(
|
||||
basicBegin +
|
||||
g_native.kRuntimeKeySkillCodeOffset) =
|
||||
Contract::kSkillCodeBias +
|
||||
Contract::kPlaceholderSkillId;
|
||||
Log("companion basic attack disabled actor=%p program=%p",
|
||||
actor,
|
||||
basicProgram);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::uint8_t* directBytecode[
|
||||
Contract::kQuickSlotCount] = {};
|
||||
std::size_t directBytecodeSize[
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
// Included inside 90CN.cpp's namespace after its existing patch helpers.
|
||||
// Only the evidenced UI update iterator call-site is patched, never the CRT.
|
||||
uintptr_t g_uiIteratorNativeAdvance = 0;
|
||||
uintptr_t g_uiIteratorAdvanceResume = 0;
|
||||
uintptr_t g_uiIteratorNextBucket = 0;
|
||||
volatile LONG g_uiIteratorInvalidations = 0;
|
||||
int __stdcall CanAdvanceUiUpdateIterator(unsigned int bucket,
|
||||
const uintptr_t* owner, const uintptr_t* iterator)
|
||||
{
|
||||
dnf90::UiIteratorSnapshot s = {};
|
||||
__try {
|
||||
s.owner = reinterpret_cast<uintptr_t>(owner);
|
||||
if (owner && iterator) {
|
||||
s.proxy = owner[0]; s.iteratorProxy = iterator[0];
|
||||
s.begin = owner[1]; s.end = owner[2]; s.current = iterator[2];
|
||||
if (s.proxy && s.iteratorProxy == s.proxy)
|
||||
s.proxyOwner = *reinterpret_cast<const uintptr_t*>(s.proxy);
|
||||
}
|
||||
} __except (EXCEPTION_EXECUTE_HANDLER) { s.proxyOwner = 0; }
|
||||
if (dnf90::CanAdvanceUiIterator(s)) return 1;
|
||||
LONG n = InterlockedIncrement(&g_uiIteratorInvalidations);
|
||||
if (n <= 16) LogLine("ui-update iterator invalidated bucket=%u owner=%08X "
|
||||
"proxy=%08X iter_proxy=%08X begin=%08X end=%08X current=%08X "
|
||||
"action=defer_remaining_bucket_until_next_frame hit=%ld",
|
||||
bucket, s.owner, s.proxy, s.iteratorProxy, s.begin, s.end, s.current, n);
|
||||
return 0;
|
||||
}
|
||||
__declspec(naked) void ProxyUiUpdateIteratorAdvance()
|
||||
{
|
||||
__asm {
|
||||
// Entry is a JMP replacing CALL; result pointer and dummy are on stack.
|
||||
push eax
|
||||
push ecx
|
||||
push edx
|
||||
push ecx
|
||||
push dword ptr [ebp - 14h]
|
||||
push dword ptr [ebp - 1Ch]
|
||||
call CanAdvanceUiUpdateIterator
|
||||
test eax, eax
|
||||
pop edx
|
||||
pop ecx
|
||||
pop eax
|
||||
jz invalidated
|
||||
call dword ptr [g_uiIteratorNativeAdvance]
|
||||
jmp dword ptr [g_uiIteratorAdvanceResume]
|
||||
invalidated:
|
||||
// Native ++ would have consumed two arguments (ret 8). Do not compare
|
||||
// an invalid iterator again; the next bucket constructs a fresh one.
|
||||
add esp, 8
|
||||
jmp dword ptr [g_uiIteratorNextBucket]
|
||||
}
|
||||
}
|
||||
bool InstallUiIteratorAdvanceCompatibility()
|
||||
{
|
||||
const uintptr_t site = g_dnfBase + 0x02BF2732;
|
||||
static const unsigned char kLoopContract[] = {
|
||||
0x8B,0x0F,0x8B,0x11,0x8B,0x42,0x10,0xFF,0xD0,0x6A,0x00,
|
||||
0x8D,0x4D,0xB4,0x51,0x8D,0x4D,0xD4,0xE8,0x19,0x02,0x7F,0xFD,
|
||||
0xE9,0x77,0xFF,0xFF,0xFF,0x8B,0x45,0xE4,0x83,0x45,0xEC,0x14,
|
||||
0x40,0x89,0x45,0xE4,0x3D,0x87,0x04,0x00,0x00,0x0F,0x8C,0x55,0xFF,0xFF,0xFF
|
||||
};
|
||||
static const unsigned char kBeginContract[] = {
|
||||
0x55,0x8B,0xEC,0x8B,0x45,0x08,0x8B,0x51,0x04,0x8B,0x09,
|
||||
0xC7,0x40,0x04,0,0,0,0,0x89,0x50,0x08,0x89,0x08,0x5D,0xC2,0x04,0
|
||||
};
|
||||
static const unsigned char kAdvanceContract[] = {
|
||||
0x55,0x8B,0xEC,0x8B,0x45,0x08,0x8B,0x11,0x56,0xC7,0x00,0,0,0,0
|
||||
};
|
||||
if (!BytesMatch(reinterpret_cast<unsigned char*>(g_dnfBase+0x02BF2720),
|
||||
kLoopContract,sizeof(kLoopContract)) ||
|
||||
!BytesMatch(reinterpret_cast<unsigned char*>(g_dnfBase+0x00A44ED0),
|
||||
kBeginContract,sizeof(kBeginContract)) ||
|
||||
!BytesMatch(reinterpret_cast<unsigned char*>(g_dnfBase+0x003E2950),
|
||||
kAdvanceContract,sizeof(kAdvanceContract))) {
|
||||
LogLine("ui-update iterator compatibility disabled: native signature mismatch");
|
||||
return false;
|
||||
}
|
||||
g_uiIteratorNativeAdvance = g_dnfBase + 0x003E2950;
|
||||
g_uiIteratorAdvanceResume = g_dnfBase + 0x02BF2737;
|
||||
g_uiIteratorNextBucket = g_dnfBase + 0x02BF273C;
|
||||
DWORD oldProtection = 0;
|
||||
if (!VirtualProtect(reinterpret_cast<void*>(site),5,PAGE_EXECUTE_READWRITE,&oldProtection)) {
|
||||
LogLine("ui-update iterator compatibility protection failed error=%lu",GetLastError());
|
||||
return false;
|
||||
}
|
||||
unsigned char jump[5] = {0xE9};
|
||||
*reinterpret_cast<int32_t*>(jump+1) = static_cast<int32_t>(
|
||||
reinterpret_cast<intptr_t>(&ProxyUiUpdateIteratorAdvance)-static_cast<intptr_t>(site+5));
|
||||
memcpy(reinterpret_cast<void*>(site),jump,sizeof(jump));
|
||||
DWORD ignored = 0;
|
||||
VirtualProtect(reinterpret_cast<void*>(site),5,oldProtection,&ignored);
|
||||
FlushInstructionCache(GetCurrentProcess(),reinterpret_cast<void*>(site),5);
|
||||
LogLine("ui-update mutation-safe iterator installed site=%08X next_bucket=%08X",site,g_uiIteratorNextBucket);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,703 @@
|
||||
'���
|
||||
�
|
||||
�
|
||||
�
|
||||
�
|
||||
�
|
||||
�
|
||||
�
|
||||
�
���������������������������������������������������������������������������������������������#%���
�
�
�
�
�
�
�
�
�
��뇦�MNN�MNN�MNN�utr�utr�utr�MNN�MNN�MNN�MNN�뇦�
|
||||
�������������������������������������������������������������������������������������������� � �뇦�MNN�MNN�MNN�MNN�utr�utr�utr�MNN�MNN�MNN�뇦� � � � � � � � � � � � �뇦�
|
||||
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
�
� �뇦� � � � � � � � � � � � ���撞�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������utr�utr�MNN�MNN�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�MNN�MNN�MNN�MNN�MNN�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�MNN�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�MNN�MNN�MNN�MNN�MNN�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�MNN�MNN�utr�utr� �MNN�MNN� �utr� � �utr� � � � � � �MNN� � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � �MNN� � � � � � �utr� � �utr� �MNN�MNN� � �뇦� �MNN�MNN�MNN�MNN�MNN�MNN�MNN�MNN�MNN�MNN�MNN� � �蔽$�遡q�蔽$�蔽$�蔽$�駭)�駭)�駭)�蔽$�駭)�駭)�駭)�駭)�駭)�蔽$�駭)�駭)�蔽$�蔽$�蔽$�蔽$�駭)�蔽$�蔽$�蔽$�蔽$�蔽$�蔽$�駭)�駭)�蔽$�蔽$�蔽$�蔽$�蔽$�駭)�駭)�蔽$�蔽$�蔽$�蔽$�蔽$�蔽$�蔽$�蔽$�蔽$�駭)�蔽$�蔽$�蔽$�蔽$�蔽$�駭)�蔽$�駭)�蔽$�蔽$�蔽$�蔽$�蔽$�蔽$�蔽$�蔽$�蔽$�駭)�蔽$�蔽$�蔽$�蔽$�駭)�駭)�蔽$�駭)�駭)�駭)�駭)�駭)�蔽$�駭)�駭)�駭)�蔽$�蔽$�蔽$�遡q�蔽$� � �MNN�MNN�MNN�MNN�MNN�MNN�MNN�MNN�MNN�MNN�MNN� �뇦� �MNN�utr�MNN�MNN� � � � � � � � � � � �蔽$�駭)�駭)��+��+�棋_�棋_�棋_�棋_��+��s*��s*��s*��s*��x,��+��s*��s*��+��+��+��x,��+��+��s*��x,��x,��+��s*��+��s*��+��x,��x,��+��+��+��+��+��+��s*��s*��+��+��+��+��+��x,��s*��s*��+��x,��+��+��s*��s*��+��+��+��s*��+��x,��x,��s*��+��+��x,��+��+��+��s*��s*��+��x,��s*��s*��s*��s*��+�棋_�棋_�棋_�棋_��+��+�駭)�駭)�蔽$� � � � � � � � � � � �MNN�MNN�utr�MNN� �MNN� �MNN� �蔽$�蔽$�蔽$�蔽$�蔽$�蔽$�蔽$�駭)�駭)��+��+��s*�쮟3�똣4�냍0�냍0�냍0�냍0�똣4�켷G�켷G���������oP1�����냍0�냍0�냍0�냍0�냍0�냍0�냍0�����냍0�냍0�냍0�냍0�����냍0�oP1�냍0�냍0�냍0�냍0�����냍0�냍0�냍0�냍0�����냍0�����냍0�냍0�냍0�냍0�냍0�냍0�냍0�oP1�oP1�����냍0�냍0�냍0�냍0�냍0�냍0�oP1�냍0�����냍0�냍0�냍0�냍0�냍0�냍0�냍0�냍0�냍0�����냍0�냍0�냍0�����냍0�똣4�켷G�켷G�똣4�냍0�냍0�냍0�냍0�똣4�쮟3��s*��+��+�駭)�駭)�蔽$�蔽$�蔽$�蔽$�蔽$�蔽$�蔽$� �MNN� �MNN� � �뇦� �MNN� �蔽$�蔽$�駭)��+��+��+��+��s*�쮟3�쮟3�냍0�oP1�M,�M5(�M5(�M5(�M5(�M5(�M5(�������������M5(�M5(�����M5(�0$�����M5(�M5(�M5(�����M5(�M5(�M5(�M5(�M5(�����M5(�M5(�M5(�M5(�M5(�M5(�����M5(�M5(�M5(�M5(�����0$�M5(�����M5(�M5(�0$�M5(�����M5(�M5(�M5(�����0$�M,�0$�M5(�M5(�M5(�M5(�M5(�����M5(�M5(�M5(�M5(�M5(�M5(�M5(�M5(�M5(�����0$�����������������������������M5(�M5(�M5(�M5(�M5(�M5(�M,�oP1�냍0�쮟3�쮟3��s*��+��+��+��+�駭)�蔽$�蔽$� �MNN� �뇦� �MNN�뇦� �MNN� �蔽$��+��s*�쮟3�냍0�냍0�냍0�냍0�sK�M,�M5(�,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�����,**�,**����� � � �����,**���������������������,**�,**�����������������,**�,**�,**�������������,**�,**����� �,**�,**�,**�,**�,**� �,**����� �,**�����,**� �,**�,**�,**�,**�,**�,**�����,**�,**� �,**�,**�,**�,**�,**����� � � �,**�����,**� �,**�,**�,**�,**�,**�,**�,**�,**�,**�,**�M5(�M,�sK�냍0�냍0�냍0�냍0�쮟3��s*��+�蔽$� �MNN� �뇦�MNN� �MNN�MNN� � �駭)��s*�냍0�YF/�M5(�M5(�YF/�0$�M5(�,**�,**�)�,**�,**�,**� �,**�,**�,**�,**�,**�����,**� �����,**� �,**� � �����,**�,**�,**�����,**�����,**�,**�,**�����,**� � �����,**�,**�,**�,**�����������������,**�,**�,**�,**�,**�,**�����,**�����,**�,**� �,**�����������������������������������������,**�,**� �����,**� �������������������������,**�,**�,**�,**� �,**�,**�,**�)�h딧�h딧�M5(�0$�YF/�M5(�h딧�h딧�냍0��s*�駭)� � �MNN�MNN� � �MNN� � �蔽$��+�냍0�M5(�,**� �,**�,**� �,**� �,**�,**�,**�,**� �,**� �,**��������������������������������������������� �����,**�,**�,**���������,**�,**�,**�,**�����,**�,**�,**�����,**�,**������������� �,**�,**� �,**�����,**�,**�,**�,**�,**����� �,**�,**�,**�,**�,**�,**�,**�����,**�,**�,**�,**�����,**�,**Line truncated
|
||||
�
|
||||
�
|
||||
�
|
||||
�%FO�U「�Q넄�+"�)�)�)�)�)�)�)� �뇦� �MNN�MNN� �뇦� �0�0�2!�2!�2!�2!�2!�0�/�0�0�*�*�*�*�*�*�*�(�*�(�+�+�(�(�(�*�*�*�(�(�(�*�*�,�(�(�(�*�*�(�*�(�*�*�*�*�*�*�*�(�*�(�+�+�(�(�(�*�*�*�(�(�(�*�*�,�(�(�(�*�*�(�*�(�*�*�*�*�*�*�*�(�*�(�+�+�(�(�(�+�[윸�2`m�
|
||||
�
|
||||
)Z�Q�b�b�Q�
|
||||
)Z�
|
||||
�2`m�[〕�+�)�*�*�*�*�*� �뇦� �MNN�MNN� �뇦� �/�0�2!�2!�2!�0�0�0�0�0�0�/�,�,�*�*�*�*�(�*�(�*�+�(�*�*�*�*�(�(�(�(�(�*�*�+�+�(�*�*�(�*�(�*�*�*�*�*�*�*�(�*�(�*�+�(�*�*�*�*�(�(�(�(�(�*�*�+�+�(�*�*�(�*�(�*�*�*�*�*�*�*�(�*�(�*�+�(�*�)�P꼺�5dr��O�V�.`� | ||||