일반적으로 플러그인을 디컴파일하게되면 온전한 상태로 컴파일이 되지않는다.
온전히 컴파일 하기위해서 참고할만한 자료를 적어놓겠다.
1. Return 타입 수정
Plugin_Continue = 0, /**< Continue with the original action */
Plugin_Changed = 1, /**< Inputs or outputs have been overridden with new values */
Plugin_Handled = 3, /**< Handle the action at the end (don't call it) */
Plugin_Stop = 4, /**< Immediately stop the hook chain and handle the original */
Plugin_Continue - Let the hook continue as normal.
Plugin_Handled - Stop the engine from processing the hook.
Plugin_Changed - Feed the modified parameters back into the engine.
Plugin_Stop - Stop repeating timers.
INVALID_HANDLE is just another way to express '0' in terms of a handle. It is what the name implies, the handle is invalid, and can't really be used for anything.
그러나 주의점이 있다.
해당 함수에서 return 0;이 붙어있는경우 위를 보면 플러그인 컨티뉴를 써야할거 같지만 아니다.
써야하는것은 함수의 타입에 따라 다르다.
해당 함수에 Action이 붙어있다면 리턴을 써주고
없다면 return 0; 자체를 지워주면 되겠다.
2. SDKHook 타입 수정
SDKHook도 변환해야 해줄것이 생긴다. 바로 SDK훅의 타입이다.
참고로 SDKHookType:2 는 SDKHook_OnTakeDamage 이다. 나머지는 모르겠다.
SDKHook(client, SDKHookType:5, OnPostThink);
SDKHook(client, SDKHookType:20, OnPostThinkPost);
SDKHook(client, SDKHookType:11, OnTraceAttack);
SDKHook(client, SDKHookType:32, OnWeaponEquipPost);
SDKHook(client, SDKHookType:2, OnTakeDamage);
SDKHook(client, SDKHookType:33, OnWeaponSwitchPost);
는 아래와 같다
SDKHook(client, SDKHook_PostThink, OnPostThink);
SDKHook(client, SDKHook_PostThinkPost, OnPostThinkPost);
SDKHook(client, SDKHook_TraceAttack, OnTraceAttack);
SDKHook(client, SDKHook_WeaponEquipPost, OnWeaponEquipPost);
SDKHook(client, SDKHook_OnTakeDamage, OnTakeDamage);
SDKHook(client, SDKHook_WeaponSwitchPost, OnWeaponSwitchPost);
[변환 전]
SDKUnhook(client, SDKHookType:2, OnTakeDamageHook);
[변환 후]
SDKUnhook(clinet, SDKHook_OnTakeDamage, OnTakeDamageHook);
3. HookEvent 수정
HookEvent("round_start", EventStart, EventHookMode:1);
HookEvent("round_end", EventEnd, EventHookMode:1);
이런식으로 나오는데 훅 이벤트의 발동 순서 설정에는
발동전, 발동즉시, 발동후 이렇게 나뉜다
그러나 구글링 해본결과 EventHookMode의 값이 뭐가 뭔지 찾아도 없다.
그리고 발동 순서도 차이가 크게 안난다. 전, 즉시, 후 이므로 그냥 지워버린다.
이런식으로
HookEvent("round_start", EventStart);
HookEvent("round_end", EventEnd);
+ 최근에 구글링으로 다시 찾아봤다.
EventHookMode:1 = EventHookMode_Post
EventHookMode:2 = EventHookMode_PostNoCopy
라는데 실제 디컴파일 직접 해본결과(확정)
EventHookMode:1는 그냥 없애도 된다.
4. 타이머 수정
타이머의 시간과 실행함수는 그대로인 반면 3번째 인자값부터는 값이 바뀌므로 바꿔줘야한다.
세번째 인자 : 대상
네번째 인자 : 타이머의 속성
[대상의 경우]
- any:0은 대상이 없다는것을 뜻하므로 _로 치환해야한다.
[속성의 경우]
- 3 은 추정상 TIMER_FLAG_NO_MAPCHANGE인것같다
Ex ) CreateTimer(5.0, settimer, any:0, 3);
> CreateTimer(5.0, settimer, _, TIMER_FLAG_NO_MAPCHANGE);
5. 의미없는 변수
디컴파일을 하게되면 new var1, new var 2, ... new var 999
머 이런식으로 new var이 생기는데 해당 변수가 쓰이는 부분이 있으면 사용하면되고
사용하는 부분이 없다면 과감히 지워주면 되겠다.
아래 코드를 통해 실제 디컴파일 코드를 변환하는 과정을 보여주겠다.
[디컴파일 함수]
public OnGameFrame()
{
new i = 1;
while (i < MaxClients)
{
if (IsClientConnectedIngameAlive(i))
{
new entity = GetClientAimTarget(i, false);
new var1;
if (IsValidEntity(entity) && IsValidEdict(entity))
{
new String:classname[32];
GetEdictClassname(entity, classname, 32);
new var2;
if (StrContains(classname, "prop_physics", false) != -1 && check[entity])
{
PrintCenterText(i, "바리게이트 체력 - %d HP 남음", health[entity]);
}
}
}
i++;
}
return 0;
}
[직접 변환 후]
public OnGameFrame()
{
for(new i = 1; i <= MaxClients; i++)
{
if (IsClientConnectedIngameAlive(i))
{
new entity = GetClientAimTarget(i, false);
if (IsValidEntity(entity) && IsValidEdict(entity))
{
new String:classname[32];
GetEdictClassname(entity, classname, 32);
if (StrContains(classname, "prop_physics", false) != -1 && check[entity])
{
PrintCenterText(i, "바리게이트 체력 - %d HP 남음", health[entity]);
}
}
}
}
}
해당 함수는 Action이 들어있지 않기 때문에 return 0; 은 과감히 지워버렸으며
디컴파일 특성상 생기는 의미없는 변수는 전부 지웠다.
그리고 while을 for로 고쳤다.
5. 조건문
if 후 else if를 쓴 부분은 아래와 같이 표시된다.
if (500 < health[client] < 750)
{
SetEntityRenderColor(client, 255, 200, 200, 255);
}
else
{
if (350 < health[client] < 500)
{
SetEntityRenderColor(client, 255, 150, 150, 255);
}
if (100 < health[client] < 350)
{
SetEntityRenderColor(client, 255, 100, 100, 255);
}
if (0 < health[client] < 100)
{
SetEntityRenderColor(client, 255, 10, 10, 255);
}
}
물론 실제 우리는 else if를 이런식으로 쓰지 않는다 아래와 같이 고쳐주자.
if (500 < health[client] < 750)
{
SetEntityRenderColor(client, 255, 200, 200, 255);
}
else if (350 < health[client] < 500)
{
SetEntityRenderColor(client, 255, 150, 150, 255);
}
else if (100 < health[client] < 350)
{
SetEntityRenderColor(client, 255, 100, 100, 255);
}
else if (0 < health[client] < 100)
{
SetEntityRenderColor(client, 255, 10, 10, 255);
}
6. 엔티티
순수한 의미의 엔티티가 뿐만아니라 엔티티 설정 관련 부분도 바꿔주어야한다.
6-1. SetEntData
SetEntData(activator, g_offsCollisionGroup, any:2, 4, true);
SetEntData(Client, g_offsCollisionGroup, any:5, 4, true);
세번째 인자값을 보자. any:숫자의 형태를 하고있다. 실제 코드에선 저렇게 작성하지 않는다.
any:만 제거하면 될것같다.
요로코롬 ↓
SetEntData(activator, g_offsCollisionGroup, 2, 4, true);
SetEntData(Client, g_offsCollisionGroup, 5, 4, true);
7. 메뉴
7-1. CreateMenu
CreateMenu(WeaponmodMenuHandler, MenuAction:28);
CreateMenu(WeaponmodMenuHandler);
7-2. AddMenuItem
AddMenuItem(WeaponmodMenu, "galil", "galil", 0);
AddMenuItem(WeaponmodMenu, "galil", "galil");
8. Enum
만약 Enum값이 실수값이라면 포기하는게 좋다. 그 이유는 아래를 보면 알것이다.
[원본]
enum WeaponAttributes
{
Float:RecoilType1,
Float:RecoilType2,
Float:FireRate,
AutoMode,
Float:GenericDamage,
Float:HeadDamage,
Float:TorsoDamage,
Float:LimbDamage,
Float:RagdollForce,
BurstMode,
InfiniteAmmo,
QuickSwitch,
Float:ModeFireRate,
Float:StandSpread,
Float:MoveSpread,
Float:CrouchSpread,
Float:MiscSpread
};
new GalilInfo[WeaponAttributes];
GalilInfo[RecoilType1] = 1.0;
GalilInfo[RecoilType2] = -5.0;
GalilInfo[FireRate] = -1.0;
GalilInfo[AutoMode] = -5;
GalilInfo[GenericDamage] = -5.0;
GalilInfo[HeadDamage] = 1.0;
GalilInfo[TorsoDamage] = 1.0;
GalilInfo[LimbDamage] = 1.0;
GalilInfo[RagdollForce] = 5.0;
GalilInfo[BurstMode] = -5;
GalilInfo[InfiniteAmmo] = 0;
GalilInfo[QuickSwitch] = 0;
GalilInfo[ModeFireRate] = -5.0;
GalilInfo[StandSpread] = -1.0;
GalilInfo[MoveSpread] = -1.0;
GalilInfo[CrouchSpread] = -1.0;
GalilInfo[MiscSpread] = -1.0;
SetTrieArray(WeaponTypeTrie, "galil", GalilInfo[0], 17);
[디컴파일]
new GalilInfo[17];
GalilInfo[0] = 1065353216;
GalilInfo[1] = -1063256064;
GalilInfo[2] = -1082130432;
GalilInfo[3] = -5;
GalilInfo[4] = -1063256064;
GalilInfo[5] = 1065353216;
GalilInfo[6] = 1065353216;
GalilInfo[7] = 1065353216;
GalilInfo[8] = 1084227584;
GalilInfo[9] = -5;
GalilInfo[10] = 0;
GalilInfo[11] = 0;
GalilInfo[12] = -1063256064;
GalilInfo[13] = -1082130432;
GalilInfo[14] = -1082130432;
GalilInfo[15] = -1082130432;
GalilInfo[16] = -1082130432;
SetTrieArray(WeaponTypeTrie, "galil", GalilInfo, 17, true);
그렇다 가망이없다. 변수선언인 Enum자체를 찾아볼수없게되며,
정수값 소수값 의미가 없어질정도로 변형되어 원래값은 찾아볼수없게된다.
그리고 Enum 변수들은 직접적인 형태로 변형되어 원형으로의 복구는 불가능하다.
9. 프롭 타입(PropType)
new Float:minbounds[3] = 0.0;
GetEntPropVector(0, PropType:1, "m_WorldMins", minbounds, 0);
new Float:maxbounds[3] = 0.0;
GetEntPropVector(0, PropType:1, "m_WorldMaxs", maxbounds, 0);
SetEntPropVector(bombzone, PropType:0, "m_vecMins", minbounds, 0);
SetEntPropVector(bombzone, PropType:0, "m_vecMaxs", maxbounds, 0);
SetEntProp(bombzone, PropType:0, "m_nSolidType", any:2, 4, 0);
이런식으로 PropType:0이나 PropType:1이 뜨는데
0이 PropSend이고, 1이 PropData이다.
그러나 모든 오프셋을 일일이 알긴 힘든법.
아래와 같이 프롭타입을 자동인식해주는 코드를 이용하자.
decl String:buffer[64];
new PropType:proptype = PropType:-1;
GetCmdArg(1, buffer, sizeof(buffer));
if (!strcmp(buffer, "send"))
proptype = Prop_Send;
else if (!strcmp(buffer, "data"))
proptype = Prop_Data;
아니면 https://forums.alliedmods.net/showthread.php?t=117723 참조
10. 메뉴 수정(Menu)
MenuAction:16 = MenuAction_End
DisplayMenu(메뉴핸들, 대상, 0); = 여기서 0은 MENU_TIME_FOREVER이다. 이외 숫자는 지속시간을 따로설정한것.
CreateMenu(menuhandler, MenuAction:28); 여기서 MenuAction:28은 없애버리자.
AddMenuItem(hMenu, "", szReadData, 1); 맨마지막 1은 ITEMDRAW_DISABLED 이다.
'소스모드 > TIP' 카테고리의 다른 글
[TIP] 신문법 훅 이벤트 변경점 (0) | 2023.03.16 |
---|---|
[TIP] 소스모드 개발시 참고하면 좋은 사이트 (0) | 2021.12.17 |
[TIP] 소스모드 문법 혼용으로 인한 발생워링 고치는법 (0) | 2021.04.01 |
[TIP] NPC의 관계 설정 (0) | 2021.03.25 |
[TIP] 소스모드 디컴파일 사이트 (0) | 2021.03.19 |