SRL Archive - Reflection Development

canReach


Iamadam

2011-04-27 20:52:08

program canReacher;
{$DEFINE SMART}
{$i SRL\SRL.scar}
{$i Reflection\Reflection.simba}

function getGroundBlocks: array of array of integer;

var rsObject : Integer;
xCount, yCount, xMax, yMax, i, markTime1 : Integer;
blockArray : array of array of integer;
begin
rsObject := SmartGetFieldArrayObject(0, 'uha.a', getPlaneIndex);
xMax := SmartGetFieldArraySize(rsObject, 'o', 1);
yMax := SmartGetFieldArraySize(rsObject, 'o', 2);
SetLength(blockArray, xMax - 4);
for i := low(blockArray) to high(blockArray) do
begin
setLength(blockArray[i], yMax - 4);
end;

//~330 ms to do this... (fyi, this would be unnesessary in java...)
markTime1 := getSystemTime;
for xCount := 0 to xMax - 5 do
begin
for yCount := 0 to yMax - 5 do
begin
blockArray[xCount][yCount] := smartGetFieldArray2DInt(rsObject, 'o', xCount, yCount);
end;
end;
smartFreeObject(rsObject);
result := blockArray;
end;

function dijkstraDistance(startX, startY, destX, destY: Integer; searchAllPaths : boolean) : Integer;
var via, cost, blocks: array of array of Integer;
tileQueueX, tileQueueY : array of Integer;
curX, curY, head, tail, pathLength, i1, newCost, i, j : Integer;

begin
SetLength(via, 104);
for i := low(via) to high(via) do
setLength(via[i], 104);

SetLength(cost, 104);
for i := low(cost) to high(cost) do
setLength(cost[i], 104);
SetLength(tileQueueX, 4000);
SetLength(tileQueueY, 4000);

for i := 0 to 103 do
for j := 0 to 103 do
begin
via[i][j] := 0;
cost[i][j] := 99999999;
end;

curX := startX;
curY := startY;
via[startX][startY] := 99;
cost[startX][startY] := 0;
head := 0;
tail := 0;
tileQueueX[head] := startX;
tileQueueY[(head)] := startY;
inc(head);
blocks := getGroundBlocks;
pathLength := 4000;
i1 := 0;

while (tail <> head) do
begin
curX := tileQueueX[tail];
curY := tileQueueY[tail];
if ((curX = destX) and (curY = destY)) then
i1 := 1;

if(not searchAllPaths) then
if (((curX = destX) and (curY = destY + 1)) or ((curX = destX) and (curY = destY - 1)) or ((curX = destX + 1) and (curY = destY)) or ((curX = destX - 1) and (curY = destY))) then
begin
i1 := 1;
break;
end;

tail := (tail + 1) mod pathLength;
newCost := cost[curX][curY] + 1;

if ((curY > 0) and (via[curX][(curY - 1)] = 0) and ((blocks[(curX + 1)][curY] and $1280102) = 0)) then
begin
tileQueueX[head] := curX;
tileQueueY[head] := (curY - 1);
head := (head + 1) mod pathLength;
via[curX][(curY - 1)] := 1;
cost[curX][(curY - 1)] := newCost;
end;
if ((curX > 0) and (via[(curX - 1)][curY] = 0) and ((blocks[curX][(curY + 1)] and $1280108) = 0)) then
begin
tileQueueX[head] := (curX - 1);
tileQueueY[head] := curY;
head := (head + 1) mod pathLength;
via[(curX - 1)][curY] := 2;
cost[(curX - 1)][curY] := newCost;
end;

if ((curY < 103) and (via[curX][(curY + 1)] = 0) and ((blocks[(curX + 1)][(curY + 2)] and $1280120) = 0))then
begin
tileQueueX[head] := curX;
tileQueueY[head] := (curY + 1);
head := (head + 1) mod pathLength;
via[curX][(curY + 1)] := 4;
cost[curX][(curY + 1)] := newCost;
end;

if ((curX < 103) and (via[(curX + 1)][curY] = 0) and ((blocks[(curX + 2)][(curY + 1)] and $1280180) = 0))then
begin
tileQueueX[head] := (curX + 1);
tileQueueY[head] := curY;
head := (head + 1) mod pathLength;
via[(curX + 1)][curY] := 8;
cost[(curX + 1)][curY] := newCost;
end;

if ((curX > 0) and (curY > 0) and (via[(curX - 1)][(curY - 1)] = 0)
and ((blocks[curX][curY] and $128010E) = 0) and ((blocks[curX][(curY + 1)] and $1280108) = 0)
and ((blocks[(curX + 1)][curY] and $1280102) = 0)) then
begin
tileQueueX[head] := (curX - 1);
tileQueueY[head] := (curY - 1);
head := (head + 1) mod pathLength;
via[(curX - 1)][(curY - 1)] := 3;
cost[(curX - 1)][(curY - 1)] := newCost;
end;

if ((curX > 0) and (curY < 103) and (via[(curX - 1)][(curY + 1)] = 0)
and ((blocks[curX][(curY + 2)] and $1280138) = 0) and ((blocks[curX][(curY + 1)]
and $1280108) = 0) and ((blocks[(curX + 1)][(curY + 2)] and $1280120) = 0)) then
begin
tileQueueX[head] := (curX - 1);
tileQueueY[head] := (curY + 1);
head := (head + 1) mod pathLength;
via[(curX - 1)][(curY + 1)] := 6;
cost[(curX - 1)][(curY + 1)] := newCost;
end;

if ((curX < 103) and (curY > 0) and (via[(curX + 1)][(curY - 1)] = 0)
and ((blocks[(curX + 2)][curY] and $1280183) = 0)
and ((blocks[(curX + 2)][(curY + 1)] and $1280180) = 0)
and ((blocks[(curX + 1)][curY] and $1280102) = 0)) then
begin
tileQueueX[head] := (curX + 1);
tileQueueY[head] := (curY - 1);
head := (head + 1) mod pathLength;
via[(curX + 1)][(curY - 1)] := 9;
cost[(curX + 1)][(curY - 1)] := newCost;
end;

if ((curX < 103) and (curY < 103) and (via[(curX + 1)][(curY + 1)] = 0)
and ((blocks[(curX + 2)][(curY + 2)] and $12801E0) = 0)
and ((blocks[(curX + 2)][(curY + 1)] and $1280180) = 0)
and ((blocks[(curX + 1)][(curY + 2)] and $1280120) = 0)) then
begin
tileQueueX[head] := (curX + 1);
tileQueueY[head] := (curY + 1);
head := (head + 1) mod pathLength;
via[(curX + 1)][(curY + 1)] := 12;
cost[(curX + 1)][(curY + 1)] := newCost;
end;
end;

if(i1 <> 0) then
result := cost[curX][curY]
else
result := -1;
end;

function GetMyLocalPos: TTile;
var
me: Integer;
begin
me := SmartGetFieldObject(0, hook_static_MyPlayer);
Result.x := SmartGetFieldInt(me, hook_animable_PixelX) / 512;
Result.y := SmartGetFieldInt(me, hook_animable_PixelY) / 512;
SmartFreeObject(me);
end;

function canReach(dest : TTile) : boolean;
var pathDist, baseX, baseY : Integer;
localPos : TTile;
begin
writeln('canReach called');
baseX := SmartGetFieldInt(0, hook_static_BaseX);
baseY := SmartGetFieldInt(0, hook_static_BaseY);
localPos := getMyLocalPos;

pathDist := dijkstraDistance(localPos.x, localPos.y, dest.x - baseX, dest.y - baseY, false);
writeln(toStr(pathDist));
if(pathDist <> -1) then
result := true;

end;

procedure setup;
begin
clearDebug;
smart_server := 1;
smart_signed := true;
smart_members := true;
setupSRL;
setupReflection;
end;

begin
setup;
repeat
if(canReach(Tile(3162,3434))) then
writeln('Can reach!');
wait(1000);
until(false);
end.

Obviously a VERY useful function for us. I have ported the one we used in ARGA to pascal, and found the necessary hooks. It works brilliantly, BUT is incredibly slow because of pascal script.

we need to:
1. Port the DijkstraDistance function to a plugin
2. Add the requierd hooks to the hooks file. I will write a search and give it to pyro (unless you want to write your own??).

This is great to see if there is a closed door in the way (or any other impassable obstacle).

Anyone willing to get on board with this? Other wise I'll do it myself. :)

HarryJames

2011-04-27 20:58:53

It looks good, I think that it should be included but would it be quicker as a plugin?

pyroryan

2011-04-27 21:16:06

From: Iamadam

Obviously a VERY useful function for us. I have ported the one we used in ARGA to pascal, and found the necessary hooks. It works brilliantly, BUT is incredibly slow because of pascal script.

we need to:
1. Port the DijkstraDistance function to a plugin
2. Add the requierd hooks to the hooks file. I will write a search and give it to pyro (unless you want to write your own??).


I have had the basic collision flags stuff hooked so no worries on that end. I skimmed it and I didn't see anything besides uha.a and eq.o. Correct me if I'm wrong :)

Iamadam

2011-04-27 21:17:55

That's right :) Only need those two. Could you add them to the hooks file?

pyroryan

2011-04-27 21:19:18

From: Iamadam
That's right :) Only need those two. Could you add them to the hooks file?


Do you have any preferences for names?

Btw, get on MSN more often :D

Iamadam

2011-04-27 22:06:53

Names:
uha.a –> groundDataArray
eq.o –> groundBlocks

Here's an updated version of it. Have written the plugin (attached).
Very fast and works well. How do we add this to reflection lib? (pyroryan you have commit access, could you? :) )

{$LOADLIB LibPath.dll}
{$DEFINE SMART}
{$i SRL\SRL.scar}
{$i Reflection\Reflection.simba}

*******************************************************************************
function getGroundBlocks: array of array of integer;
By: Iamadam
Description: Returns a 2D array of all ground blockss. Each bit of the result
represents a blocked location on a tile.
*******************************************************************************}
function getGroundBlocks: array of array of integer;
var rsObject : Integer;
xCount, yCount, xMax, yMax, i, markTime1 : Integer;
blockArray : array of array of integer;
begin
rsObject := SmartGetFieldArrayObject(0, 'uha.a', getPlaneIndex);
xMax := SmartGetFieldArraySize(rsObject, 'o', 1);
yMax := SmartGetFieldArraySize(rsObject, 'o', 2);

SetLength(blockArray, xMax - 4);
for i := low(blockArray) to high(blockArray) do
begin
setLength(blockArray[i], yMax - 4);
end;
markTime1 := getSystemTime;
for xCount := 0 to xMax - 5 do
begin
for yCount := 0 to yMax - 5 do
begin
blockArray[xCount][yCount] := smartGetFieldArray2DInt(rsObject, 'o', xCount, yCount);
end;
end;
smartFreeObject(rsObject);
result := blockArray;
end;

{*******************************************************************************
function GetMyLocalPos: TTile;
By: Iamadam
Description: Returns the local position of your player.
*******************************************************************************}
function GetMyLocalPos: TTile;
var
me: Integer;
begin
me := SmartGetFieldObject(0, hook_static_MyPlayer);
Result.x := SmartGetFieldInt(me, hook_animable_PixelX) / 512;
Result.y := SmartGetFieldInt(me, hook_animable_PixelY) / 512;
SmartFreeObject(me);
end;

{*******************************************************************************
function canReach(dest : TTile) : boolean;
By: Iamadam
Description: Returns true if the target tile can be reached from your players current position
*******************************************************************************}
function canReach(dest : TTile) : boolean;
var pathDist, baseX, baseY : Integer;
groundBlocks : array of array of integer;
localPos : TTile;
begin
if(not loggedIn) then exit;
baseX := SmartGetFieldInt(0, hook_static_BaseX);
baseY := SmartGetFieldInt(0, hook_static_BaseY);
localPos := getMyLocalPos;
groundBlocks := getGroundBlocks;
pathDist := dijkstraDistance(localPos.x, localPos.y, dest.x - baseX, dest.y - baseY, false, groundBlocks);
if(pathDist <> -1) then
result := true;
end;

Method

2011-04-27 22:59:03

From: Iamadam
Names:
uha.a –> groundDataArray
eq.o –> groundBlocks


Neither of those seem very informative. How about collisionMaps and traversalFlags or something similar?

Iamadam

2011-04-27 23:03:08

groundBlocks is collisionMap - we could use that, sure.
GroundDataArray has a bunch of other stuff that we'll never access.

Method

2011-04-27 23:07:23

From: Iamadam
groundBlocks is collisionMap - we could use that, sure.
GroundDataArray has a bunch of other stuff that we'll never access.


Like what? The fields I remember being in the class are the traversal flags, x/y bounds, and x/y offsets. Perhaps you're thinking of something else?

Iamadam

2011-04-27 23:34:09

That's right actually. But for this we don't need to access bounds/offsets.
Haven't looked into the other fields - but that class does seem to represent the collisionMap.
Happy to use those as names then.

I'm uploading the plugin source and edited simba files.
Someone with access, please compile the plugin for linux & commit. ??

Method

2011-04-27 23:44:09

From: Iamadam
That's right actually. But for this we don't need to access bounds/offsets.
Haven't looked into the other fields - but that class does seem to represent the collisionMap.
Happy to use those as names then.

I'm uploading the plugin source and edited simba files.
Someone with access, please compile the plugin for linux & commit. ??


Why wouldn't you use them, though? Considering the client has the ability to load variable-sized map regions (104x104, 120x120, 136x136, and 168x168), it makes sense to me to use at least the bounds fields to ensure that you're always looking at the entire loaded region. The offsets seem to always be -1, but I don't think it would hurt to use those two fields as well.

Iamadam

2011-04-27 23:47:21

I'm not sure if pyroryan has hooked them yet. If you like, you can edit the plugin source to work with variable sized regions :P

pyroryan

2011-04-28 01:07:51

From: Iamadam
I'm not sure if pyroryan has hooked them yet. If you like, you can edit the plugin source to work with variable sized regions :P


offsetX = eq.c
offsetY = eq.s
boundsX = eq.j
boundsY = eq.r

Home

2011-04-28 03:22:35

Good job Iamadam :)
Thanks for this, life saver ;)

~Home

**BANNED The Man

2011-04-28 12:29:53

(Read: Haven't read the source) Can this be used for say WebWalking?
Like will it detect walls and shizz? xD

-Boom

Iamadam

2011-04-28 19:39:05

Yes dynamite, that's exactly what it's for. Only thing is that it only works within the loaded area (usually a 104 x 104 block of tiles). But it is necessary for a decent webwalker.

Echo_

2011-04-30 09:32:04

ARGA be oldschool.

This is a sick function, I really hope it gets added.

ruler

2011-05-21 08:31:58

I would consider that tortuously slow.

Curious, why your back in pascal instead of java? rsbuddy, powerbot, etc.

In nexus, I got a hand coded one that builds an entire buffer that has the result for every tile in the chunk in 1.5-0.5ms on a i7-990X Extreme Edition Gulftown 3.46GHz.

And using that we have web pathing calcs that take 8 to 5 ms.

Drakan

2011-05-21 11:12:26

Ruler, you should pastebin me some of that yumminess :D

ruler

2011-05-21 13:16:59

My latest work is a new bank API, every little option anyone would ever want. Well for now at least until familiars.

All that is missing:
recipe withdraw (all or none) 1 root, 1 bottle, 1 something?
ratio withdraw like 1 copper, 1 tin.



//BankJob priority Highest to lowest
//Uses theColorScriptable.theInventorySlotSelector.select(slotsThatMatch, theColorScriptable)
//Uses theColorScriptable.getColorBot().theInventoryItemSlotToDeposit2.select(ignore, items, slotStacksLeft)
theBank2.processJobs(BankJob[] bankJobs, EnumSet<BankLocation> bankLocations, EnumSet<BankOptions> bankOptions, EnumSet<WebWalkingOptions> webOptions)
http://scripterland.com/partialSource/core/impsoft/scripting/ibot/builtin/itemrec/BankInterface2.java
http://scripterland.com/partialSource/scripts/BankTest.java
7a. actionThrottle will should help prevent doing 2 actions in one turn.
7b. Will compare to your current inventory before even going to bank.
7c. Will emulate inventory and push its predicted inventory to the rest of the bot in which the rest of the bot will uses this for TTL 4000ms or until another method modifies the inv.
7d. subsequent calls to processJobs may use the previous bank cache if we are under the 4000ms TTL
7e. Web calls should be able to continue using the emulated inventory no waiting or missing inventory items if you call count() right after doing a bank action in theory.
7f. current kinds of bank jobs:
http://scripterland.com/partialSource/core/impsoft/scripting/ibot/builtin/itemrec/BankJob.java
7g: caches bank x option
7h: bank options
http://scripterland.com/partialSource/core/impsoft/scripting/ibot/enums/BankOptions.java
7i:
WebWalkingOptions just like the rest of the system
http://scripterland.com/partialSource/core/impsoft/scripting/ibot/enums/WebWalkingOptions.java
7j: scripters have finner control over what banks to use.

Iamadam

2011-05-22 02:32:38

Ruler, this works fine. A call takes ~5ms. Just super slow in PS

Drakan

2011-06-02 16:17:16

Doesn't actually detect when the tile is out of reach. Just ran multiple tests on it. It does detect the distance around things, but it always seems to find a way even if the area is completely inaccessible.

Yago

2011-06-02 20:37:47

From: drags111
Doesn't actually detect when the tile is out of reach. Just ran multiple tests on it. It does detect the distance around things, but it always seems to find a way even if the area is completely inaccessible.


You can usually go around things like the AK fence and stuff. Maybe there should be checks based on tiles in the MM alone?

Drakan

2011-06-02 22:30:36

From: Yago
You can usually go around things like the AK fence and stuff. Maybe there should be checks based on tiles in the MM alone?


No the places I checked were completely inaccessible. Such as behind the bank counters and behind the bar counter in falador.

Yago

2011-06-02 22:33:13

From: drags111
No the places I checked were completely inaccessible. Such as behind the bank counters and behind the bar counter in falador.


That sucks. It would be really useful…

Drakan

2011-06-04 10:02:37

From: Yago
That sucks. It would be really useful…


It seems that certain objects are returning that they are in fact walkable when they are not, IE bank booths and certain tables. As far as walls go and stuff like that I have a working function now that will get all of that info.

Yago

2011-06-04 12:15:34

From: drags111
It seems that certain objects are returning that they are in fact walkable when they are not, IE bank booths and certain tables. As far as walls go and stuff like that I have a working function now that will get all of that info.


Good, I was using the old NPCChatText for reflection and I think there are some memleaks, just letting you know for a fix.
Also, I looked at chat in Ref2 and I couldn't find any functions for interacting and talking to NPC's. I would like to request it unless you are working on it :)

Drakan

2011-06-04 14:08:15

From: Yago
Good, I was using the old NPCChatText for reflection and I think there are some memleaks, just letting you know for a fix.
Also, I looked at chat in Ref2 and I couldn't find any functions for interacting and talking to NPC's. I would like to request it unless you are working on it :)


SRL handles that just fine so thats at the bottom of our priority list atm.

Iamadam

2011-06-05 06:45:42

Yeah, I have tested it and it does work - perhaps I didn't post proper code or something. Dunno.
But I tested it by trying to reach a tile inside a room with a closed door - returned no path. The opened the door and it was fine. I'll test some more =)

Drakan

2011-06-05 10:07:41

Try testing by trying to access behind a bank booth counter, for some reason it thinks the bank booths are walkable =]

Iamadam

2011-06-05 19:12:33

Hmm… maybe we need to hack it up a little - check tiles for unwalkable objects. Only concern is that will be slow & ugly :S

Drakan

2011-06-05 21:34:34

Yah speed is our biggest concern. I don't think those sorts of things would be that important anyway.

Iamadam

2011-06-05 23:12:25

No probably not. Just need to be careful in its use. Overall it works well enough to be included I think :)