Skip to content

Instantly share code, notes, and snippets.

@Yiin
Created December 17, 2016 18:16
Show Gist options
  • Save Yiin/4fe4f51b380e2fb184a56a11f85347fe to your computer and use it in GitHub Desktop.
Save Yiin/4fe4f51b380e2fb184a56a11f85347fe to your computer and use it in GitHub Desktop.
stock bool:Callback_Get(callback:name, ret[E_CALLBACK_DATA], expect[] = "", bool:remote = false)
{
P:2("Callback_Get called: %s", name);
Inline_Reset(ret);
if (!(callback_tag:0 < name[0] < callback_tag:128))
{
P:3("Callback_Get: Found resolved callback.");
// Resolved inline.
return bool:memcpy(_:ret[E_CALLBACK_DATA:0], name[0], 0, _:E_CALLBACK_DATA * 4, _:E_CALLBACK_DATA);
}
else if (name[0] == callback_tag:'\03')
{
// This prefix is ALWAYS for publics not inlines.
return bool:(ret[E_CALLBACK_DATA_POINTER] = (remote ? GetRemoteFunction(name[1], expect) : GetLocalFunction(name[1], expect)));
}
else if (remote)
{
// "remote" functions must always be done this way.
return bool:(ret[E_CALLBACK_DATA_POINTER] = GetRemoteFunction(name, expect));
}
new
pos = strfind(name, "\02"),
frm = GetCurrentFramePreviousFrame(),
prf = GetFramePreviousFrame(frm);
if (pos == -1)
{
new
cur = YSI_g_sPrevInlineFunc,
parent = GetFrameFunction(prf),
res;
pos = strlen(name),
frm = GetFrameReturn(frm);
// Find the function by name.
while (cur)
{
#emit PUSH.S pos
#emit PUSH.C 0
#emit PUSH.S name
#emit PUSH.S cur
#emit PUSH.C 16
#emit SYSREQ.C strcmp
#emit STACK 20
#emit STOR.S.pri res
if (res == 0 && AMX_Read(cur + pos * 4) == '\02')
{
if (parent <= AMX_Read(cur + pos * 4 + 1 * 4) <= frm)
{
// Rewrite the value of "name" for the subsequent code.
#emit LOAD.S.pri cur
#emit STOR.S.pri name
break;
}
}
static const
gsSearch[] = "\02";
#emit PUSH.C 0
#emit PUSH.C 0
#emit PUSH.C gsSearch
#emit PUSH.S cur
#emit PUSH.C 16
#emit SYSREQ.C strfind
#emit STACK 20
#emit LOAD.S.alt cur
#emit IDXADDR
#emit ADD.C 16
#emit LOAD.I
#emit STOR.S.pri cur
}
if (!cur)
{
// Try publics...
return bool:(ret[E_CALLBACK_DATA_POINTER] = GetLocalFunction(name, expect));
}
}
static
spec[2];
Inline_EncodeFormatString(expect, spec),
ret[E_CALLBACK_DATA_FORMAT] = spec,
// Load this inline function's data in to our closure (and allocate memory).
ret[E_CALLBACK_DATA_POINTER] = Function:name[pos + 1];
new
to = name[pos + 2],
local = to >> 8, // Sign-extending!
params = to & 0xFF,
stack = params + local + 3,
Alloc:a = malloc(stack); // Allocate closure space.
// printf("local: %d, params: %d, stack: %d", local, params, stack);
if (a)
{
// Get the address of the data.
#emit CONST.alt YSI_gMallocMemory
#emit LOAD.S.pri a
#emit IDXADDR
#emit STOR.S.pri frm
// Get the stack size in bytes.
stack <<= 2,
ret[E_CALLBACK_DATA_ALLOC] = ResolvedAlloc:frm,
ret[E_CALLBACK_DATA_OFFSET] = stack,
// Copy the stack over. First get the frame of the function that used
// an inline function, thus calling us indirectly.
prf -= local << 2,
// Adjust to the bottom of that stack, at least the bottom of the parts
// we need (there may be more locals declared later that we don't need).
// Copy "stack" bytes from "prf" to "frm".
rawMemcpy(frm, prf, stack),
// Save the "return" address for the inline to our fake stack.
mset(a, local + 1, name[pos + 3]),
// Save the parameter count (may be mangled by y_hooks).
mset(a, local + 2, params << 2);
P:2("Callback_Get end");
return true;
}
return false;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment