読者です 読者をやめる 読者になる 読者になる

めいくりぷとのブログ

技術的なことやゲームのことやら・・・

AVA D3D hook

AVA SDK + WDDM Hook


まあWDDM hookなんてしないでも、普通にIDirect3DDevice9のfuction table書き換えでもいいのと、それのほうがBeginSceneとEndSceneに処理突っ込めれてやりやすいんだけど、書き直すのが面倒だから、また次やる気出たときに作り直します。


AVA SDKはUE3 SDK Generatorを用いて各自用意してください。
AVA SDKからクラスやら取得するのが割りと重いから(処理的に)、PFND3DDDI_PRESENTに入れるのはちょっとアレかな...?


余談ですが、オブジェクトの座標取得の基本的な流れとしては、プレイヤーを描画する時は他より比較的に頂点数が多い(?)ので、それを基に3D座標を取得して2D(スクリーン座標)に変換する~って感じなので、OpenGLの場合はglVertex3f/v関数でVertexCount(頂点数)が一定数以上の時に座標を格納して、変換するだけで簡単に取れるのですが、D3Dは自分が知っている限りでは、少し手間のかかる方法しか知りません...


DrawIndexedPrimitive関数にオブジェクトの種類によって渡される引数(PrimitiveCount?)があり、その値から判断するという方法もありますが、Loggerなどを用いてログを調べないといけないのと、ゲームによって違うというのが面倒です...
何か良い方法ありませんかね..? もう少し調べてみます。

FLOAT APIENTRY GetDistance(__in FLOAT *LocationA, __in FLOAT *LocationB)
{
	FLOAT DistanceX = LocationA[0] - LocationB[0];
	FLOAT DistanceY = LocationA[1] - LocationB[1];
	FLOAT DistanceZ = LocationA[2] - LocationB[2];

	return (FLOAT)sqrt((DistanceX * DistanceX) + (DistanceY * DistanceY) + (DistanceZ * DistanceZ));
}

HRESULT APIENTRY DrawBox(IDirect3DDevice9 *pDevice, FLOAT x, FLOAT y, FLOAT Width, FLOAT Height, D3DCOLOR Color)
{
	D3DRECT Rect = { x, y, x + Width, y + Height };

	return pDevice->Clear(1, &Rect, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, Color, 0, 0);
}

HRESULT APIENTRY DrawLine(ID3DXLine *pLine, FLOAT x, FLOAT y, FLOAT x2, FLOAT y2, D3DCOLOR Color)
{
	D3DXVECTOR2 vLine[2];
	vLine[0].x = x;
	vLine[0].y = y;
	vLine[1].x = x2;
	vLine[1].y = y2;

	if (pLine)
	{
		pLine->SetWidth(1);
		pLine->SetAntialias(FALSE);
		pLine->SetGLLines(FALSE);
		pLine->Begin();
		pLine->Draw(vLine, 2, Color);
		pLine->End();
	}

	return S_OK;
}

HRESULT APIENTRY DDICreateQuery(__in HANDLE hDevice, __in_opt D3DDDIARG_CREATEQUERY *pCreateQuery)
{
	if (pCreateQuery && pCreateQuery->QueryType == D3DDDIQUERYTYPE_OCCLUSION)
		pCreateQuery->QueryType = D3DDDIQUERYTYPE_EVENT;

	return _DDICreateQuery(hDevice, pCreateQuery);
}

HRESULT APIENTRY DDIDrawIndexedPrimitive(__in HANDLE hDevice, __in_opt const D3DDDIARG_DRAWINDEXEDPRIMITIVE *pDPI)
{
	CGraphicsContext *pGraphicsContext = CGraphicsContext::GetInstance();
	IDirect3DDevice9 *pDevice = Direct3D9::GetInstance()->GetDevice();

	// get entity 2D position
	for (int i = 0; i < MaxEnts; i++)
	{
		D3DXMATRIX mProjection, mViewProj, mWorldProj;
		D3DXVECTOR3 vScreen2D, vWorld3D;

		vWorld3D.x = Ents[i].Origin[0];
		vWorld3D.y = Ents[i].Origin[1];
		vWorld3D.z = Ents[i].Origin[2];

		if (pDevice)
		{
			pDevice->GetViewport(&Viewport);
			pDevice->GetVertexShaderConstantF(0, mProjection, 4);
			pDevice->GetVertexShaderConstantF(231, mViewProj, 4);

			D3DXMatrixIdentity(&mWorldProj);
			D3DXVec3Project(&vScreen2D, &vWorld3D, &Viewport, &mProjection, &mViewProj, &mWorldProj);

			if (vScreen2D.z < 1.0f && mProjection._44 > 1.0f)
			{
				Ents[i].ESP.x = vScreen2D.x;
				Ents[i].ESP.y = vScreen2D.y;
			}
		}
	}

	// draw esp
	for (int i = 0; i < MaxEnts; i++)
	{
		FLOAT x = Ents[i].ESP.x;
		FLOAT y = Ents[i].ESP.y;
		UCHAR r, g, b, a;

		if (Ents[i].IsVisible == TRUE)
		{
			r = 20; g = 255; b = 20; a = 200;
		}
		else
		{
			r = 255; g = 255; b = 20; a = 200;
		}

		// draw esp box on target
		if (pGraphicsContext->IsDrawEspBoxActivated())
		{
			DrawBox(pDevice, Ents[i].ESP.x, Ents[i].ESP.y, 5, 5, D3DCOLOR_RGBA(r, g, b, a));
		}

		// draw esp line on foot to target
		if (pGraphicsContext->IsDrawEspLineActivated())
		{
			ID3DXLine *pLine = NULL;

			D3DXCreateLine(pDevice, &pLine);
			if (pLine)
			{
				DrawLine(pLine, x, y, Viewport.Width / 2.0f, Viewport.Height, D3DCOLOR_RGBA(r, g, b, a));
			}
		}
	}

	// reset
	MaxEnts = 0;

	return _DDIDrawIndexedPrimitive(hDevice, pDPI);
}

HRESULT APIENTRY DDIPresent(__in HANDLE hDevice, __in_opt const D3DDDIARG_PRESENT *pPresent)
{
	CGameManager *pGameManager = CGameManager::GetInstance();
	UGameEngine* pGameEngine;
	AavaPlayerController* pAvaPC;
	AavaPawn* pAvaPawn;

	pGameEngine = pGameManager->GetEngine();

	if (pGameEngine && pGameEngine->GamePlayers.Data)
	{
		pAvaPC = (AavaPlayerController*)pGameEngine->GamePlayers.Data[0]->Actor;

		if (pAvaPC && pAvaPC->IsA(AavaPlayerController::StaticClass()))
		{
			pAvaPawn = (AavaPawn*)pAvaPC->Pawn;

			// Validate the pawn and the WorldInfo pointer required for pawn looping
			if (pAvaPawn && pAvaPawn->IsA(AavaPawn::StaticClass()) && pAvaPawn->WorldInfo)
			{
				if (MaxEnts = 0)
				{
					// Loop through the pawns
					for (APawn* pTarget = pAvaPawn->WorldInfo->PawnList; pTarget; pTarget = pTarget->NextPawn)
					{
						// Validate the current target
						if (pTarget != pAvaPawn && pTarget->IsA(AavaPawn::StaticClass()) 
							&& pGameManager->IsValidTarget(pTarget))
						{
							// player hp
							Ents[MaxEnts].Health = (INT)pTarget->Health;

							// player position
							Ents[MaxEnts].Origin[0] = pTarget->Location.X;
							Ents[MaxEnts].Origin[1] = pTarget->Location.Y;
							Ents[MaxEnts].Origin[2] = pTarget->Location.Z;

							// Next Entity
							MaxEnts++;
						}
					}
				}
			}
		}
	}

	return _DDIPresnet(hDevice, pPresent);
}