SRL Archive - SRL Positioning System

Downloading minimap from graphics card/cache?


marpis

2011-12-01 01:39:22

Somewhere I found c0de had succeeded to get a pretty big, around 500x500 pixels picture of currently loaded RS map downloaded from graphics card. RS loads that chunk of map, and when you approach the edge you can see it in the minimap, when you start seeing black. Then RS loads a new chunk of map.

It would be revolutionary for SPS if someone here could do this! I really have no idea how c0de did that.

YoHoJo

2011-12-01 01:46:24

Yeah would be sweet if a plugin could simply just 'read' that loaded portion and for SPS to use/understand it! Then no need to create our own maps and download the maps files and stuff, would make everything a lot easier and be super cool!

Coh3n

2011-12-01 01:50:35

From: Method
From: Coh3n
Hey Method,

I was told you're the expert on this kind of this, so here goes. :) Basically, we're having some accuracy issues with SPS, and I think it's because the world map and the minimap aren't matching well enough (i.e. the minimap has more detail than the world map). I forget who it was, but someone extracted a piece of the minimap from the OpenGL client. They said they are the images the game uses to load into the minimap.

Is the same thing possible with the safe/software modes? If so, it would be amazing if we could extract the entire world map and use that for SPS rather than the in game world map.

Any information is appreciated.

Thanks,
Cohen


I don't know if the same thing is possible to do in safe mode or software mode, given that the graphics pipeline is different. However, I'm able to generate minimap images for areas that I can decrypt from the cache. Here's Lumbridge and the road just north of it (I don't have the key to decrypt the Lumbridge file; note the lack of walls, doors, and other objects):



Unfortunately, I don't have a program to gather the keys to decrypt the files, and the list of ones that I do have is outdated. If you guys can't figure out a way to make it work with the world map image, you might have to run around the world taking pictures of the minimap if you still want to use SPS.

Method
The second image would be perfect.

marpis

2011-12-01 02:45:16

Running around gathering the images wouldn't be a problem at all.
We would have the whole world within a week.

Coh3n

2011-12-01 13:09:05

From: marpis
Running around gathering the images wouldn't be a problem at all.
We would have the whole world within a week.
Are you serious? That is probably the biggest pain in the ass thing you can do. I did it for some of the dwarven mine and the essence mine and it was a pain, and those are very small areas.

It's not just running around getting images, you also have to crop them exactly right.

It's not hard, it's just a pain and will take a long time, and if the minimap is ever updated (which it probably will) it will take a long time to fix. I mean, if it's our only solution then fine, I just don't like it. :p

E: May not be a bad idea to do it for smaller areas first to test, like Al Khaird since a lot of people have issues with it.

weequ

2011-12-01 13:16:07

I think marpis means running around downloading the images as he explained.

Coh3n

2011-12-01 13:26:37

From: weequ
I think marpis means running around downloading the images as he explained.
Yeah… Did I say something different?

weequ

2011-12-01 13:39:16

From: Coh3n
Yeah… Did I say something different?
Well I thought you were talking about manually rotating compass to perfect north and then copying small areas at a time.

Edit: Sorry didn't read method's post. Only watched images.

euphemism

2011-12-01 13:43:21

Coh3n, Jagex apparently loads the minimap in ~ 500x500 pixel tiles, or areas, so if we walk around getting these tiles, we would have the same areas Jagex uses. So, if the map is updated in a certain area, it likely that only one of these tiles is updated, so all that would need to be done would be to walk into the bounds of that area and grab the updated tile.

Coh3n

2011-12-01 13:54:21

From: weequ
Well I thought you were talking about manually rotating compass to perfect north and then copying small areas at a time.

Edit: Sorry didn't read method's post. Only watched images.
That's what I was talking about. Is that not what Method said at the end of his message? I could be misunderstanding him I guess. :p

From: euphemism
Coh3n, Jagex apparently loads the minimap in ~ 500x500 pixel tiles, or areas, so if we walk around getting these tiles, we would have the same areas Jagex uses. So, if the map is updated in a certain area, it likely that only one of these tiles is updated, so all that would need to be done would be to walk into the bounds of that area and grab the updated tile.
Oh you mean getting the areas when they're loaded properly into the cache or whatever it's called?

I'm kind of confused right now. >.<

euphemism

2011-12-01 14:11:23

Yes, when they are loaded into the cache. I interpret Method's message to mean that if we aren't able to get the images from the cache, we are stuck doing what we have been doing. That is, your code that produces the SPS maps.

Coh3n

2011-12-01 14:39:39

Oh okay well gathering the 500x500 images isn't as bad. I thought they meant taking screenshots of the minimap and piecing them together. Gathering 500x500 images will still take a long time though, and be a big pain to update, BUT may improve SPS significantly.

If someone can explain how to get the images from the cache, I wouldn't mind trying out Al Kharid.

mormonman

2011-12-01 16:00:24

You have to have the right key to decrypt the cache.

Coh3n

2011-12-01 21:33:28

So we need a way to get the right key?

mormonman

2011-12-01 22:48:15

From: Coh3n
So we need a way to get the right key?


If I'm reading into Method's post correctly, we need a whole bunch of keys…

Coh3n

2011-12-02 00:17:41

Yes, sorry that's what I meant.

pyroryan

2011-12-09 12:29:57

From: mormonman
If I'm reading into Method's post correctly, we need a whole bunch of keys…


Like >1000 (1500?) XTEA keys. I believe the only way to get those is through injection. Either way, an insane amount.

mormonman

2011-12-09 12:56:26

From: pyroryan
Like >1000 (1500?) XTEA keys. I believe the only way to get those is through injection. Either way, an insane amount.


Would you have to dump the keys at runtime?

pyroryan

2011-12-09 16:32:49

From: mormonman
Would you have to dump the keys at runtime?


Thats how I used to do it. Basically run around collecting keys.

mormonman

2011-12-09 16:34:51

From: pyroryan
Thats how I used to do it. Basically run around collecting keys.


When do they change, every client update?

pyroryan

2011-12-09 16:39:27

From: mormonman
When do they change, every client update?


Not sure, I never really tracked nor bothered with using them. But I believe they'd update them if they change the map. If I recall correctly, there have been instances where most/all the keys were changed.

mormonman

2011-12-09 17:00:59

How hard is it to find those fields in the client? Is it worth finding them or would it take too much time?

pyroryan

2011-12-09 17:06:29

From: mormonman
How hard is it to find those fields in the client? Is it worth finding them or would it take too much time?


They're not fields. Hence "injection" to get them, reflection won't work. I doubt its worthwhile trying to dump them since it would take a lot more than a one man effort to dump keys for every region.

TRiLeZ

2011-12-10 02:54:21

From: pyroryan
They're not fields. Hence "injection" to get them, reflection won't work. I doubt its worthwhile trying to dump them since it would take a lot more than a one man effort to dump keys for every region.


Last time I checked (around a year ago), the keys for the loaded regions was stored in a field, but you still have to load a new region to get the key(s?).

I believe this (578) method used the keys field:


static final void parseMapRegion(boolean flag) {
CacheWorkerManager.secondaryMapRegion = flag;
if (CacheWorkerManager.secondaryMapRegion) {
int j = CustomCursorLoader.incomingStream.getUShort();
int l = CustomCursorLoader.incomingStream.getLEUShort();
int j1 = CustomCursorLoader.incomingStream.getNegUByte();
boolean flag1 = ~CustomCursorLoader.incomingStream.getNegUByte() == -2;
NodeSub_Sub11.method631(j1);
CustomCursorLoader.incomingStream.startBitAccess();
for (int l1 = 0; l1 < 4; l1++) {
for (int j2 = 0; ~j2 > ~(FloorLoader.mapWidth >> 3); j2++) {
for (int i3 = 0; ~i3 > ~(DummyOutputStream.mapHeight >> 3); i3++) {
int i4 = CustomCursorLoader.incomingStream.getBits(1);
if (i4 == 1) {
ClientMode.anIntArrayArrayArray2801[l1][j2][i3] = CustomCursorLoader.incomingStream.getBits(26);
} else {
ClientMode.anIntArrayArrayArray2801[l1][j2][i3] = -1;
}
}

}

}

CustomCursorLoader.incomingStream.endBitAccess();
int k2 = (Class46.currentPacketSize - CustomCursorLoader.incomingStream.offset) / 16;
GEItem.anIntArrayArray2395 = new int[k2][4];
for (int j3 = 0; k2 > j3; j3++) {
for (int j4 = 0; j4 < 4; j4++) {
GEItem.anIntArrayArray2395[j3][j4] = CustomCursorLoader.incomingStream.getInt();
}

}

HandshakePacket.landscapeIndices = new int[k2];
Class45_Sub1.underworldLandscapeIndices = new int[k2];
Class150.underworldMapData = new byte[k2][];
Class171.underworldLandscapeData = new byte[k2][];
Node_Sub18_Sub12.mapData = new byte[k2][];
Node_Sub18_Sub20.anIntArray5938 = null;
Mobile.mapIndices = new int[k2];
Class138.aByteArrayArray1676 = null;
Node_Sub5.underworldMapIndices = new int[k2];
Class186.mapRegions = new int[k2];
Class46.landscapeData = new byte[k2][];
k2 = 0;
for (int k4 = 0; k4 < 4; k4++) {
for (int i5 = 0; i5 < FloorLoader.mapWidth >> 3; i5++) {
for (int j5 = 0; ~j5 > ~(DummyOutputStream.mapHeight >> 3); j5++) {
int k5 = ClientMode.anIntArrayArrayArray2801[k4][i5][j5];
if (k5 != -1) {
int l5 = 0x3ff & k5 >> 14;
int i6 = (k5 & 0x3ff9) >> 3;
int region = i6 / 8 + (l5 / 8 << 8);
for (int k6 = 0; k6 < k2; k6++) {
if (region != Class186.mapRegions[k6]) {
continue;
}
region = -1;
break;
}

if (region != -1) {
Class186.mapRegions[k2] = region;
int x = (region & 0xff44) >> 8;
int y = 0xff & region;
Mobile.mapIndices[k2] = NodeSub_Sub13.fs5.getFileIndex("m" + x + "_" + y);
HandshakePacket.landscapeIndices[k2] = NodeSub_Sub13.fs5.getFileIndex("l" + x + "_" + y);
Node_Sub5.underworldMapIndices[k2] = NodeSub_Sub13.fs5.getFileIndex("um" + x + "_" + y);
Class45_Sub1.underworldLandscapeIndices[k2] = NodeSub_Sub13.fs5.getFileIndex("ul" + x + "_" + y);
k2++;
}
}
}

}

}

FloorLoader.method2620(false, j, flag1, l, true);
} else {
int k = CustomCursorLoader.incomingStream.getLEUShort();
int i1 = CustomCursorLoader.incomingStream.getUShort();
int k1 = CustomCursorLoader.incomingStream.getUByte();
boolean flag2 = ~CustomCursorLoader.incomingStream.getNegUByte() == -2;
NodeSub_Sub11.method631(k1);
int i2 = (-CustomCursorLoader.incomingStream.offset + Class46.currentPacketSize) / 16;
GEItem.anIntArrayArray2395 = new int[i2][4];
for (int l2 = 0; l2 < i2; l2++) {
for (int k3 = 0; k3 < 4; k3++) {
GEItem.anIntArrayArray2395[l2][k3] = CustomCursorLoader.incomingStream.getInt();
}

}

Node_Sub18_Sub12.mapData = new byte[i2][];
Node_Sub5.underworldMapIndices = new int[i2];
Class46.landscapeData = new byte[i2][];
Class150.underworldMapData = new byte[i2][];
HandshakePacket.landscapeIndices = new int[i2];
Mobile.mapIndices = new int[i2];
Class186.mapRegions = new int[i2];
Class45_Sub1.underworldLandscapeIndices = new int[i2];
Class171.underworldLandscapeData = new byte[i2][];
Class138.aByteArrayArray1676 = null;
Node_Sub18_Sub20.anIntArray5938 = null;
i2 = 0;
for (int x = (k - (FloorLoader.mapWidth >> 4)) / 8; (k + (FloorLoader.mapWidth >> 4)) / 8 >= x; x++) {
for (int y = (i1 - (DummyOutputStream.mapHeight >> 4)) / 8; y <= (i1 + (DummyOutputStream.mapHeight >> 4)) / 8; y++) {
Class186.mapRegions[i2] = (x << 8) + y;
Mobile.mapIndices[i2] = NodeSub_Sub13.fs5.getFileIndex("m" + x + "_" + y);
HandshakePacket.landscapeIndices[i2] = NodeSub_Sub13.fs5.getFileIndex("l" + x + "_" + y);
Node_Sub5.underworldMapIndices[i2] = NodeSub_Sub13.fs5.getFileIndex("um" + x + "_" + y);
Class45_Sub1.underworldLandscapeIndices[i2] = NodeSub_Sub13.fs5.getFileIndex("ul" + x + "_" + y);
i2++;
}

}

FloorLoader.method2620(false, k, flag2, i1, true);
}
}

pyroryan

2011-12-10 15:14:26

From: TRiLeZ
Last time I checked (around a year ago), the keys for the loaded regions was stored in a field, but you still have to load a new region to get the key(s?).

I believe this (578) method used the keys field:


You sir need to get on MSN more often. I suppose it is stored in fields as of 578, but I could have sworn it wasn't when I looked at it. Faulty memory I suppose. Either way, its impractical to walk around to get the keys for each region.

Shuttleu

2011-12-13 04:48:39

would it be possible to get the images through OpenGL, stitch them together and then use that in safe mode?

~shut

Kyle Undefined

2011-12-13 09:28:11

From: Shuttleu
would it be possible to get the images through OpenGL, stitch them together and then use that in safe mode?

~shut


Is the maps the same for Safe Mode? I only use Safe so I don't know if they differ.

Coh3n

2011-12-13 13:52:15

From: Shuttleu
would it be possible to get the images through OpenGL, stitch them together and then use that in safe mode?

~shut

I forget who it was, but someone posted an image from OpenGL, and it's not even close to what the minimap looks like. It didn't even look like the minimap in OpenGL, which doesn't make sense, does it?