 |

04-22-2011, 01:06 AM
|
|
Active Member
|
|
Join Date: Dec 2005
Location: Alberta Canada
Posts: 235
|
|
RuneScape Loader for VB2010
Due to some issues with an older RuneScape loader, I decided to rebuild it.
It supports hiding or showing the ads, taking snapshots, multiple game languages and loading RuneScape classic. Also if the X button at the login screen is pressed, it will automatically unload the game.
To use it, add the code below into a new code file, build your projects, add it to your form/usercontrol, the call the LoadGame function.
Code:
Imports System.Runtime.InteropServices
''' <summary>
''' A control for loading RuneScape.
''' </summary>
<System.Windows.Forms.Docking(DockingBehavior.AutoDock)>
Public Class RuneScapeLoader
Inherits Control
Private Const classicUrl As String = "http://www.runescape.com/classicapplet/classicgame.ws?f={0}"
Private Const gameUrl As String = "http://www.runescape.com{0}/game.ws"
Public Event GameLoaded As EventHandler
Public Event GameUnloaded As EventHandler
Public Event GameLoading As EventHandler
Private WithEvents Loader As RuneScapeLoaderBrowser
Private _gameHandle As IntPtr
Private _hideAds As Boolean = True
Private Sub Loader_Disposed(sender As Object, e As System.EventArgs) Handles Loader.Disposed
Me.Loader = Nothing
RaiseEvent GameUnloaded(Me, EventArgs.Empty)
End Sub
Private Sub SetLoaded(gameHandle As IntPtr?)
Dim gh = If(gameHandle, IntPtr.Zero)
Me._gameHandle = gh
If gameHandle.HasValue Then
RaiseEvent GameLoaded(Me, EventArgs.Empty)
End If
End Sub
''' <summary>
''' Gets if the RuneScape is currently loaded.
''' </summary>
<System.ComponentModel.Browsable(False)>
Public ReadOnly Property IsGameLoaded() As Boolean
Get
Return _gameHandle <> IntPtr.Zero
End Get
End Property
''' <summary>
''' Gets if the RuneScape is currently loading.
''' </summary>
<System.ComponentModel.Browsable(False)>
Public ReadOnly Property IsGameLoading() As Boolean
Get
Return Loader IsNot Nothing AndAlso _gameHandle = IntPtr.Zero
End Get
End Property
''' <summary>
''' Gets the current handle for RuneScape if it is loaded. Otherwise returns nothing.
''' </summary>
<System.ComponentModel.Browsable(False)>
Public ReadOnly Property GameHandle As IntPtr?
Get
Return If(_gameHandle = IntPtr.Zero, Nothing, _gameHandle)
End Get
End Property
''' <summary>
''' Gets or sets if the the game loader should hide everything but the game. Set to null, it will only hide the bar at the top for members.
''' </summary>
Public Property HideAds() As Boolean
Get
Return _hideAds
End Get
Set(ByVal value As Boolean)
_hideAds = value
If IsGameLoaded Then Loader.SetGameBounds(Loader.Url)
End Set
End Property
Private Sub InitLoader()
If Loader IsNot Nothing Then Throw New InvalidOperationException("RuneScape must be unloaded before it can be reloaded.")
Me.Loader = New RuneScapeLoaderBrowser(Me)
Me.Loader.Size = New Size(1000, 1000)
Me.Controls.Add(Loader)
End Sub
''' <summary>
''' Loads RuneScape using the specified language. Defaults to English.
''' </summary>
Public Sub LoadGame(Optional language As GameLanguage = GameLanguage.English)
InitLoader()
Loader.Navigate(String.Format(gameUrl, If(language = GameLanguage.English, "", "/l=" + CInt(language))))
RaiseEvent GameLoading(Me, EventArgs.Empty)
End Sub
''' <summary>
''' Loads RuneScape Classic using the specified world. Defaults to the best world.
''' </summary>
Public Sub LoadClassic(Optional world As Integer? = Nothing)
InitLoader()
Loader.Navigate(String.Format(classicUrl, If(world, "best")))
RaiseEvent GameLoading(Me, EventArgs.Empty)
End Sub
''' <summary>
''' Unloads RuneScape.
''' </summary>
Public Sub UnloadGame()
If Loader Is Nothing Then Throw New InvalidOperationException("RuneScape must be loaded before it can be unloaded.")
Loader.Navigate("about:dispose")
End Sub
''' <summary>
''' Takes a snapshot of RuneScape and returns an image. If the game is not loaded or there was another problem it will return nothing.
''' </summary>
Public Function TakeSnapshot() As Image
If Not IsGameLoaded Then Return Nothing
Dim lr = New RuneScapeLoaderBrowser.LRTBRect
RuneScapeLoaderBrowser.GetWindowRect(_gameHandle, lr)
Dim r = lr.ToRectangle()
If r.Width = 0 OrElse r.Height = 0 Then Return Nothing
Dim bmp = New Bitmap(r.Width, r.Height, Imaging.PixelFormat.Format24bppRgb)
Using g = Graphics.FromImage(bmp)
g.CopyFromScreen(r.Location, Point.Empty, r.Size)
End Using
Return bmp
End Function
''' <summary>
''' The languages RuneScape can use
''' </summary>
''' <remarks></remarks>
Public Enum GameLanguage
English = 0
German = 1
French = 2
Portuguese = 3
End Enum
Private NotInheritable Class RuneScapeLoaderBrowser
Inherits WebBrowser
Public Sub New(host As RuneScapeLoader)
Me.Host = host
Me.ScriptErrorsSuppressed = True
Me.Visible = False
End Sub
Public ReadOnly Host As RuneScapeLoader
Private Shared m As System.Text.RegularExpressions.Regex =
New System.Text.RegularExpressions.Regex("/l=.+/a=.+/p=.+")
#Region "Game Handle"
Public Delegate Function EnumWindowCallback(handle As IntPtr, listHandle As IntPtr) As Boolean
Public Declare Auto Function EnumChildWindows Lib "user32" (window As IntPtr, callback As EnumWindowCallback, listHandle As IntPtr) As Boolean
Public Declare Auto Function GetWindowRect Lib "user32" (window As IntPtr, ByRef rect As LRTBRect) As Boolean
Public Structure LRTBRect
Public Left, Top, Right, Bottom As Integer
Public Function ToRectangle() As Rectangle
Return Rectangle.FromLTRB(Left, Top, Right, Bottom)
End Function
End Structure
''' <summary>
''' Gets the handle and bounds of the loaded RuneScape client.
''' </summary>
Friend Function GetRuneScapeHandle() As Tuple(Of IntPtr, Rectangle)
Dim l As New List(Of Tuple(Of IntPtr, Rectangle))()
Dim gc = GCHandle.Alloc(l)
Try
EnumChildWindows(Me.Handle, AddressOf EnumWindowCB, GCHandle.ToIntPtr(gc))
Finally
If (gc.IsAllocated) Then gc.Free()
End Try
Return Aggregate x In l Into FirstOrDefault(x.Item2.Height >= 503 AndAlso x.Item2.Height < Me.Height)
End Function
''' <summary>
''' Adds the window handle and bounds of the window to the list.
''' </summary>
Private Shared Function EnumWindowCB(handle As IntPtr, listHandle As IntPtr) As Boolean
Dim gc = GCHandle.FromIntPtr(listHandle)
Dim l = TryCast(gc.Target, List(Of Tuple(Of IntPtr, Rectangle)))
If l Is Nothing Then Throw New InvalidCastException("GCHandle target could not be cast as List(Of Tuple(Of IntPtr, Rectangle)).")
Dim r = New LRTBRect
GetWindowRect(handle, r)
l.Add(Tuple.Create(handle, r.ToRectangle()))
Return True
End Function
#End Region
Protected Overrides Sub OnDocumentCompleted(e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs)
Dim Url = e.Url
' If the desired url is about:dispose, it will try to dispose of the browser.
If url.ToString().ToLower() = "about:dispose" Then
Me.BeginInvoke(New Action(AddressOf Dispose))
Return
End If
SetGameBounds(url)
End Sub
Public Sub SetGameBounds(url As Uri)
' Checks if the url is valid.
Dim isRuneScape = url.LocalPath.ToLower().EndsWith("/game.ws") AndAlso url.Host.ToLower() = "www.runescape.com"
Dim isRSClassic = url.Host.ToLower().StartsWith("classic") AndAlso url.Host.ToLower().EndsWith(".runescape.com")
If isRuneScape = isRSClassic Then Return
Dim target = Me.GetRuneScapeHandle()
If target Is Nothing OrElse target.Item1 = IntPtr.Zero Then Return
' Gets the required bounds of the web browser to hide everything but the game.
Dim targetRect = target.Item2
targetRect.Location -= Me.PointToScreen(Point.Empty)
Me.Anchor = 15
Me.Bounds = If(Host.HideAds, New Rectangle(-targetRect.X, -targetRect.Y, Parent.Width + (Me.Width - targetRect.Width), Parent.Height + (Me.Height - targetRect.Height)), Parent.ClientRectangle)
Me.Show()
Me.Host.SetLoaded(target.Item1)
End Sub
Protected Overrides Sub OnNavigating(e As System.Windows.Forms.WebBrowserNavigatingEventArgs)
' Makes sure the browser is disposed if going to the homepage.
If m.IsMatch(e.Url.AbsolutePath.ToLower()) Then
e.Cancel = True
Me.Navigate("about:dispose")
End If
End Sub
Protected Overrides Sub Dispose(disposing As Boolean)
Host.SetLoaded(Nothing)
MyBase.Dispose(disposing)
End Sub
End Class
End Class
Edit: Added an IsGameLoading property and GameLoading event to notify if the game is still loading, instead of some unknown state.
Last edited by Flaming Idiots : 04-28-2011 at 07:05 PM.
|

04-28-2011, 02:37 PM
|
 |
Creator of EliteSwitch
|
|
Join Date: Sep 2005
Location: Fuckin' BAM!
Posts: 4,464
|
|
Re: RuneScape Loader for VB2010
Hey Flaming, nice work 
Just one question about a problem i'm having.
When i load a classic world and then load a normal world (or vice-a-versa) if i don't wait until the game has finished loading it throws an errors saying "the game must be unloaded for it to be loaded".
Even though i have the following before my "Loadgame" call:
Code:
If rsMain.Visible = True Then 'this identifies a world has already been loaded
rsMain.UnloadGame()
Application.DoEvents()
End If
|

04-28-2011, 07:20 PM
|
|
Active Member
|
|
Join Date: Dec 2005
Location: Alberta Canada
Posts: 235
|
|
Re: RuneScape Loader for VB2010
If you unload the game, you must wait until the GameUnloaded event is raised before you can load another world (it's to make sure that Java doesn't explode). The easy way to fix this is just to disable the buttons while the game is loading.
If that's not an option, you can tell it to load the game after it's been unloaded like this:
Code:
Private unloadAction As Action
Private Sub RuneScapeLoader_GameUnloaded(sender As System.Object, e As System.EventArgs) Handles RuneScapeLoader.GameUnloaded
If unloadAction IsNot Nothing AndAlso Not (RuneScapeLoader.Disposing OrElse RuneScapeLoader.IsDisposed) Then
RuneScapeLoader.BeginInvoke(unloadAction)
unloadAction = Nothing
End If
End Sub
Private Sub LoadGameButton_Click(sender As System.Object, e As System.EventArgs) Handles LoadGameButton.Click
With Me.RuneScapeLoader
If Not (.IsGameLoading OrElse .IsGameLoaded) Then
.LoadGame()
Else
unloadAction = Sub() .LoadGame()
.UnloadGame()
End If
End With
End Sub
Private Sub LoadClassicButton_Click(sender As Object, e As System.EventArgs) Handles LoadClassicButton.Click
With Me.RuneScapeLoader
If Not (.IsGameLoading OrElse .IsGameLoaded) Then
.LoadClassic()
Else
unloadAction = Sub() .LoadClassic()
.UnloadGame()
End If
End With
End Sub
Private Sub UnloadGameButton_Click(sender As Object, e As System.EventArgs) Handles UnloadGameButton.Click
With Me.RuneScapeLoader
unloadAction = Nothing
If .IsGameLoaded OrElse .IsGameLoading Then .UnloadGame()
End With
End Sub
|

04-29-2011, 02:07 AM
|
 |
Creator of EliteSwitch
|
|
Join Date: Sep 2005
Location: Fuckin' BAM!
Posts: 4,464
|
|
Re: RuneScape Loader for VB2010
Thanks FI, i'll go with the simplicity or disabling the buttons 
|

04-29-2011, 01:41 PM
|
 |
Creator of EliteSwitch
|
|
Join Date: Sep 2005
Location: Fuckin' BAM!
Posts: 4,464
|
|
Re: RuneScape Loader for VB2010
Found a fix for it, replace the InitLoader() sub with this:
Code:
Private Sub InitLoader()
If Loader IsNot Nothing Then
UnloadGame()
Do Until Loader Is Nothing
Application.DoEvents()
Loop
End If
If Loader IsNot Nothing Then Throw New InvalidOperationException("RuneScape must be unloaded before it can be reloaded.")
Me.Loader = New RuneScapeLoaderBrowser(Me)
Me.Loader.Size = New Size(1000, 1000)
Me.Controls.Add(Loader)
End Sub
|
 |
|