Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- enum E_HOOK_NAME_REPLACEMENT_DATA
- {
- E_HOOK_NAME_REPLACEMENT_SHORT[4],
- E_HOOK_NAME_REPLACEMENT_LONG[11],
- E_HOOK_NAME_REPLACEMENT_MIN,
- E_HOOK_NAME_REPLACEMENT_LEN
- }
- static stock
- YSI_g_sReplacements[][E_HOOK_NAME_REPLACEMENT_DATA] =
- {
- {"CP", "Checkpoint", 2, 10},
- {"Dyn", "Dynamic", 3, 7},
- {"TD", "TextDraw", 2, 8},
- {"Upd", "Update", 3, 6},
- {"Obj", "Object", 3, 6},
- {"Cmd", "Command", 3, 6},
- };
- stock Hooks_MakeLongName(name[64])
- {
- new
- len,
- i = 0,
- pos = -1;
- while (i != sizeof (YSI_g_sReplacements))
- {
- if ((pos = strfind(name, YSI_g_sReplacements[i][E_HOOK_NAME_REPLACEMENT_SHORT], false, pos + 1)) != -1)
- {
- // Try this same string again. We may have found a different word.
- if ('a' <= name[(len = pos + YSI_g_sReplacements[i][E_HOOK_NAME_REPLACEMENT_MIN])] <= 'z') continue;
- else
- {
- // Found a complete word according to CamelCase rules.
- strdel(name, pos, len),
- strins(name, YSI_g_sReplacements[i][E_HOOK_NAME_REPLACEMENT_LONG], pos),
- pos = -1;
- }
- else continue;
- }
- ++i;
- }
- // It is possible for the expansions to become TOO big.
- return Hooks_MakeShortName(name);
- }
- Test:Hooks_MakeLongName0()
- {
- new
- name[64];
- name = "OnUpd";
- ASSERT(Hooks_MakeLongName(name) == 8);
- ASSERT(!strcmp(name, "OnUpdate"));
- name = "OnUpdD";
- ASSERT(Hooks_MakeLongName(name) == 9);
- ASSERT(!strcmp(name, "OnUpdateD"));
- name = "OnUpda";
- ASSERT(Hooks_MakeLongName(name) == 6);
- ASSERT(!strcmp(name, "OnUpda"));
- }
- Test:Hooks_MakeLongName1()
- {
- new
- name[64];
- name = "CP";
- ASSERT(Hooks_MakeLongName(name) == 10);
- ASSERT(!strcmp(name, "Checkpoint"));
- name = "TD";
- ASSERT(Hooks_MakeLongName(name) == 8);
- ASSERT(!strcmp(name, "TextDraw"));
- name = "Upd";
- ASSERT(Hooks_MakeLongName(name) == 6);
- ASSERT(!strcmp(name, "Update"));
- name = "Dyn";
- ASSERT(Hooks_MakeLongName(name) == 7);
- ASSERT(!strcmp(name, "Dynamic"));
- name = "Obj";
- ASSERT(Hooks_MakeLongName(name) == 6);
- ASSERT(!strcmp(name, "Object"));
- name = "Cmd";
- ASSERT(Hooks_MakeLongName(name) == 7);
- ASSERT(!strcmp(name, "Command"));
- }
- Test:Hooks_MakeLongName2()
- {
- new
- name[64];
- name = "OnUpdTDCP";
- ASSERT(Hooks_MakeLongName(name) == 26);
- ASSERT(!strcmp(name, "OnUpdateTextDrawCheckpoint"));
- name = "OnUpdTDObjCmd";
- ASSERT(Hooks_MakeLongName(name) == 29);
- ASSERT(!strcmp(name, "OnUpdateTextDrawObjectCommand"));
- name = "OnUpdTDCPObjCmd";
- ASSERT(Hooks_MakeLongName(name) == 31);
- ASSERT(!strcmp(name, "OnUpdateTextDrawCPObjectCommand"));
- }
- stock Hooks_MakeShortName0(name[64])
- {
- // Easy one.
- new
- len = strlen(name);
- if (len >= 32)
- {
- new
- pos,
- i = 0;
- do
- {
- if ((pos = strfind(name, YSI_g_sReplacements[i][E_HOOK_NAME_REPLACEMENT_LONG])) != -1)
- {
- strdel(name, pos, pos + YSI_g_sReplacements[i][E_HOOK_NAME_REPLACEMENT_LEN]),
- strins(name, YSI_g_sReplacements[i][E_HOOK_NAME_REPLACEMENT_SHORT], pos);
- }
- }
- while ((len = strlen(name)) >= 32 && ++i != sizeof (YSI_g_sReplacements));
- }
- return len;
- }
- Test:Hooks_MakeShortName1()
- {
- new
- name[64];
- name = "OnPlayerEnterRaceCP";
- ASSERT(Hooks_MakeShortName(name) == 19);
- ASSERT(!strcmp(name, "OnPlayerEnterRaceCP"));
- name = "OnPlayerEnterRaceCheckpoint";
- ASSERT(Hooks_MakeShortName(name) == 27);
- ASSERT(!strcmp(name, "OnPlayerEnterRaceCheckpoint"));
- name = "OnPlayerEnterDynamicRaceCheckpoint";
- ASSERT(Hooks_MakeShortName(name) == 25);
- ASSERT(!strcmp(name, "OnPlayerEnterDynamicRaceCP"));
- name = "AAAAAAAAAAAAAAAAAAAUpdateTextDraw";
- Hooks_MakeShortName(name);
- ASSERT(!strcmp(name, "AAAAAAAAAAAAAAAAAAAUpdateTD"));
- name = "BBBBBAAAAAAAAAAAAAAAAAAAUpdateTextDraw";
- Hooks_MakeShortName(name);
- ASSERT(!strcmp(name, "BBBBBAAAAAAAAAAAAAAAAAAAUpdTD"));
- }
- Test:Hooks_MakeShortName2()
- {
- new
- name[64];
- name = "AAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCC";
- ASSERT(Hooks_MakeShortName(name) == 43);
- ASSERT(!strcmp(name, "AAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCC"));
- name = "AAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCommandCCCC";
- ASSERT(Hooks_MakeShortName(name) == 45);
- ASSERT(!strcmp(name, "AAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCmdCCCC"));
- }
- // Get rid of the "@yH_" prefix and "@" suffix and change "CP" into "Checkpoint"
- // etc.
- #define Hooks_MakeBaseName(%0) ( \
- Hooks_IsolateName(name) , \
- Hooks_MakeLongName(name) )
- static stock Hooks_Collate(name[64], &idx)
- {
- // For this function, note that:
- //
- // hook OnPlayerConnect(playerid)
- //
- // Compiles as:
- //
- // public @yH_OnPlayerConnect@XXX(playerid)
- //
- // Where "XXX" is some unique number (the exact value is irrelevant, it just
- // means that multiple hooks of the same function have different names).
- static
- sBase[64],
- sHooks[128];
- // Isolate the common prefix part:
- //
- // @yH_OnPlayerConnect@042
- //
- // Becomes:
- //
- // @yH_OnPlayerConnect@
- //
- // The numbers at the end are irrelevant, now we can just search for hooks
- // of this exact callback.
- name[strfind(name, "@", false, 4) + 1] = '\0',
- // The above now becomes:
- //
- // OnPlayerConnect
- //
- // This also handles cases such as:
- //
- // @yH_OnPlayerEnterRaceCheckpoint@162
- //
- // Being invalid (too long), so instead converts the shortened:
- //
- // @yH_OnPlayerEnterRaceCP@162
- //
- // To:
- //
- // OnPlayerEnterRaceCheckpoint
- //
- // Thus expanding common name length reductions.
- sBase = name,
- Hooks_MakeBaseName(sBase);
- new
- // See if the original function exists.
- original = funcidx(sBase),
- // See if a fixes.inc hook exists.
- fixes = Hooks_GetFixesFunc(sBase),
- // Get all the hooks of this type. They are stored alphabetically.
- hookCount = Hooks_GetAllHooks(name, sHooks, idx);
- // We now have:
- //
- // 1) All the hooks of this function.
- // 2) The original function if it exists.
- // 3) The FIXES_ ALS chained function if fixes.inc exists.
- //
- // This took huge chunks of complex code in the old version. Now not so
- // much! I don't know if this code is faster (I suspect it is), but it is
- // absolutely simpler!
- // Get the AMX header entry from the public function index.
- original = (original == -1) ? (0) : (AMX_GetEntryFromPublicIndex(original)),
- // Get the AMX header entry from the public function index.
- fixes = (fixes == -1) ? (0) : (AMX_GetEntryFromPublicIndex(fixes ));
- new
- stub = Hooks_GenerateStub(fixes ? Hooks_GetFixesChain(fixes) : AMX_GetEntryPointer(original), sHooks, hookCount);
- return Hooks_MakePublicPointer(original, fixes, stub, name, sBase);
- }
- static stock Hooks_GetFixesChain(stub)
- {
- // Get the address of the next function from the FIXES_ ALS state stub.
- new
- ctx[DisasmContext];
- DisasmInit(ctx, stub);
- switch (DisasmNextInsn(ctx))
- {
- case OP_LOAD_PRI:
- {
- if (DisasmNextInsn(ctx) == OP_SWITCH && DisasmNextInsn(ctx) == OP_CASETBL)
- {
- // Get the number of items in the casetable.
- if (DisasmGetNumOperands(ctx) == 3) // 2 means no used hook.
- {
- // Got a hook to return. Find it.
- new
- h0 = DisasmGetOperand(ctx, 3),
- h1 = DisasmGetOperand(ctx, 5),
- h2 = DisasmGetOperand(ctx, 7);
- if (h1 == h2) return h0; // Most likely.
- else if (h0 == h2) return h1;
- else if (h0 == h1) return h2;
- }
- }
- }
- case OP_JUMP:
- {
- // Already replaced once (shouldn't happen, but may if two different
- // hooks use two different short versions of a callback).
- return DisasmGetOperand(ctx, 0);
- }
- }
- return 0;
- }
- static stock Hooks_MakePublicPointer(original, fixes, func, const hname[], const name[])
- {
- // We need to create an AMX header entry for "name", e.g. point
- // "OnPlayerConnect" at the correct function.
- if (fixes)
- {
- // Here, "fixes" points to the second item in the ALS chain. "original"
- // points to the actual callback in "fixes.inc", which if it exists
- // means that we don't need to rewrite anything in the header, just
- // rewrite the states stub.
- // There is a remote chance that the stub has already been rewritten
- // once, in which case just replace that old jump with the new one.
- // Other code will need to account for that case to correct call the
- // remainder of the chain.
- return Hooks_RedirectFixes(fixes, func);
- }
- else if (original)
- {
- // No "fixes.inc", but this callback already exists. In that case, just
- // replace the pointer address.
- AMX_SetHeaderPOinter(original, func);
- }
- }
- static stock Hooks_GetAllHooks(const name[], hooks[128], &idx)
- {
- // Start from the very start - repeats the first item.
- new
- count,
- i = idx - 1;
- while ((i = AMX_GetPublicEntry(i, hooks[count], name)))
- {
- Hooks_InvalidateName(hooks[count]),
- idx = i;
- if (++count == sizeof (hooks))
- {
- P:W("Hooks_GetAllHooks: Potential overflow.");
- break;
- }
- }
- return count;
- }
- static stock Hooks_GetFixesFunc(const name[64])
- {
- static
- fn[64];
- return
- fn = "FIXES_",
- strcat(fn, name),
- Hooks_MakeShortName(fn),
- funcidx(fn);
- }
- // Main loop
- static
- name[64];
- new
- idx;
- // Get the next hook type.
- while ((idx = AMX_GetPublicNamePrefix(idx, name, _A<@yH_>)))
- {
- // Collect all the hooks of this function, and rewrite the call code.
- Hooks_Collate(name, idx);
- }
Advertisement
Add Comment
Please, Sign In to add comment