PDA

View Full Version : How do I make a Java plugin for simba?



rj
10-12-2013, 08:36 PM
I don't understand how to make a Java plugin for Simba because there are no guides on how to :S

Brandon
10-12-2013, 08:42 PM
I don't understand how to make a Java plugin for Simba because there are no guides on how to :S

You can't? Well that depends on what you're trying to do. You'll eventually end up using JNI to connect the java side and the Simba.

rj
10-12-2013, 08:49 PM
You can't? Well that depends on what you're trying to do. You'll eventually end up using JNI to connect the java side and the Simba.

I just want to use the Java version of GetPage because it seems to be like 20% faster


this is what I have so far

package Grabber;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import javax.swing.JComponent;


public class Highscores {

public interface Plugin {
public void load(PluginConfiguration pluginConfiguration);
public String javaGetPage(String Name);
public void run();
public JComponent getConfigurationPage();
}

public static String getUrlSource(String url) throws IOException {
URL page = new URL(url);
URLConnection yc = page.openConnection();
BufferedReader in = new BufferedReader(new InputStreamReader(
yc.getInputStream(), "UTF-8"));
String inputLine;
StringBuilder a = new StringBuilder();
while ((inputLine = in.readLine()) != null)
a.append(inputLine);
in.close();

return a.toString();
}

public static String javaGetPage(String Name) {
try {
return getUrlSource("http://soulsplit.com/hs/index.php?name=" + Name);
} catch (IOException e) {
return "null";
}
}
public void run() {
System.out.println("Started get page plugin");
}

}

Brandon
10-12-2013, 09:04 PM
You'll need to write a dll in C/C++/Pascal/ASM or any other language capable of writing modules to run the jar and communicate with it..

The other option is to create a socket in Simba and listen on some port. Then on the Java side, write to that socket and Simba will retrieve whatever you wrote.

The last option is to have the jar write to a file and have Simba read that file..

Either way, I don't see how much "faster" the socket in the jar would be compared to a simba socket performing a get request..

The simba sockets and java sockets are both "C" sockets anyway as I'm sure both use WinAPI or the equivalent of.

Simba's compiled into a module and the jar is compiled into a jar file which is interpretted by the JVM or further compiled.


20% seems like a lot but do you have benchmarks that show the actual speed difference over a certain amount of runs?

rj
10-12-2013, 09:05 PM
You'll need to write a dll in C/C++/Pascal or any other language capable of writing modules to run the jar and communicate with it..

The other option is to create a socket in Simba and listen on some port. Then on the Java side, write to that socket and Simba will retrieve whatever you wrote.

The last option is to have the jar write to a file and have Simba read that file..

Either way, I don't see how much "faster" the socket in the jar would be compared to a simba socket performing a get request..

The simba sockets and java sockets are both "C" sockets anyway as that is what Windows API is. Simba's compiled into a module and the jar is compiled into a jar file which is interpretted by the JVM or further compiled.
oh nevermind then, so getpage is so slow because my internet is slow?

Brandon
10-12-2013, 09:11 PM
oh nevermind then, so getpage is so slow because my internet is slow?

No. It all depends on the implementation of GetPage as well as your internet. I cannot narrow down what makes it slow for you or anyone. It might be doing more than the Java socket under the hood of Simba.

You can always try creating a Raw socket in Simba and perform the Get by sending the right headers and see which is faster.

See here on how to use a raw socket: http://villavu.com/forum/showthread.php?t=94735


How slow are we talking here though?

rj
10-12-2013, 09:16 PM
No. It all depends on the implementation of GetPage as well as your internet. I cannot narrow down what makes it slow for you or anyone. It might be doing more than the Java socket under the hood of Simba.

You can always try creating a Raw socket in Simba and perform the Get by sending the right headers and see which is faster.

See here on how to use a raw socket: http://villavu.com/forum/showthread.php?t=94735


How slow are we talking here though?
Takes about 1500 ms to run but I plan to use my code as a way of getting the player stats, XP, and gamemode perfectly without having to bother with OCR stuff:


type PlayerSkills = record
IDS:Array[0..22] of Integer;
XPS:Array[0..22] of string;
Levels:Array[0..22] of string;
Names:Array[0..22] of string;
TotalLevel, TotalXP:string;
end;

type Player = record
Stats:PlayerSkills;
GameMode, name:string;
worked:boolean;
end;

var
PlayerArray:Array of Player;

procedure MarkTime(var a:Integer);
begin
a := GetSystemTime;
end;

function TimeFromMark(a:Integer):Integer;
begin
result := (GetSystemTime - a);
end;

function getPlayerStats(names:TStringArray):Boolean;
var
i, l:Integer;
str:string;
begin
SetLength(PlayerArray, Length(names));
for i := 0 to high(PlayerArray) do
begin
PlayerArray[i].name := names[i];
PlayerArray[i].Stats.Names := [
'Attack', 'Defence', 'Strength', 'Hitpoints', 'Ranged',
'Prayer', 'Magic', 'Cooking', 'Woodcutting', 'Fletching',
'Fishing', 'Firemaking', 'Crafting', 'Smithing', 'Mining',
'Herblore', 'Agility', 'Thieving', 'Slayer', 'Farming',
'Runecrafting', 'Dungeoneering', 'Summoning'
];
PlayerArray[i].Stats.IDS := [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
13, 14, 15, 16, 17, 18, 19, 20, 21, 22
];
names[i] := replace(names[i], ' ', '+', [rfReplaceAll]);
str := GetPage('http://soulsplit.com/hs/index.php?name=' + Names[i]);
for l := 0 to high(PlayerArray[i].Stats.Names) do
PlayerArray[i].Stats.Levels[l] := Between(PlayerArray[i].Stats.Names[l] + '</a></td><td>', '</td><td>',str);
for l := 0 to high(PlayerArray[i].Stats.Names) do
PlayerArray[i].Stats.XPS[l] := Between(PlayerArray[i].Stats.Names[l] + '</a></td><td>' + PlayerArray[i].Stats.Levels[l] + '</td><td>' , ' <td>' ,str);
for l := 0 to high(PlayerArray[i].Stats.XPS) do
PlayerArray[i].Stats.XPS[l] := replace(PlayerArray[i].Stats.XPS[l], ' ', '', [rfReplaceAll]);
PlayerArray[i].GameMode := between('Total Level (',')</a><',str);
PlayerArray[i].Stats.TotalLevel := between('Total Level (' + PlayerArray[i].GameMode + ')</a></td><td>', '</td>', str);
PlayerArray[i].Stats.TotalXP := between('Total Level (' + PlayerArray[i].GameMode + ')</a></td><td>' + PlayerArray[i].Stats.TotalLevel + '</td> <td> ','<td>', str);
end;
end;
var
i, l, t:Integer;
SSPlayers:TStringArray;

begin
MarkTime(t);
getPlayerStats(['advise']);
Writeln(TimeFromMark(t));
for l := 0 to high(PlayerArray) do
begin
Writeln('========================================= ============');
Writeln('Player: ' + PlayerArray[l].name + ' ' + PlayerArray[l].GameMode + ' ' + PlayerArray[l].stats.TotalLevel + ' ' + PlayerArray[l].stats.totalXP);
for i := 0 to high(PlayerArray[l].Stats.Names) do
Writeln(PlayerArray[0].Stats.Names[i] + ' ' + PlayerArray[0].Stats.Levels[i] + ' ' + PlayerArray[0].Stats.XPS[i])
end;
end.

Brandon
10-12-2013, 09:33 PM
Takes about 1500 ms to run but I plan to use my code as a way of getting the player stats, XP, and gamemode perfectly without having to bother with OCR stuff


There's quite a bit of optimisations you can do.. For example, you have the same for loop twice (well three times):


for l := 0 to high(PlayerArray[i].Stats.Names) do


Why? Just take whatever is in the second consequtive for loop and place it in the first loop. This way, you iterate the array once and perform the instructions you would have done going through it the second time around.

Basically, instead of doing 200k iterations for example, do 100k iteration by combining the two loops.


And finally, since you have:

PlayerArray[i].Stats.XPS[l] being the same length as PlayerArray[i].Stats.Names[l]

Then you can compress all three loops into one loop.


Thus:

for l := 0 to high(PlayerArray[i].Stats.Names) do
PlayerArray[i].Stats.Levels[l] := Between(PlayerArray[i].Stats.Names[l] + '</a></td><td>', '</td><td>',str);

for l := 0 to high(PlayerArray[i].Stats.Names) do
PlayerArray[i].Stats.XPS[l] := Between(PlayerArray[i].Stats.Names[l] + '</a></td><td>' + PlayerArray[i].Stats.Levels[l] + '</td><td>' , ' <td>' ,str);

for l := 0 to high(PlayerArray[i].Stats.XPS) do
PlayerArray[i].Stats.XPS[l] := replace(PlayerArray[i].Stats.XPS[l], ' ', '', [rfReplaceAll]);



becomes:


for l := 0 to high(PlayerArray[i].Stats.Names) do
begin
PlayerArray[i].Stats.Levels[l] := Between(PlayerArray[i].Stats.Names[l] + '</a></td><td>', '</td><td>',str);
PlayerArray[i].Stats.XPS[l] := Between(PlayerArray[i].Stats.Names[l] + '</a></td><td>' + PlayerArray[i].Stats.Levels[l] + '</td><td>' , ' <td>' ,str);
PlayerArray[i].Stats.XPS[l] := replace(PlayerArray[i].Stats.XPS[l], ' ', '', [rfReplaceAll]);
end;


And so.. you've cut your iterations by 1/3. But then you may notice you can remove an extra copy by turning it into:


for l := 0 to high(PlayerArray[i].Stats.Names) do
begin
PlayerArray[i].Stats.Levels[l] := Between(PlayerArray[i].Stats.Names[l] + '</a></td><td>', '</td><td>',str);
PlayerArray[i].Stats.XPS[l] := replace(Between(PlayerArray[i].Stats.Names[l] + '</a></td><td>' + PlayerArray[i].Stats.Levels[l] + '</td><td>' , ' <td>' ,str), ' ', '', [rfReplaceAll]);
end;


Now that last optimisation (the one right above that 'removes' extra copy), "may NOT" be an optimisation in Simba. It is in cpp though via r-value references/move semantics.

But you get the idea.. Now fix the others..

Example:


PlayerArray[i].Stats.Names := [............]
PlayerArray[i].IDs := [.......]


You are doing that in a LOOP. Does EVERY player really need an array of constants for themselves? Why not make that a global variable? Aka a static variable in Simba. It does not make much sense to keep assigning each player the same exact constant array every iteration..

Fix it and you'll have speed drastically improved.

For the:


WriteLn(Str1 + Str2 + ' ' + Str3); //for example..


That does a string concatenation BEFORE printing it.. Strings are immutable and so you are creating a new string at every + sign.. yes?
However, "I think" Lape's WriteLn might be faster as you do:


WriteLn(Str1, Str2, ' ', Str3);


It's only going to be faster if Lape's WriteLn comma operator does NOT concatenate each time and rather just writes straight to the standard output.

rj
10-12-2013, 09:41 PM
thanks lol forgot about the third loop, meant to remove it


New code



type PlayerSkills = record
XPS, Levels:Array[0..22] of string;
TotalLevel, TotalXP:string;
end;

type Player = record
Stats:PlayerSkills;
GameMode, name:string;
Skillnames:Array[0..22] of string;
end;

var
PlayerArray:Array of Player;

procedure MarkTime(var a:Integer);
begin
a := GetSystemTime;
end;

function TimeFromMark(a:Integer):Integer;
begin
result := (GetSystemTime - a);
end;

function getPlayerStats(names:TStringArray):Boolean;
var
i, l:Integer;
str:string;
begin
SetLength(PlayerArray, Length(names));
PlayerArray[i].Skillnames := [
'Attack', 'Defence', 'Strength', 'Hitpoints', 'Ranged',
'Prayer', 'Magic', 'Cooking', 'Woodcutting', 'Fletching',
'Fishing', 'Firemaking', 'Crafting', 'Smithing', 'Mining',
'Herblore', 'Agility', 'Thieving', 'Slayer', 'Farming',
'Runecrafting', 'Dungeoneering', 'Summoning'
];
for i := 0 to high(PlayerArray) do
begin
PlayerArray[i].name := names[i];
names[i] := replace(names[i], ' ', '+', [rfReplaceAll]);
str := GetPage('http://soulsplit.com/hs/index.php?name=' + Names[i]);
for l := 0 to high(PlayerArray[i].Skillnames) do
begin
PlayerArray[i].Stats.Levels[l] := Between(PlayerArray[i].Skillnames[l] + '</a></td><td>', '</td><td>',str);
PlayerArray[i].Stats.XPS[l] := Between(PlayerArray[i].Skillnames[l] + '</a></td><td>' + PlayerArray[i].Stats.Levels[l] + '</td><td>' , ' <td>' ,str);
end;
PlayerArray[i].GameMode := between('Total Level (',')</a><',str);
PlayerArray[i].Stats.TotalLevel := between('Total Level (' + PlayerArray[i].GameMode + ')</a></td><td>', '</td>', str);
PlayerArray[i].Stats.TotalXP := between('Total Level (' + PlayerArray[i].GameMode + ')</a></td><td>' + PlayerArray[i].Stats.TotalLevel + '</td> <td> ','<td>', str);
end;
end;


var
i, l, t:Integer;
SSPlayers:TStringArray;

begin
MarkTime(t);
getPlayerStats(['advise']);
Writeln(TimeFromMark(t));
for l := 0 to high(PlayerArray) do
begin
Writeln('========================================= ============');
Writeln('Player: ' + PlayerArray[l].name + ' ' + PlayerArray[l].GameMode + ' ' + PlayerArray[l].stats.TotalLevel + ' ' + PlayerArray[l].stats.totalXP);
for i := 0 to high(PlayerArray[l].Skillnames) do
Writeln(PlayerArray[0].Skillnames[i] + ' ' + PlayerArray[0].Stats.Levels[i] + ' ' + PlayerArray[0].Stats.XPS[i])
end;
end.

Not much of a change in performance but looks a lot better

Brandon
10-12-2013, 09:46 PM
Not much of a change in performance but looks a lot better

I wasn't done posting lol. Re-read all the edits in the previous post. Also note that your code you just posted won't compile because PlayerArray[I].SkillNames is NOT in the loop. But again, read the optimisations for that above.

It would be a ton faster if you got rid of all the "Between" and "Replace" stuff as they make allocations/copies a lot but I don't think you can.

rj
10-12-2013, 09:51 PM
I wasn't done posting lol. Re-read all the edits in the previous post. Also note that your code you just posted won't compile because PlayerArray[I].SkillNames is NOT in the loop. But again, read the optimisations for that above.

It would be a ton faster if you got rid of all the "Between" and "Replace" stuff as they make allocations/copies a lot but I don't think you can.

Edited it after posting





type PlayerSkills = record
XPS, Levels:Array[0..22] of string;
TotalLevel, TotalXP:string;
end;

type Player = record
Stats:PlayerSkills;
GameMode, name:string;
end;

var
PlayerArray:Array of Player;
SkillNames:TStringArray;

procedure MarkTime(var a:Integer);
begin
a := GetSystemTime;
end;

function TimeFromMark(a:Integer):Integer;
begin
result := (GetSystemTime - a);
end;

function getPlayerStats(names:TStringArray):Boolean;
var
i, l:Integer;
str:string;
begin
SetLength(PlayerArray, Length(names));
for i := 0 to high(PlayerArray) do
begin
PlayerArray[i].name := names[i];
names[i] := replace(names[i], ' ', '+', [rfReplaceAll]);
str := GetPage('http://soulsplit.com/hs/index.php?name=' + Names[i]);
for l := 0 to high(Skillnames) do
begin
PlayerArray[i].Stats.Levels[l] := Between(Skillnames[l] + '</a></td><td>', '</td><td>',str);
PlayerArray[i].Stats.XPS[l] := Between(Skillnames[l] + '</a></td><td>' + PlayerArray[i].Stats.Levels[l] + '</td><td>' , ' <td>' ,str);
end;
PlayerArray[i].GameMode := between('Total Level (',')</a><',str);
PlayerArray[i].Stats.TotalLevel := between('Total Level (' + PlayerArray[i].GameMode + ')</a></td><td>', '</td>', str);
PlayerArray[i].Stats.TotalXP := between('Total Level (' + PlayerArray[i].GameMode + ')</a></td><td>' + PlayerArray[i].Stats.TotalLevel + '</td> <td> ','<td>', str);
end;
end;


var
i, l, t:Integer;
SSPlayers:TStringArray;

begin
Skillnames := [
'Attack', 'Defence', 'Strength', 'Hitpoints', 'Ranged',
'Prayer', 'Magic', 'Cooking', 'Woodcutting', 'Fletching',
'Fishing', 'Firemaking', 'Crafting', 'Smithing', 'Mining',
'Herblore', 'Agility', 'Thieving', 'Slayer', 'Farming',
'Runecrafting', 'Dungeoneering', 'Summoning'
];
MarkTime(t);
getPlayerStats(['advise']);
Writeln(TimeFromMark(t));
for l := 0 to high(PlayerArray) do
begin
Writeln('========================================= ============');
Writeln('Player: ',PlayerArray[l].name , ' ' , PlayerArray[l].GameMode , ' ' , PlayerArray[l].stats.TotalLevel , ' ' , PlayerArray[l].stats.totalXP);
for i := 0 to high(Skillnames) do
Writeln(Skillnames[i],' ' , PlayerArray[0].Stats.Levels[i] , ' ' , PlayerArray[0].Stats.XPS[i])
end;
end.

that good now?

never knew about the " , " thing that's new in lape right?

Brandon
10-12-2013, 10:09 PM
that good now?
never knew about the " , " thing that's new in lape right?

Good but not enough.

This version runs in 359-900ms as opposed to yours which runs at a steady 1700ms+.. Iunno of any way to speed it up more other than to write a custom string builder or a module. Over 100 runs, it takes an average of 291ms.


const
SkillNames = ['Attack', 'Defence', 'Strength', 'Hitpoints', 'Ranged',
'Prayer', 'Magic', 'Cooking', 'Woodcutting', 'Fletching',
'Fishing', 'Firemaking', 'Crafting', 'Smithing', 'Mining',
'Herblore', 'Agility', 'Thieving', 'Slayer', 'Farming',
'Runecrafting', 'Dungeoneering', 'Summoning'
];


type PlayerSkills = record
XPS, Levels:Array[0..22] of string;
TotalLevel, TotalXP:string;
end;

type Player = record
Stats:PlayerSkills;
GameMode, name:string;
Skillnames:Array[0..22] of string;
end;

var
PlayerArray:Array of Player;

procedure MarkTime(var a:Integer);
begin
a := GetSystemTime;
end;

function TimeFromMark(a:Integer):Integer;
begin
result := (GetSystemTime - a);
end;

function getPlayerStats(names:TStringArray):Boolean;
var
i, l:Integer;
t, str:string;
begin
SetLength(PlayerArray, Length(names));

for i := 0 to high(PlayerArray) do
begin
PlayerArray[i].name := names[i];
str := Between('<tbody>', '</tbody>', GetPage('http://soulsplit.com/hs/index.php?name=' + replace(names[i], ' ', '+', [rfReplaceAll])));

for l := 0 to high(SkillNames) do
begin
T := Skillnames[l] + '</a></td><td>';
PlayerArray[i].Stats.Levels[l] := Between(T, '</td><td>',str);
PlayerArray[i].Stats.XPS[l] := Between(T + PlayerArray[i].Stats.Levels[l] + '</td><td>' , ' <td>' ,str);
end;

PlayerArray[i].GameMode := between('Total Level (',')</a><',str);

T := 'Total Level (' + PlayerArray[i].GameMode + ')</a></td><td>';
PlayerArray[i].Stats.TotalLevel := between(T, '</td>', str);
PlayerArray[i].Stats.TotalXP := between(T + PlayerArray[i].Stats.TotalLevel + '</td> <td> ','<td>', str);
end;
end;


var
i, l, t:Integer;
SSPlayers:TStringArray;

begin
ClearDebug;
MarkTime(t);
getPlayerStats(['advise']);
Writeln(TimeFromMark(t));
for l := 0 to high(PlayerArray) do
begin
Writeln('========================================= ============');
Writeln('Player: ',PlayerArray[l].name , ' ' , PlayerArray[l].GameMode , ' ' , PlayerArray[l].stats.TotalLevel , ' ' , PlayerArray[l].stats.totalXP);
for i := 0 to high(Skillnames) do
Writeln(Skillnames[i],' ' , PlayerArray[0].Stats.Levels[i] , ' ' , PlayerArray[0].Stats.XPS[i])
end;
end.



359
================================================== ===
Player: advise Legend 2398 4,800,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
99 200,000,000
121 200,000,000
99 200,000,000
Successfully executed.

rj
10-12-2013, 10:15 PM
..


grr why didn't I think of just using part of the page :s thanks anyway (both run 1700 ms for me)