Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【建议】如意宝箱 #30

Open
bigsinger opened this issue Sep 12, 2024 · 10 comments
Open

【建议】如意宝箱 #30

bigsinger opened this issue Sep 12, 2024 · 10 comments

Comments

@bigsinger
Copy link

bigsinger commented Sep 12, 2024

箱子目前是随机效果,可以实现一个如意宝箱的效果,就是想来啥来啥。这个目前在单机版已经实现了,可以用,代码如下:

// 所有捡箱子的效果:金钱
void SetBoxAllMoney() {
	const LPVOID MethodTableAddr = (LPVOID)0x004833C4;
	const size_t MethodTableCount = 0x12;
	const SIZE_T MethodTableSize = MethodTableCount * sizeof(DWORD);
	const DWORD JumpToAddr = 0x00482463;	// 捡到的是金钱的跳转地址

	// 修改代码保护属性
	DWORD dwOldProtect = 0;
	if (VirtualProtect(MethodTableAddr, MethodTableSize, PAGE_EXECUTE_READWRITE, &dwOldProtect)  {

		DWORD* p = (DWORD*)MethodTableAddr;
		for (size_t i = 0; i < MethodTableCount; i++) {
			*(p + i) = JumpToAddr;
		}

		// 恢复代码保护属性
		if (!VirtualProtect(MethodTableAddr, MethodTableSize, dwOldProtect, &dwOldProtect)) {
			OutputDebugString("Failed 2!");
		}
	} else {
		OutputDebugString("Failed 1!");
	}
}

其他捡箱子效果可以参考这个来设计。这样当缺钱的时候,就按下按键让所有捡箱子效果是金钱,当需要升级部队时按下某个按键让捡箱子效果都是升级,以此类推……

另:这个功能在联网对战中会卡死,不知道啥原因,有知道的吗?

@AdjWang
Copy link
Owner

AdjWang commented Sep 12, 2024

联网模式改 text 段会有两个问题,一个是被反作弊扫描到;另一个是产生平行世界,除非把所有人的同时都改了。

@bigsinger
Copy link
Author

联网模式改 text 段会有两个问题,一个是被反作弊扫描到;另一个是产生平行世界,除非把所有人的同时都改了。

如果在内存中找到存放箱子列表的地址呢?然后修改箱子数据的属性,是不是就可以实现?

参考这个文章:红色警戒2-尤里复仇之自动全图捡箱子,里面提到「所有箱子坐标」,应该能找到箱子的列表。
image

@bigsinger
Copy link
Author

从下面的代码可以看出,esi应该是箱子对象相关,动态调试时给拦截下来看一下:

00481DE0  |.  FF2495 C43348>jmp     dword ptr [edx*4+4833C4]
00481DE7  |>  0FBF46 26     movsx   eax, word ptr [esi+26]
00481DEB  |.  0FBF4E 24     movsx   ecx, word ptr [esi+24]
00481DEF  |.  50            push    eax
00481DF0  |.  51            push    ecx
00481DF1  |.  68 80D08100   push    0081D080                         ;  crate at %d,%d contains poison gas\n
00481DF6  |.  E8 E54AF8FF   call    004068E0

如下地址不确定是否跟箱子数据有关,动态调试的时候看下:

00481A28  |.  8B0D 843DA800 mov     ecx, dword ptr [A83D84]

00481A3F  |.  8B15 38B2A800 mov     edx, dword ptr [A8B238]

00481A95  |.  A1 48E78900   mov     eax, dword ptr [89E748]

00481D5B  |.  8A83 C0EC8900 mov     al, byte ptr [ebx+89ECC0]

@AdjWang
Copy link
Owner

AdjWang commented Sep 13, 2024

联机有数据一致性要求,本地数据修改必须直接或者间接发送给所有玩家,保持多人游戏状态同步。自动捡箱子功能会把对单位的操作也发给别的玩家,没有不一致问题。对箱子内容的修改无法发送给别的玩家,会导致多客户端数据不一致,俗称平行世界……
就拿你之前提的几个建议来举例,改 GUI,放大小地图不需要主动同步,配置进攻策略,工程师自动抢修,自动维修,巨炮有顺序攻击,巨炮自动转向都需要主动同步,有些同步可能调了接口引擎就自动发了数据,接口上面看不到但是网络数据上有。

@bigsinger
Copy link
Author

bigsinger commented Oct 25, 2024

倒也不是不可行,要看修改的时机。

猜想:

可以在触碰箱子的时候,修改箱子的处理效果函数,例如修改为升级效果,之后的逻辑不动,则发送数据到服务端的逻辑仍然是通的。
也即修改的操作在发送数据之前应该是可行的。

@AdjWang

@bigsinger
Copy link
Author

看下这块代码,动态调试下看看时机和箱子属性。

00481A00  /$  55            push    ebp
00481A01  |.  8BEC          mov     ebp, esp
00481A03  |.  83E4 F8       and     esp, FFFFFFF8
00481A06  |.  81EC 7C010000 sub     esp, 17C
00481A0C  |.  53            push    ebx
00481A0D  |.  56            push    esi
00481A0E  |.  57            push    edi
00481A0F  |.  8B7D 08       mov     edi, dword ptr [ebp+8]
00481A12  |.  85FF          test    edi, edi
00481A14  |.  8BF1          mov     esi, ecx
00481A16  |.  0F84 6D190000 je      00483389
00481A1C  |.  8B46 44       mov     eax, dword ptr [esi+44]
00481A1F  |.  83F8 FF       cmp     eax, -1
00481A22  |.  0F84 61190000 je      00483389
00481A28  |.  8B0D 843DA800 mov     ecx, dword ptr [A83D84]
00481A2E  |.  8B1481        mov     edx, dword ptr [ecx+eax*4]
00481A31  |.  8A9A AA020000 mov     bl, byte ptr [edx+2AA]
00481A37  |.  84DB          test    bl, bl
00481A39  |.  0F84 4A190000 je      00483389
00481A3F  |.  8B15 38B2A800 mov     edx, dword ptr [A8B238]
00481A45  |.  C64424 13 00  mov     byte ptr [esp+13], 0
00481A4A  |.  85D2          test    edx, edx
00481A4C  |.  C74424 14 000>mov     dword ptr [esp+14], 0
00481A54  |.  74 17         je      short 00481A6D
00481A56  |.  8B97 1C020000 mov     edx, dword ptr [edi+21C]
00481A5C  |.  8B52 34       mov     edx, dword ptr [edx+34]
00481A5F  |.  8A9A A6010000 mov     bl, byte ptr [edx+1A6]
00481A65  |.  84DB          test    bl, bl
00481A67  |.  0F85 1C190000 jnz     00483389
00481A6D  |>  8B0481        mov     eax, dword ptr [ecx+eax*4]
00481A70  |.  8A88 AB020000 mov     cl, byte ptr [eax+2AB]
00481A76  |.  84C9          test    cl, cl
00481A78  |.  74 4E         je      short 00481AC8
00481A7A  |.  8B47 34       mov     eax, dword ptr [edi+34]
00481A7D  |.  85C0          test    eax, eax
00481A7F  |.  74 3A         je      short 00481ABB
00481A81  |.  0FBF4E 26     movsx   ecx, word ptr [esi+26]
00481A85  |.  0FBF56 24     movsx   edx, word ptr [esi+24]
00481A89  |.  51            push    ecx
00481A8A  |.  52            push    edx
00481A8B  |.  68 A4D08100   push    0081D0A4                         ;  springing trigger on crate at %d,%d\n
00481A90  |.  E8 4B4EF8FF   call    004068E0

@AdjWang
Copy link
Owner

AdjWang commented Oct 30, 2024

从箱子生成到单位拾取箱子过程中,只有对单位的移动指令会发送给服务器,其他的都是计算出来的。发送到服务器的内容有限,事件类型定义在 https://github.com/Phobos-developers/YRpp/blob/phobos-dev/GeneralDefinitions.h#L1370
具体到这个例子,假如两个人在线上,双方的游戏配置共同的随机数种子,时钟就是游戏从开始时候累计的帧数,"在第1000帧随机生成升级箱子"这个事件是计算出来的,因为随机数和帧数计算结果一致,所以不发送网络数据双方也是同步的。
只有玩家输入的操作,比如建造、移动单位、攻击这些无法通过随机数和时钟计算得到的事件,才会发到服务器上。

@bigsinger
Copy link
Author

@AdjWang 那就比较困惑了:

  1. 不会出现同步问题吗?这个机制相当于是玩家各自捡自己客户端随机生成的箱子,如何做到数据同步的?
  2. 如果某个客户端进行欺骗操作:生成一个箱子呢?
  3. 单位拾取箱子是服务器来计算的?根据玩家的单位距离箱子的远近和碰撞来计算是谁拾取了箱子?然后分发数据给所有客户端?

@bigsinger
Copy link
Author

bigsinger commented Oct 30, 2024

我大概理解下:
所有玩家拥有所有地图和所有单位的所有数据,各自客户端各自计算自己的,因为数据和算法一致,所以结果也是一致的,不会出现同步问题。

有点类似区块链的思想,每个客户端都在计算,都有全量数据。

如果按照这个思路的话,似乎如意宝箱就很难实现了,但是似乎强制修改数据有实现的可能,修改后锁死并同步出去,有机会可以将所有玩家的数据给刷回去。

@AdjWang
Copy link
Owner

AdjWang commented Oct 30, 2024

我大概理解下: 所有玩家拥有所有地图和所有单位的所有数据,各自客户端各自计算自己的,因为数据和算法一致,所以结果也是一致的,不会出现同步问题。

有点类似区块链的思想,每个客户端都在计算,都有全量数据。

如果按照这个思路的话,似乎如意宝箱就很难实现了,但是似乎强制修改数据有实现的可能,修改后锁死并同步出去,有机会可以将所有玩家的数据给刷回去。

是这样的。

  1. 只要随机数种子一样,调用随机数函数的结果序列就是一样的。
  2. 单个客户端自行改变箱子数据会导致多客户端数据不一致。
  3. 单位拾取箱子是客户端计算的。客户端先生成箱子,之后玩家在客户端发起单位移动事件(MEGAMISSION),移动事件发送服务器并广播到所有客户端,然后所有客户端的单位接收移动事件,前往箱子位置拾取箱子。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants