SRL Archive - General Botting Help

Forwarding Overloaded Functions


Obscurity

2015-01-30 16:11:02

As the title says. I've not yet needed to do this, but say I have:
  //~ Etc...

function obsCanThreshold():boolean;
begin
result:=obsGetAdrenaline()>=50;
end;

//~ Etc...

function obsGetAdrenaline():single;
var
adrenalineTexture:glTextureArray;
begin
if (adrenalineTexture:=glGetTextures(79179).extractColourID(14724672,4)).isEmpty() then
exit;
result:=floor(adrenalineTexture[0].width()/103*100);
end;

//~ Etc

Obviously for this example, I'd have to forward obsGetAdrenaline():
  //~ Etc...

function obsGetAdrenaline():single;forward;
function obsCanThreshold():boolean;
begin
result:=obsGetAdrenaline()>=50;
end;

//~ Etc...

function obsGetAdrenaline():single;
var
adrenalineTexture:glTextureArray;
begin
if (adrenalineTexture:=glGetTextures(79179).extractColourID(14724672,4)).isEmpty() then
exit;
result:=floor(adrenalineTexture[0].width()/103*100);
end;

//~ Etc

Now, what if I had overloaded functions? I would think:
  //~ Etc...

function obsGetAdrenaline():single;forward;
function obsCanThreshold():boolean;
begin
result:=obsGetAdrenaline()>=50;
end;

function obsGetAdrenaline(adrenalineTexture:glTextureArray):single;forward;
function obsCanThreshold(adrenalineTexture:glTextureArray):boolean;overload;
begin
result:=obsGetAdrenaline(adrenalineTexture)>=50;
end;

//~ Etc...

function obsGetAdrenaline():single;
var
adrenalineTexture:glTextureArray;
begin
if (adrenalineTexture:=glGetTextures(79179).extractColourID(14724672,4)).isEmpty() then
exit;
result:=floor(adrenalineTexture[0].width()/103*100);
end;

function obsGetAdrenaline(adrenalineTexture:glTextureArray):single;overload;
begin
if (adrenalineTexture:=adrenalineTexture.extractID(79179).extractColourID(14724672,4)).isEmpty() then
exit;
result:=floor(adrenalineTexture[0].width()/103*100);
end;

//~ Etc...

However, I get an error with the second forward:
Error: Forwarded declaration doesn't match at line 2395
Compiling failed.

So I figured I had to change the second forward to:
  function obsGetAdrenaline(adrenalineTexture:glTextureArray):single;overload;forward;

But this only results in an error with the actual obsGetAdrenaline(adrenalineTexture:glTextureArray):
Error: Cannot overload function at line 3616
Compiling failed.

Ideas? :P.

slacky

2015-01-30 16:51:00

A workaround that should work I think:

function Foo(): Int32; overload; forward; //a single forward that also specifies that it's an overloaded-method.

procedure Bar();
begin WriteLn(Foo()); end;

procedure Bar(x:Int32); overload;
begin WriteLn(Foo(x)); end;

function Foo(): Int32;
begin Result := 0; end;

function Foo(x:Int32): Int32; overload;
begin Result := 1; end;

begin
Bar();
Bar(1);
end.

Best thing would be if you could avoid forwarding all together. This can be done by using a "object oriented" structure. If that's not an option, you can use a default parameter.

The fist one would be something like (object oriented):

type
TDummy = type Pointer;
var
x:TDummy;

procedure TDummy.Bar();
begin WriteLn(Self.Foo()); end;

procedure TDummy.Bar(x:Int32); overload;
begin WriteLn(Self.Foo(x)); end; //referance to `Self` is required for forward calls

function TDummy.Foo(): Int32;
begin Result := 0; end;

function TDummy.Foo(x:Int32): Int32; overload;
begin Result := x; end;

begin
x.Bar();
x.Bar(1);
end.

The second alternative (default parameters) and forward:

function Foo(x:TIntegerArray=[]): Int32; forward;

procedure Bar();
begin WriteLn(Foo()); end;

procedure Bar(x:TIntegerArray); overload;
begin WriteLn(Foo(x)); end;

function Foo(x:TIntegerArray=[]): Int32;
begin
if Pointer(x)=nil then Result := 1
else Result := 2;
end;

begin
Bar();
Bar([1]);
end.

Brandon

2015-01-30 17:58:17

My failed attempt:


function CallProc(s: string; params: TVariantArray): Variant;
begin
Result := VariantInvoke('obsGetAdrenaline', params);
end;

function obsCanThreshold(): Boolean;
begin
Result := CallProc('obsGetAdrenaline', []) >= 50;
end;

function obsCanThreshold(I: Integer): Boolean; overload;
begin
Result := CallProc('obsGetAdrenaline', TVariantArray([I])) >= 50;
end;


function obsGetAdrenaline(): Integer;
begin
writeln('called');
Result := 0;
end;

function obsGetAdrenaline(I: Integer): Single; overload;
begin
writeln('called');
Result := 90;
end;

begin
writeln(obsCanThreshold(50));
end.


Works but NOT for overloads.. It's probably because of name mangling which is usually how overloaded functions are implemented.. If you know how the function names are mangled, you can call that specific one with CallProc. This way, you would not need forwarding at all.. However, VariantInvoke is not able to do a proper look up on the function in question..

Sad.. Add another thing to the list of bugs or broken features. You also cannot take the address of the overloaded function so I can't figure out a way to get its underlying name..


EDIT: You can get the address of it by passing it as a parameter to a function.. That means you can print the underlying name of the function by trying to print it's address.. Thus, you can finally use CallProc to call overloaded functions given the underlying name..

SOLUTION:


function CallProc(s: string; params: TVariantArray): Variant;
begin
Result := VariantInvoke(s, params);
end;

function obsCanThreshold(): Boolean;
begin
Result := CallProc('obsGetAdrenaline[0]', []) >= 50;
end;

function obsCanThreshold(I: Integer): Boolean; overload;
begin
Result := CallProc('obsGetAdrenaline[1]', TVariantArray([I])) >= 50;
end;


function obsGetAdrenaline(): Single;
begin
writeln('called - 0');
Result := 0;
end;

function obsGetAdrenaline(I: Integer): Single; overload;
begin
writeln('called - 1 with parameter: ', I);
Result := 90;
end;


procedure printAddr(func: function(): Single);
begin
writeln(@func);
end;

begin
writeln(obsCanThreshold());
writeln(obsCanThreshold(100));
end.


called - 0
False
called - 1 with parameter: 100
True

It turns out Lape manges the names of overloaded functions with an array index.. This is in the order they are declared in. The first declaration of obsGetAdrenaline is index 0, the second is index 1, and so on and so forth.. Knowing this, you can use CallProc to call the correct overload via index as shown above..

Obscurity

2015-01-30 18:18:22

Cheers, guys! I was hoping to not have to do something like yours, however, Brandon. :P. With so many functions, that could get painful! Haha.

Brandon

2015-01-30 18:27:12

From: Obscurity
Cheers, guys! I was hoping to not have to do something like yours, however, Brandon. :P. With so many functions, that could get painful! Haha.



What I'd do is create a file called Utility.. Put all your hacks and dirty code required for Lape to function properly.. Such as the CallProc function..

Whenever you want to call an overload, just do CallProc('OverLoad[0]', []), CallProc('Overload[1], [..]), etc.. CallProc is really all you need for calling overloads without lots of work I guess..

The include uses a couple hacks as well.. One is: OffsetOf - PtrUInt(@(CStruct(nil + 1)^.Var)) - 1; by Dgby; to determine the offset of a variable from the address of its struct lol..

slacky

2015-01-30 18:45:25

From: Brandon
EDIT: You can get the address of it by passing it as a parameter to a function..
…
It turns out Lape manges the names of overloaded functions with an array index.. This is in the order they are declared in. The first declaration of obsGetAdrenaline is index 0, the second is index 1, and so on and so forth.. Knowing this, you can use CallProc to call the correct overload via index as shown above..

You can get the addr of a overload method by indexing, or by assigning (to a variable that matches the methods def, like you did by passing it to a function).

{$f-}
procedure foo(); begin end;
procedure foo(i:Int32); overload; begin end;

begin
WriteLn(foo[0]);
WriteLn(foo[1]);
end;

var x: procedure(i:Int32);
begin
WriteLn(x := foo);
end.
>>> procedure() ("foo[0]"::0x6130)
>>> procedure(Int32) ("foo[1]"::0x617C)
>>> procedure(Int32) ("foo[1]"::0x617C)


Getting the correct overload by JUST casting it to a "procedure(i:Int32)" doesn't work in lape, pretty sure that's a bug:

{$f-}
procedure foo(); begin end;
procedure foo(i:Int32); overload; begin end;

type
TI32Proc = procedure(i:Int32);
begin
WriteLn(TI32Proc(foo));
end.
>>> procedure(Int32) (0xFFFFFFFF)

PS: I also updated my prev post with a better solution than that quick and dirty hack.