Add projects including README.md(s), .gitignore(s) and the actual project files.
Signed-off-by: Michael Fabian Dirks <michael.dirks@project-kube.de>
@@ -0,0 +1,124 @@
|
||||
Strict
|
||||
|
||||
Import BRL.Stream
|
||||
Import BRL.Retro
|
||||
|
||||
Function FileMD5$(filePath$, bufferSize=$400000)
|
||||
Assert (bufferSize & 63) = 0 Else "bufferSize must be a multiple of 64 bytes"
|
||||
|
||||
Local h0 = $67452301, h1 = $EFCDAB89, h2 = $98BADCFE, h3 = $10325476
|
||||
|
||||
Local r[] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,..
|
||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,..
|
||||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,..
|
||||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]
|
||||
|
||||
Local k[] = [$D76AA478, $E8C7B756, $242070DB, $C1BDCEEE, $F57C0FAF, $4787C62A,..
|
||||
$A8304613, $FD469501, $698098D8, $8B44F7AF, $FFFF5BB1, $895CD7BE,..
|
||||
$6B901122, $FD987193, $A679438E, $49B40821, $F61E2562, $C040B340,..
|
||||
$265E5A51, $E9B6C7AA, $D62F105D, $02441453, $D8A1E681, $E7D3FBC8,..
|
||||
$21E1CDE6, $C33707D6, $F4D50D87, $455A14ED, $A9E3E905, $FCEFA3F8,..
|
||||
$676F02D9, $8D2A4C8A, $FFFA3942, $8771F681, $6D9D6122, $FDE5380C,..
|
||||
$A4BEEA44, $4BDECFA9, $F6BB4B60, $BEBFBC70, $289B7EC6, $EAA127FA,..
|
||||
$D4EF3085, $04881D05, $D9D4D039, $E6DB99E5, $1FA27CF8, $C4AC5665,..
|
||||
$F4292244, $432AFF97, $AB9423A7, $FC93A039, $655B59C3, $8F0CCC92,..
|
||||
$FFEFF47D, $85845DD1, $6FA87E4F, $FE2CE6E0, $A3014314, $4E0811A1,..
|
||||
$F7537E82, $BD3AF235, $2AD7D2BB, $EB86D391]
|
||||
|
||||
Local fileStream:TStream = OpenStream(filePath$, True, False)
|
||||
If fileStream = Null Then Return
|
||||
|
||||
Local buffer:Byte Ptr = MemAlloc(bufferSize)
|
||||
Local bitCount:Long, dataTop = bufferSize
|
||||
|
||||
Repeat
|
||||
Local bytesRead = fileStream.Read(buffer, bufferSize)
|
||||
|
||||
If fileStream.EOF()
|
||||
dataTop = (((bytesRead + 8) Shr 6) + 1) Shl 6
|
||||
If dataTop > bufferSize
|
||||
buffer = MemExtend(buffer, bufferSize, dataTop)
|
||||
EndIf
|
||||
|
||||
bitCount :+ (bytesRead Shl 3)
|
||||
|
||||
For Local b = (bytesRead + 1) Until (dataTop - 8)
|
||||
buffer[b] = 0
|
||||
Next
|
||||
|
||||
buffer[bytesRead] = $80
|
||||
LEPokeLong(buffer, dataTop - 8, bitCount)
|
||||
Else
|
||||
bitCount :+ (bufferSize Shl 3)
|
||||
EndIf
|
||||
|
||||
For Local chunkStart=0 Until (dataTop Shr 2) Step 16
|
||||
Local a = h0, b = h1, c = h2, d = h3
|
||||
|
||||
For Local i=0 To 15
|
||||
Local f = d ~ (b & (c ~ d))
|
||||
Local t = d
|
||||
|
||||
d = c ; c = b
|
||||
b = Rol((a + f + k[i] + LEPeekInt(buffer, (chunkStart + i) Shl 2)), r[i]) + b
|
||||
a = t
|
||||
Next
|
||||
|
||||
For Local i=16 To 31
|
||||
Local f = c ~ (d & (b ~ c))
|
||||
Local t = d
|
||||
|
||||
d = c ; c = b
|
||||
b = Rol((a + f + k[i] + LEPeekInt(buffer, (chunkStart + (((5 * i) + 1) & 15)) Shl 2)), r[i]) + b
|
||||
a = t
|
||||
Next
|
||||
|
||||
For Local i=32 To 47
|
||||
Local f = b ~ c ~ d
|
||||
Local t = d
|
||||
|
||||
d = c ; c = b
|
||||
b = Rol((a + f + k[i] + LEPeekInt(buffer, (chunkStart + (((3 * i) + 5) & 15)) Shl 2)), r[i]) + b
|
||||
a = t
|
||||
Next
|
||||
|
||||
For Local i=48 To 63
|
||||
Local f = c ~ (b | ~d)
|
||||
Local t = d
|
||||
|
||||
d = c ; c = b
|
||||
b = Rol((a + f + k[i] + LEPeekInt(buffer, (chunkStart + ((7 * i) & 15)) Shl 2)), r[i]) + b
|
||||
a = t
|
||||
Next
|
||||
|
||||
h0 :+ a ; h1 :+ b
|
||||
h2 :+ c ; h3 :+ d
|
||||
Next
|
||||
Until fileStream.EOF()
|
||||
|
||||
fileStream.Close()
|
||||
MemFree(buffer)
|
||||
|
||||
Return (LEHex(h0) + LEHex(h1) + LEHex(h2) + LEHex(h3)).ToLower()
|
||||
End Function
|
||||
|
||||
Function Rol(val, shift)
|
||||
Return (val Shl shift) | (val Shr (32 - shift))
|
||||
End Function
|
||||
|
||||
Function LEPeekInt(buffer:Byte Ptr, offset)
|
||||
Return (buffer[offset + 3] Shl 24) | (buffer[offset + 2] Shl 16) | ..
|
||||
(buffer[offset + 1] Shl 8) | buffer[offset]
|
||||
End Function
|
||||
|
||||
Function LEPokeLong(buffer:Byte Ptr, offset, value:Long)
|
||||
For Local b=7 To 0 Step -1
|
||||
buffer[offset + b] = (value Shr (b Shl 3)) & $ff
|
||||
Next
|
||||
End Function
|
||||
|
||||
Function LEHex$(val)
|
||||
Local out$ = Hex(val)
|
||||
|
||||
Return out$[6..8] + out$[4..6] + out$[2..4] + out$[0..2]
|
||||
End Function
|
||||
@@ -0,0 +1,197 @@
|
||||
'Function DebugProgressCB:Int(data:Object,dltotal:Double,dlnow:Double,ultotal:Double,ulnow:Double)
|
||||
' DebugLog "dltotal="+Int(dltotal)+",dlnow="+Int(dlnow)+",ultotal="+Int(ultotal)+",ulnow="+Int(ulnow)
|
||||
'EndFunction
|
||||
|
||||
|
||||
Rem
|
||||
Type TTaskPatchCheck Extends TTaskPatch
|
||||
Field m_stFile:String
|
||||
Field m_stHash:String
|
||||
Field l_bValid:Byte = True
|
||||
|
||||
Method Run()
|
||||
' Retrieve Hash
|
||||
Local stHash:String = FileMD5(m_stFile).ToUpper();l_fProgress = 0.5
|
||||
|
||||
' Compare Hash
|
||||
If stHash <> m_stHash Then
|
||||
l_bValid = False
|
||||
oPatchListMutex.Lock()
|
||||
oPatchList.AddLast(m_stFile)
|
||||
oPatchListMutex.Unlock()
|
||||
EndIf
|
||||
l_fProgress = 1.0
|
||||
EndMethod
|
||||
|
||||
Function Create:TTask(File:String, Hash:String)
|
||||
Local oTask:TTaskPatchCheck = New TTaskPatchCheck
|
||||
oTask.m_stFile = File
|
||||
oTask.m_stHash = Hash
|
||||
Return oTask
|
||||
EndFunction
|
||||
EndType
|
||||
|
||||
Type TTaskPatchFile Extends TTaskPatch
|
||||
Field m_stFile:String
|
||||
|
||||
Method Run()
|
||||
Local oCurl:TCurlEasy = New TCurlEasy
|
||||
oCurl.setOptInt(CURLOPT_FOLLOWLOCATION, 1)
|
||||
oCurl.setOptString(CURLOPT_USERAGENT, "Sirius Online Launcher")
|
||||
oCurl.setOptString(CURLOPT_REFERER, TPatcher_Server)
|
||||
oCurl.setOptString(CURLOPT_URL, TPatcher_Server + m_stFile)
|
||||
oCurl.setWriteString()
|
||||
|
||||
|
||||
EndMethod
|
||||
|
||||
Function Create:TTask(File:String)
|
||||
Local oTask:TTaskPatchFile = New TTaskPatchFile
|
||||
oTask.m_stFile = File
|
||||
Return oTask
|
||||
EndFunction
|
||||
EndType
|
||||
|
||||
Rem
|
||||
Import BRL.LinkedList
|
||||
|
||||
Const TPatcher_MaxParallelTasks:Int = 4
|
||||
Const TPatcher_Server:String = "http://sirius-online.us.to/patch/"
|
||||
|
||||
Type TPatcher
|
||||
' TCurlMulti Instance for non-blocking IO.
|
||||
Field oCurlMulti:TCurlMulti = TCurlMulti.Create()
|
||||
|
||||
' List of available tasks and active tasks.
|
||||
Field oTasks:TList = (New TList)
|
||||
Field oTaskSlots:TTaskSlot[] = New TTaskSlot[TPatcher_MaxParallelTasks]
|
||||
Field oTasksDone:TList = (New TList)
|
||||
|
||||
Method New()
|
||||
For Local i:Int = 0 Until TPatcher_MaxParallelTasks
|
||||
oTaskSlots[i].oCurl = oCurlMulti.newEasy()
|
||||
next
|
||||
|
||||
oTasks.AddLast(TTask_PatchInfo.Create())
|
||||
EndMethod
|
||||
|
||||
' Main loop for TPatcher
|
||||
Method Perform()
|
||||
Local runningHandles:Int
|
||||
|
||||
If oTaskSlots[0].oTask <> Null or oTaskSlots[1].oTask <> Null or oTaskSlots[2].oTask <> Null or oTaskSlots[3].oTask <> Null Then
|
||||
Local iResult:Int = CURLM_OK
|
||||
Repeat
|
||||
iResult = oCurlMulti.multiPerform(runningHandles)
|
||||
|
||||
For Local slot:Int = 0 Until TPatcher_MaxParallelTasks
|
||||
If oTaskSlots[slot].oTask = Null And oTasks.Count() > 0 Then
|
||||
oTaskSlots[slot].oTask = TTask(oTasks.RemoveLast())
|
||||
oTaskSlots[slot].oTask.Initialize(Self, oTaskSlots[slot].oCurl)
|
||||
ElseIf oTaskSlots[slot].oTask <> Null Then
|
||||
If oTaskSlots[slot].oTask.bComplete = True Then
|
||||
oTasksDone.AddLast(oTaskSlots[slot].oTask)
|
||||
oTaskSlots[slot].oTask = Null
|
||||
|
||||
' Restore TCurlEasy to useable state.
|
||||
oCurlMulti.multiRemove(oTaskSlots[slot].oCurl)
|
||||
oTaskSlots[slot].oCurl.cleanup()
|
||||
oCurlMulti.multiAdd(oTaskSlots[slot].oCurl)
|
||||
EndIf
|
||||
Endif
|
||||
Next
|
||||
Until iResult <> CURLM_CALL_MULTI_PERFORM
|
||||
Else
|
||||
oCurlMulti.cleanup()
|
||||
EndIf
|
||||
|
||||
EndMethod
|
||||
EndType
|
||||
|
||||
Type TTaskSlot
|
||||
Field oTask:TTask
|
||||
Field oCurl:TCurlEasy
|
||||
EndType
|
||||
|
||||
Type TTask Abstract
|
||||
Field oPatcher:TPatcher = Null
|
||||
Field stName:String = "Unknown"
|
||||
Field bComplete:Byte = False
|
||||
Field fProgress:Float = 0.0
|
||||
|
||||
Method Initialize(oPatcher:TPatcher, oCurl:TCurlEasy)
|
||||
Self.oPatcher = oPatcher
|
||||
oCurl.setWriteCallback(_HandleWriteCallback, Self)
|
||||
oCurl.setProgressCallback(_HandleProgressCallback, Self)
|
||||
EndMethod
|
||||
|
||||
Method HandleProgressCallback:Int(dltotal:Double, dlnow:Double, ultotal:Double, ulnow:Double)
|
||||
fProgress = dlnow / dltotal
|
||||
If dlnow = dltotal Then bComplete = True
|
||||
EndMethod
|
||||
Method HandleWriteCallback:Int(buffer:Byte Ptr, size:Int)
|
||||
EndMethod
|
||||
|
||||
Function _HandleProgressCallback:Int(Data:Object, dltotal:Double, dlnow:Double, ultotal:Double, ulnow:Double)
|
||||
Local Task:TTask = TTask(Data)
|
||||
Return Task.HandleProgressCallback(dltotal, dlnow, ultotal, ulnow)
|
||||
EndFunction
|
||||
Function _HandleWriteCallback(buffer:Byte Ptr, size:Int, Data:Object)
|
||||
Local Task:TTask = TTask(Data)
|
||||
Return Task.HandleWriteCallback(buffer, size)
|
||||
EndFunction
|
||||
EndType
|
||||
|
||||
Type TTask_PatchInfo Extends TTask
|
||||
Method New()
|
||||
Self.stName = "Retrieving Patch Information"
|
||||
EndMethod
|
||||
|
||||
Method Initialize(oPatcher:TPatcher, oCurl:TCurlEasy)
|
||||
Super.Initialize(oPatcher, oCurl)
|
||||
oCurl.setOptInt(CURLOPT_FOLLOWLOCATION, 1)
|
||||
oCurl.setOptString(CURLOPT_USERAGENT, "Sirius Online Launcher")
|
||||
oCurl.setOptString(CURLOPT_REFERER, TPatcher_Server)
|
||||
oCurl.setOptString(CURLOPT_URL, TPatcher_Server + "info")
|
||||
oCurl.setWriteString()
|
||||
EndMethod
|
||||
Method HandleProgressCallback:Int(dltotal:Double, dlnow:Double, ultotal:Double, ulnow:Double)
|
||||
Super.HandleProgressCallback()
|
||||
|
||||
If bComplete = True Then
|
||||
|
||||
EndIf
|
||||
EndMethod
|
||||
|
||||
Function Create:TTask()
|
||||
Return (New TTask_PatchInfo)
|
||||
EndFunction
|
||||
EndType
|
||||
|
||||
Type TTask_File Extends TTask
|
||||
Field stHash:String
|
||||
Field stFile:String
|
||||
|
||||
Method Initialize(oPatcher:TPatcher, oCurl:TCurlEasy)
|
||||
Super.Initialize(oPatcher, oCurl)
|
||||
oCurl.setOptInt(CURLOPT_FOLLOWLOCATION, 1)
|
||||
oCurl.setOptString(CURLOPT_USERAGENT, "Sirius Online Launcher")
|
||||
oCurl.setOptString(CURLOPT_REFERER, TPatcher_Server + "info")
|
||||
|
||||
'Local oFileStream:TStream =
|
||||
oCurl.setWriteString()
|
||||
EndMethod
|
||||
|
||||
Method HandleProgressCallback:Int(dltotal:Double, dlnow:Double, ultotal:Double, ulnow:Double)
|
||||
Super.HandleProgressCallback()
|
||||
EndMethod
|
||||
|
||||
Function Create:TTask(File:String, Hash:String)
|
||||
Local oTask:TTask_File = New TTask_File
|
||||
oTask.stHash = Hash
|
||||
oTask.stFile = File
|
||||
oCurl.setOptString(CURLOPT_URL, TPatcher_Server + oTask.File)
|
||||
Return oTask
|
||||
EndFunction
|
||||
EndType
|
||||
EndRem
|
||||
@@ -0,0 +1,242 @@
|
||||
SuperStrict
|
||||
|
||||
Import BRL.Threads
|
||||
Import BRL.LinkedList
|
||||
Import BRL.StandardIO
|
||||
|
||||
Const DEF_THREADPOOL_MINTHREADS:Int = 1
|
||||
Const DEF_THREADPOOL_MAXTHREADS:Int = 4
|
||||
|
||||
Type TThreadPool
|
||||
' Threads
|
||||
Field m_oThreads:TList = New TList
|
||||
Field m_iMinThreads:Int = DEF_THREADPOOL_MINTHREADS
|
||||
Field m_iMaxThreads:Int = DEF_THREADPOOL_MAXTHREADS
|
||||
|
||||
' Task Queue
|
||||
Field m_oTaskList:TList = New TList
|
||||
Field m_oTaskMutex:TMutex = TMutex.Create()
|
||||
|
||||
' Construction
|
||||
Function Create:TThreadPool(iMinThreads:Int = DEF_THREADPOOL_MINTHREADS, iMaxThreads:Int = DEF_THREADPOOL_MAXTHREADS)
|
||||
Local oThreadPool:TThreadPool = New TThreadPool
|
||||
oThreadPool.SetLimits(iMinThreads, iMaxThreads)
|
||||
Return oThreadPool
|
||||
EndFunction
|
||||
|
||||
' Destruction
|
||||
Method Destroy()
|
||||
For Local oThreadWorker:TThreadWorker = EachIn m_oThreads
|
||||
oThreadWorker.ForceDestroy()
|
||||
Next
|
||||
m_oThreads.Clear()
|
||||
m_oTaskList.Clear()
|
||||
EndMethod
|
||||
|
||||
' Change the thread limits, for example when the game configuration changes. Effective immediately or after
|
||||
Method SetLimits(iMinThreads:Int = DEF_THREADPOOL_MINTHREADS, iMaxThreads:Int = DEF_THREADPOOL_MAXTHREADS)
|
||||
m_iMinThreads = iMinThreads
|
||||
If (iMaxThreads < iMinThreads) Then iMaxThreads = iMinThreads
|
||||
m_iMaxThreads = iMaxThreads
|
||||
EndMethod
|
||||
|
||||
' Add new Task to the queue.
|
||||
Method AddTask(oTask:TTask)
|
||||
m_oTaskMutex.Lock()
|
||||
m_oTaskList.AddLast(oTask)
|
||||
m_oTaskMutex.Unlock()
|
||||
EndMethod
|
||||
|
||||
' Distributes work across threads, destroys and spawns threads
|
||||
Method Update:Int()
|
||||
Local iThreadCount:Int = m_oThreads.Count()
|
||||
|
||||
' Spawn more Threads if we don't have at least m_iMinThreads
|
||||
If iThreadCount < m_iMinThreads Then
|
||||
Local iSpawnCount:Int = m_iMinThreads - iThreadCount
|
||||
For Local spawn:Int = 1 To iSpawnCount
|
||||
m_oThreads.AddLast(New TThreadWorker)
|
||||
iThreadCount :+ 1
|
||||
Next
|
||||
EndIf
|
||||
|
||||
For Local oThreadWorker:TThreadWorker = EachIn m_oThreads
|
||||
' Loosely enforce m_iMaxThreads by destroying unused Threads.
|
||||
If iThreadCount > m_iMaxThreads And oThreadWorker.m_oAvailable.TryLock() = True Then
|
||||
If oThreadWorker.m_oTask = Null Then
|
||||
oThreadWorker.m_oAvailable.Unlock()
|
||||
oThreadWorker.Destroy()
|
||||
m_oThreads.Remove(oThreadWorker)
|
||||
iThreadCount :- 1
|
||||
Exit
|
||||
EndIf
|
||||
EndIf
|
||||
|
||||
' Distribute available work.
|
||||
m_oTaskMutex.Lock()
|
||||
If m_oTaskList.Count() > 0 And oThreadWorker.m_oAvailable.TryLock() = True Then
|
||||
oThreadWorker.m_oAvailable.Unlock()
|
||||
Local oTask:TTask = TTask(m_oTaskList.RemoveFirst())
|
||||
If oThreadWorker.AssignTask(oTask) = False Then m_oTaskList.AddLast(oTask)
|
||||
EndIf
|
||||
m_oTaskMutex.Unlock()
|
||||
|
||||
' Destroy Threads that have been waiting too long on Work, given that they are unneeded.
|
||||
If iThreadCount > m_iMinThreads And oThreadWorker.m_oAvailable.TryLock() = True Then
|
||||
oThreadWorker.m_oAvailable.Unlock()
|
||||
If oThreadWorker.m_oTask = Null And (MilliSecs() - oThreadWorker.m_lTaskTime) > 5000 Then
|
||||
m_oThreads.Remove(oThreadWorker)
|
||||
oThreadWorker.Destroy()
|
||||
iThreadCount :- 1
|
||||
EndIf
|
||||
EndIf
|
||||
Next
|
||||
|
||||
' Spawn more Threads if we did not hit m_iMaxThreads and there is still work left.
|
||||
m_oTaskMutex.Lock()
|
||||
If m_oTaskList.Count() > 0 And iThreadCount < m_iMaxThreads Then
|
||||
Local iSpawnCount:Int = Min(m_oTaskList.Count(), m_iMaxThreads - iThreadCount)
|
||||
For Local spawn:Int = 1 To iSpawnCount
|
||||
m_oThreads.AddLast(New TThreadWorker)
|
||||
iThreadCount :+ 1
|
||||
Next
|
||||
EndIf
|
||||
m_oTaskMutex.Unlock()
|
||||
|
||||
Return iThreadCount
|
||||
EndMethod
|
||||
|
||||
Method CountTasks:Int()
|
||||
Local retVal:Int = 0
|
||||
m_oTaskMutex.Lock()
|
||||
retVal = m_oTaskList.Count()
|
||||
m_oTaskMutex.Unlock()
|
||||
Return retVal
|
||||
EndMethod
|
||||
|
||||
Method CountActiveTasks:Int()
|
||||
Local retVal:Int = 0
|
||||
For Local oThreadWorker:TThreadWorker = EachIn m_oThreads
|
||||
oThreadWorker.m_oAvailable.Lock()
|
||||
If oThreadWorker.m_oTask <> Null Then retVal :+ 1
|
||||
oThreadWorker.m_oAvailable.Unlock()
|
||||
Next
|
||||
Return retVal
|
||||
EndMethod
|
||||
EndType
|
||||
|
||||
Type TThreadWorker
|
||||
Field m_oThread:TThread
|
||||
' Used to make the Thread sleep and work.
|
||||
Field m_oAvailable:TMutex
|
||||
Field m_oCondVar:TCondVar
|
||||
' Contains Task and the time it was assigned at.
|
||||
Field m_oTask:TTask
|
||||
Field m_lTaskTime:Long
|
||||
Field d_iCount:Int
|
||||
|
||||
' Construction
|
||||
Method New()
|
||||
m_oAvailable = TMutex.Create()
|
||||
m_oCondVar = TCondVar.Create()
|
||||
m_oThread = TThread.Create(Execute, Self)
|
||||
m_lTaskTime = MilliSecs()
|
||||
EndMethod
|
||||
|
||||
' Destruction
|
||||
Method Destroy()
|
||||
While AssignTask(oTaskTerminate) = False
|
||||
Delay 10
|
||||
Wend
|
||||
m_oThread.Wait() 'broken?
|
||||
m_oThread.Detach()
|
||||
EndMethod
|
||||
|
||||
Method ForceDestroy()
|
||||
m_oThread.Detach()
|
||||
EndMethod
|
||||
|
||||
' Task Management
|
||||
Method AssignTask:Int(oTask:TTask)
|
||||
If m_oAvailable.TryLock() = True And m_oTask = Null Then
|
||||
m_oTask = oTask
|
||||
m_lTaskTime = MilliSecs()
|
||||
m_oAvailable.Unlock()
|
||||
m_oCondVar.Signal()
|
||||
Return True
|
||||
EndIf
|
||||
Return False
|
||||
EndMethod
|
||||
|
||||
' Thread Wrapper Function
|
||||
Function Execute:Object(Data:Object)
|
||||
Local oThreadWorker:TThreadWorker = TThreadWorker(Data)
|
||||
|
||||
Local oTask:TTask = Null
|
||||
oThreadWorker.m_oAvailable.Lock()
|
||||
Repeat
|
||||
oThreadWorker.m_oCondVar.Wait(oThreadWorker.m_oAvailable)
|
||||
|
||||
If oThreadWorker.m_oTask <> Null Then
|
||||
oThreadWorker.d_iCount :+ 1
|
||||
oTask = oThreadWorker.m_oTask
|
||||
oThreadWorker.m_oAvailable.Unlock()
|
||||
oTask.Run()
|
||||
oThreadWorker.m_oAvailable.Lock()
|
||||
oThreadWorker.m_oTask = Null
|
||||
EndIf
|
||||
Until oTask = oTaskTerminate
|
||||
oThreadWorker.m_oAvailable.Unlock()
|
||||
EndFunction
|
||||
EndType
|
||||
|
||||
Type TTask Abstract
|
||||
' Called when a thread is working on this item.
|
||||
Method Run()
|
||||
EndMethod
|
||||
EndType
|
||||
|
||||
Type TTaskTerminate Extends TTask
|
||||
EndType
|
||||
Global oTaskTerminate:TTask = New TTaskTerminate
|
||||
|
||||
Type TTaskPtr Extends TTask
|
||||
Field m_pFunc:Object(data:Object)
|
||||
Field m_pData:Object
|
||||
Field m_pReturn:Object
|
||||
|
||||
' Construction
|
||||
Function Create:TTask(pFunc:Object(data:Object), pData:Object)
|
||||
Local oTWPtr:TTaskPtr = New TTaskPtr
|
||||
oTWPtr.SetFunction(pFunc)
|
||||
oTWPtr.SetData(pData)
|
||||
Return oTWPtr
|
||||
EndFunction
|
||||
|
||||
' Called when a thread is working on this item.
|
||||
Method Run()
|
||||
m_pReturn = m_pFunc(m_pData)
|
||||
EndMethod
|
||||
|
||||
' Set the Function executed by Run()
|
||||
Method SetFunction(pFunc:Object(data:Object))
|
||||
m_pFunc = pFunc
|
||||
EndMethod
|
||||
|
||||
' Set the Data passed to the Function.
|
||||
Method SetData(pData:Object)
|
||||
m_pData = pData
|
||||
EndMethod
|
||||
|
||||
' Retrieve the return value of the executed Function
|
||||
Method GetReturn:Object()
|
||||
Return m_pReturn
|
||||
EndMethod
|
||||
EndType
|
||||
|
||||
Global PrintMutex:TMutex = TMutex.Create()
|
||||
Function _Print(Str:String)
|
||||
PrintMutex.Lock()
|
||||
Print(Str)
|
||||
PrintMutex.Unlock()
|
||||
EndFunction
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <brl.mod/blitz.mod/blitz.h>
|
||||
#include <time.h>
|
||||
|
||||
int getClocksPerSecond_() {
|
||||
return CLOCKS_PER_SEC;
|
||||
}
|
||||
|
||||
int getClock_() {
|
||||
return (int)clock();
|
||||
}
|
||||
|
||||
int getClockDiff_(int clockStart, int clockEnd) {
|
||||
return ((clock_t)clockEnd - (clock_t)clockStart);
|
||||
}
|
||||
|
After Width: | Height: | Size: 817 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 56 KiB |
|
After Width: | Height: | Size: 85 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 677 KiB |
@@ -0,0 +1,488 @@
|
||||
SuperStrict
|
||||
|
||||
' Modules and Includes -----------------------------------------------------------------------------------------------------------------------------------------
|
||||
Framework BRL.Blitz
|
||||
Import BRL.StandardIO
|
||||
Import BRL.Timer
|
||||
Import BRL.Max2D
|
||||
Import BRL.GLMax2D
|
||||
Import BRL.Event
|
||||
Import BRL.EventQueue
|
||||
Import PUB.FreeProcess
|
||||
Import MaxGUI.MaxGUI
|
||||
Import MaxGUI.Drivers
|
||||
|
||||
' Libraries
|
||||
Import "TGUI.bmx"
|
||||
Import "Max2DExtended.bmx"
|
||||
|
||||
' Resources -----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
' Binary Resources
|
||||
Incbin "GFX/LNC/GUIxSTYLE.png"
|
||||
Incbin "SFX/M/launcher.ogg"
|
||||
|
||||
' Initialization ------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
SetGraphicsDriver(GLMax2DDriver())
|
||||
|
||||
' Create Timers to reduce CPU load.
|
||||
Global tmrRender:TTimer = CreateTimer(20) ' One for rendering the GUI
|
||||
Global tmrUpdate:TTimer = CreateTimer(100) ' And one for working.
|
||||
|
||||
' Create the Window and Canvas for the Patcher, set the Graphics Driver to OpenGL and enable polled input.
|
||||
Global gdgPatcher:TGadget = CreateWindow("Sirius Online", 0, 0, 720, 460, Desktop(), WINDOW_CLIENTCOORDS | WINDOW_CENTER | WINDOW_HIDDEN)
|
||||
Global gdgCanvas:TGadget = CreateCanvas(0, 0, ClientWidth(gdgPatcher), ClientHeight(gdgPatcher), gdgPatcher)
|
||||
SetGraphics(gdgCanvas) ' Change OpenGL Context to the Canvas.
|
||||
EnablePolledInput(gdgCanvas) ' Enable input handling for the Canvas.
|
||||
|
||||
DebugLog TShader.CheckCompatability()
|
||||
End
|
||||
|
||||
Rem
|
||||
' Load our GUI Style and split it into the required images.
|
||||
Global guiStyle:TPixmap = LoadPixmap("GFX/LNC/GUIxSTYLE.png")
|
||||
If guiStyle = Null Then guiStyle = LoadPixmap("incbin::GFX/LNC/GUIxSTYLE.png")
|
||||
|
||||
Global guiWindowBackground:TImage = LoadImage(guiStyle.Window(0, 0, 32, 32), FILTEREDIMAGE)
|
||||
Global guiWindowShade:TImage[] = New TImage[2]
|
||||
guiWindowShade[0] = LoadImage(guiStyle.Window(32, 0, 16, 16), FILTEREDIMAGE)
|
||||
guiWindowShade[1] = LoadImage(guiStyle.Window(32, 16, 16, 16), FILTEREDIMAGE)
|
||||
Global guiWindowTitleBar:TImage[] = New TImage[2]
|
||||
guiWindowTitleBar[0] = LoadImage(guiStyle.Window(48, 0, 16, 16), FILTEREDIMAGE)
|
||||
guiWindowTitleBar[1] = LoadImage(guiStyle.Window(48, 16, 16, 16), FILTEREDIMAGE)
|
||||
Global guiSymbols:TImage[] = New TImage[8]
|
||||
guiSymbols[0] = LoadImage(guiStyle.Window(64, 0, 16, 16), FILTEREDIMAGE) 'Close
|
||||
guiSymbols[1] = LoadImage(guiStyle.Window(80, 0, 16, 16), FILTEREDIMAGE) 'Minimize
|
||||
guiSymbols[2] = LoadImage(guiStyle.Window(96, 0, 16, 16), FILTEREDIMAGE) 'Maximize
|
||||
guiSymbols[3] = LoadImage(guiStyle.Window(112, 0, 16, 16), FILTEREDIMAGE) 'Restore
|
||||
guiSymbols[4] = LoadImage(guiStyle.Window(64, 16, 16, 16), FILTEREDIMAGE)
|
||||
guiSymbols[5] = LoadImage(guiStyle.Window(80, 16, 16, 16), FILTEREDIMAGE)
|
||||
guiSymbols[6] = LoadImage(guiStyle.Window(96, 16, 16, 16), FILTEREDIMAGE)
|
||||
guiSymbols[7] = LoadImage(guiStyle.Window(112, 16, 16, 16), FILTEREDIMAGE)
|
||||
Global guiButtonNormal:TImage[] = New TImage[3]
|
||||
guiButtonNormal[0] = LoadImage(guiStyle.Window(0, 32, 16, 16), FILTEREDIMAGE)
|
||||
guiButtonNormal[1] = LoadImage(guiStyle.Window(0, 48, 16, 16), FILTEREDIMAGE)
|
||||
guiButtonNormal[2] = LoadImage(guiStyle.Window(0, 64, 16, 16), FILTEREDIMAGE)
|
||||
Global guiButtonShaped:TImage[] = New TImage[3]
|
||||
guiButtonShaped[0] = LoadImage(guiStyle.Window(16, 32, 16, 16), FILTEREDIMAGE)
|
||||
guiButtonShaped[1] = LoadImage(guiStyle.Window(16, 48, 16, 16), FILTEREDIMAGE)
|
||||
guiButtonShaped[2] = LoadImage(guiStyle.Window(16, 64, 16, 16), FILTEREDIMAGE)
|
||||
Global guiProgressBar:TImage[] = New TImage[3]
|
||||
guiProgressBar[0] = LoadImage(guiStyle.Window(16, 80, 16, 16), FILTEREDIMAGE)
|
||||
guiProgressBar[1] = LoadImage(guiStyle.Window(16, 96, 16, 16), FILTEREDIMAGE)
|
||||
guiProgressBar[2] = LoadImage(guiStyle.Window(16, 112, 16, 16), FILTEREDIMAGE)
|
||||
EndRem
|
||||
|
||||
' Show the Patcher Window
|
||||
ShowGadget gdgPatcher
|
||||
|
||||
' GUI Values
|
||||
Const guiTitleHeight:Int = 24
|
||||
Global guiWidth:Int = ClientWidth(gdgPatcher)
|
||||
Global guiHeight:Int = ClientHeight(gdgPatcher)
|
||||
Global guiActive:Int = True
|
||||
|
||||
|
||||
' Main Loop -----------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Repeat
|
||||
WaitEvent()
|
||||
|
||||
Select EventSource()
|
||||
Case tmrRender
|
||||
SetGraphics CanvasGraphics(gdgCanvas);Cls
|
||||
|
||||
Rem
|
||||
' Draw GUI
|
||||
SetColor(255, 255, 255); SetAlpha(1.0); SetBlend(SOLIDBLEND); SetScale(1.0, 1.0); SetRotation(0.0)
|
||||
' Title Bar and Title
|
||||
DrawTiledImage guiWindowTitleBar[guiActive], 0, 0, guiWidth, guiTitleHeight, 0, 0, 16, 16,,,,4,4,4,4, True, MODE_SCALEUPX | MODE_SCALEUPY
|
||||
DrawText(GadgetText(gdgPatcher), 4, guiTitleHeight / 2 - (12 / 2))
|
||||
|
||||
' Content Background
|
||||
DrawSubImageRectEx guiWindowBackground, 0, guiTitleHeight, guiWidth, guiHeight - guiTitleHeight, 0, 0, 32, 32,,,, MODE_REPEATX | MODE_REPEATY
|
||||
SetBlend SHADEBLEND
|
||||
DrawTiledImage guiContent[guiActive], 0, guiTitleHeight, guiWidth, guiHeight - guiTitleHeight, 0, 0, 16, 16,,,, 4, 4, 4, 4, True, MODE_REPEATX | MODE_REPEATY | MODE_SCALEUPX | MODE_SCALEUPY
|
||||
EndRem
|
||||
|
||||
|
||||
|
||||
' Show the now rendered GUI
|
||||
Flip False
|
||||
Case gdgPatcher
|
||||
Select EventID()
|
||||
Case EVENT_WINDOWMODE, EVENT_WINDOWSIZE
|
||||
' Update GUI Values {
|
||||
guiWidth = ClientWidth(gdgPatcher)
|
||||
guiHeight = ClientWidth(gdgPatcher)
|
||||
' }
|
||||
End Select
|
||||
End Select
|
||||
Forever
|
||||
End
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Rem
|
||||
' Files
|
||||
Import "Patcher.bmx"
|
||||
|
||||
'=====> Constants
|
||||
?Win32
|
||||
Const LAUNCHER_NAME:String = "Launcher.exe"
|
||||
?Linux
|
||||
Const LAUNCHER_NAME:String = "Launcher.bin"
|
||||
?MacOS
|
||||
Const LAUNCHER_NAME:String = "Launcher.app"
|
||||
?
|
||||
|
||||
'=====> Parse Arguments
|
||||
Global stProgram:String = AppArgs[0]
|
||||
Global stProgramPath:String = ExtractDir(AppArgs[0])
|
||||
Global stProgramName:String = StripDir(AppArgs[0])
|
||||
Global bPatchLauncher:Byte = False
|
||||
Global iPatchRetries:Int = 30
|
||||
|
||||
For Local stArgument:String = EachIn AppArgs[1..]
|
||||
Local stArgName:String, stArgValue:String
|
||||
|
||||
' Skip arguments not starting with a dash
|
||||
If stArgument[0..1] <> "-" Then Continue
|
||||
|
||||
Local iValuePos:Int = stArgument.Find("=")
|
||||
If iValuePos >= 0 Then
|
||||
stArgName = stArgument[1..iValuePos]
|
||||
stArgValue = stArgument[iValuePos..]
|
||||
Else
|
||||
stArgName = stArgument[1..]
|
||||
stArgValue = "1"
|
||||
EndIf
|
||||
|
||||
Select stArgName
|
||||
Case "patch"
|
||||
bPatchLauncher = Byte(stArgValue)
|
||||
Case "retry"
|
||||
iPatchRetries = Int(stArgValue)
|
||||
End Select
|
||||
Next
|
||||
|
||||
'=====> Use parsed Arguments
|
||||
|
||||
'--> Patch the Launcher
|
||||
If bPatchLauncher = True Then
|
||||
Local iRetryCount:Int = 0
|
||||
Local oRetryTimer:TTimer = TTimer.Create(10)
|
||||
|
||||
' Copy the newly downloaded Launcher file
|
||||
If stProgramName <> LAUNCHER_NAME Then
|
||||
If FileType(LAUNCHER_NAME) = FILETYPE_FILE Then
|
||||
Repeat
|
||||
oRetryTimer.Wait()
|
||||
iRetryCount :+ 1
|
||||
Until (DeleteFile(LAUNCHER_NAME) = True) or (iRetryCount > iPatchRetries)
|
||||
EndIf
|
||||
|
||||
If FileType(LAUNCHER_NAME) = 0 Then
|
||||
Repeat
|
||||
oRetryTimer.Wait()
|
||||
iRetryCount :+ 1
|
||||
Until (CopyFile(stProgramName, LAUNCHER_NAME) = True) or (iRetryCount > iPatchRetries)
|
||||
|
||||
If FileType(LAUNCHER_NAME) = FILETYPE_FILE Then
|
||||
Local oProcess:TProcess = CreateProcess(LAUNCHER_NAME)
|
||||
TProcess.ProcessList.Remove oProcess
|
||||
End
|
||||
Else
|
||||
Notify("Error: Failed to replace Launcher", True)
|
||||
End
|
||||
EndIf
|
||||
Else
|
||||
Notify("Error: Failed to delete old Launcher", True)
|
||||
End
|
||||
EndIf
|
||||
EndIf
|
||||
EndIf
|
||||
|
||||
' Resources: Create Variables that store resources.
|
||||
Global riMainBackground:Int, imMainBackground:TImage;LoadResource("GFX/LNC/LAUxPATxB.png",, imMainBackground, riMainBackground)
|
||||
Global riMainForeground:Int, imMainForeground:TImage;LoadResource("GFX/LNC/LAUxPATxA.png",, imMainForeground, riMainForeground)
|
||||
Global riProgressBar:Int, imProgressBar:TImage; LoadResource("GFX/LNC/BARxPROGRESS.png",, imProgressBar, riProgressBar)
|
||||
Global riButtonClose:Int, imButtonClose:TImage; LoadResource("GFX/LNC/BTNxCLOSE.png",, imButtonClose, riButtonClose)
|
||||
Global riButtonAccount:Int, imButtonAccount:TImage; LoadResource("GFX/LNC/BTNxACCOUNT.png",, imButtonAccount, riButtonAccount)
|
||||
Global riButtonWebsite:Int, imButtonWebsite:TImage; LoadResource("GFX/LNC/BTNxWEBSITE.png",, imButtonWebsite, riButtonWebsite)
|
||||
Global riButtonSupport:Int, imButtonSupport:TImage; LoadResource("GFX/LNC/BTNxSUPPORT.png",, imButtonSupport, riButtonSupport)
|
||||
Global riButtonEULATOS:Int, imButtonEULATOS:TImage; LoadResource("GFX/LNC/BTNxEULATOS.png",, imButtonEULATOS, riButtonEULATOS)
|
||||
Global riButtonCheck:Int, imButtonCheck:TImage; LoadResource("GFX/LNC/BTNxCHECK.png",, imButtonCheck, riButtonCheck)
|
||||
Global riButtonPatch:Int, imButtonPatch:TImage; LoadResource("GFX/LNC/BTNxPATCH.png",, imButtonPatch, riButtonPatch)
|
||||
Global riButtonPlay:Int, imButtonPlay:TImage; LoadResource("GFX/LNC/BTNxPLAY.png",, imButtonPlay, riButtonPlay)
|
||||
Global riButtonRestart:Int, imButtonRestart:TImage; LoadResource("GFX/LNC/BTNxRESTART.png",, imButtonRestart, riButtonRestart)
|
||||
Global rfSmallFont:Int, fnSmallFont:TImageFont; LoadFontResource("GFX/FNT/TranscencsGames.otf", 10,, fnSmallFont, rfSmallFont)
|
||||
Global rfMediumFont:Int, fnMediumFont:TImageFont;LoadFontResource("GFX/FNT/TranscencsGames.otf", 12,, fnMediumFont, rfMediumFont)
|
||||
Global rfBigFont:Int, fnBigFont:TImageFont; LoadFontResource("GFX/FNT/TranscencsGames.otf", 14,, fnBigFont, rfBigFont)
|
||||
|
||||
' Buttons
|
||||
Const BTN_STT_NORMAL:Int = 0, BTN_STT_HOVER:Int = 1, BTN_STT_DOWN:Int = 2, BTN_STT_ACTION:Int = 3
|
||||
Global stButtonClose:Int = BTN_STT_NORMAL
|
||||
Global stButtonAccount:Int = BTN_STT_NORMAL
|
||||
Global stButtonWebsite:Int = BTN_STT_NORMAL
|
||||
Global stButtonSupport:Int = BTN_STT_NORMAL
|
||||
Global stButtonEULATOS:Int = BTN_STT_NORMAL
|
||||
Global stButtonCheck:Int = BTN_STT_NORMAL
|
||||
Global stButtonPatch:Int = BTN_STT_NORMAL
|
||||
Global stButtonPlay:Int = BTN_STT_NORMAL
|
||||
Global stButtonRestart:Int = BTN_STT_NORMAL
|
||||
|
||||
' PatchLog
|
||||
Global oPatchLog:TList = New TList
|
||||
|
||||
' Patcher
|
||||
Global oPatcher:TPatcher = TPatcher.Create()
|
||||
ShowGadget(gdPatcherWindow)
|
||||
EndRem
|
||||
|
||||
|
||||
|
||||
Rem
|
||||
'=====> Mainloop
|
||||
Local relMouseX:Int, relMouseY:Int, bDragging:Byte
|
||||
Repeat
|
||||
WaitEvent()
|
||||
Select EventSource()
|
||||
Case tmTimer ' Core timer that is basically our main loop.
|
||||
'=====> User-input
|
||||
Local MX:Int = MouseX(), MY:Int = MouseY()
|
||||
Local MD1:Int = MouseDown(1), MH1:Int = MouseHit(1)
|
||||
|
||||
stButtonClose = GetButtonState(stButtonClose, 684, 0, 24, 18, MX, MY, MD1)
|
||||
stButtonWebsite = GetButtonState(stButtonWebsite, 618, 330, 96, 16, MX, MY, MD1)
|
||||
stButtonSupport = GetButtonState(stButtonSupport, 618, 348, 96, 16, MX, MY, MD1)
|
||||
stButtonAccount = GetButtonState(stButtonAccount, 618, 366, 96, 16, MX, MY, MD1)
|
||||
stButtonEULATOS = GetButtonState(stButtonEULATOS, 618, 384, 96, 16, MX, MY, MD1)
|
||||
|
||||
' React on the close button by sending a WindowCloseEvent
|
||||
If stButtonClose = BTN_STT_ACTION Then PostEvent(TEvent.Create(EVENT_WINDOWCLOSE, gdPatcherWindow, 0, 0, 0, 0, Null))
|
||||
If stButtonWebsite = BTN_STT_ACTION Then OpenURL("http://www.sirius.vektor-studios.com/")
|
||||
If stButtonSupport = BTN_STT_ACTION Then OpenURL("http://www.sirius.vektor-studios.com/#contact")
|
||||
If stButtonAccount = BTN_STT_ACTION Then OpenURL("http://www.sirius.vektor-studios.com/")
|
||||
If stButtonEULATOS = BTN_STT_ACTION Then OpenURL("http://www.sirius.vektor-studios.com/")
|
||||
|
||||
' State based checking
|
||||
Select oPatcher.GetState()
|
||||
Case TPatcher.STATE_PATCHINFO
|
||||
stButtonCheck = GetButtonState(stButtonCheck, 312, 441, 96, 16, MX, MY, MD1)
|
||||
If stButtonCheck = BTN_STT_ACTION Then oPatcher.Advance()
|
||||
Case TPatcher.STATE_PREPATCH
|
||||
stButtonPatch = GetButtonState(stButtonPatch, 312, 441, 96, 16, MX, MY, MD1)
|
||||
If stButtonPatch = BTN_STT_ACTION Then oPatcher.Advance()
|
||||
Case TPatcher.STATE_COMPLETE
|
||||
stButtonPlay = GetButtonState(stButtonPlay, 312, 441, 96, 16, MX, MY, MD1)
|
||||
If stButtonPlay = BTN_STT_ACTION Then oPatcher.Advance()
|
||||
Case TPatcher.STATE_LAUNCHER
|
||||
stButtonRestart = GetButtonState(stButtonRestart, 312, 441, 96, 16, MX, MY, MD1)
|
||||
If stButtonRestart = BTN_STT_ACTION Then oPatcher.Advance()
|
||||
EndSelect
|
||||
|
||||
' Window Dragging
|
||||
If bDragging = False And (MH1 = True And (MY >= 0 And MY < 32) And (MX >= 0 And MX < 720)) Then
|
||||
bDragging = True
|
||||
relMouseX = MX;relMouseY = MY
|
||||
ElseIf bDragging = True And MD1 = True Then
|
||||
SetGadgetShape(gdPatcherWindow, GadgetX(gdPatcherWindow) - (relMouseX - MX), GadgetY(gdPatcherWindow) - (relMouseY - MY), 720, 460)
|
||||
relMouseX = MX + (relMouseX - MX);relMouseY = MY + (relMouseY - MY) 'Magic o.o - I don't understand why this works this way, but not when using :+ notation.
|
||||
Else
|
||||
bDragging = False
|
||||
EndIf
|
||||
|
||||
'=====> Rendering
|
||||
SetGraphics CanvasGraphics(gdRenderCanvas)
|
||||
Cls
|
||||
|
||||
' Draw Back- & Foreground
|
||||
SetBlend ALPHABLEND;SetMaskColor 0, 0, 0
|
||||
SetColor 255, 255, 255;SetAlpha 1.0
|
||||
SetOrigin 0, 0;SetTransform 0, 1, 1
|
||||
If imMainBackground <> Null Then DrawImage(imMainBackground, 0, 0)
|
||||
If imMainForeground <> Null Then DrawImage(imMainForeground, 0, 0)
|
||||
|
||||
' Window Close Button
|
||||
DrawButtonState(stButtonClose, 684, 0, 24, 18, imButtonClose, "X")
|
||||
|
||||
' Buttons
|
||||
DrawButtonState(stButtonWebsite, 618, 330, 96, 16, imButtonWebsite, "Website")
|
||||
DrawButtonState(stButtonSupport, 618, 348, 96, 16, imButtonSupport, "Support")
|
||||
DrawButtonState(stButtonAccount, 618, 366, 96, 16, imButtonAccount, "Account")
|
||||
DrawButtonState(stButtonEULATOS, 618, 384, 96, 16, imButtonEULATOS, "EULA/TOS")
|
||||
|
||||
' State based drawing.
|
||||
Select oPatcher.GetState()
|
||||
Case TPatcher.STATE_PATCHINFO
|
||||
DrawButtonState(stButtonCheck, 312, 441, 96, 16, imButtonCheck, "Check")
|
||||
Case TPatcher.STATE_PREPATCH
|
||||
DrawButtonState(stButtonPatch, 312, 441, 96, 16, imButtonPatch, "Patch")
|
||||
Case TPatcher.STATE_COMPLETE
|
||||
DrawButtonState(stButtonPlay, 312, 441, 96, 16, imButtonPlay, "Play")
|
||||
Case TPatcher.STATE_LAUNCHER
|
||||
DrawButtonState(stButtonRestart, 312, 441, 96, 16, imButtonRestart, "Restart")
|
||||
Case TPatcher.STATE_PATCHINFO, TPatcher.STATE_CHECKING, TPatcher.STATE_PATCHING
|
||||
DrawProgressBar(8, 442, 704, 12, oPatcher.GetProgress(), imProgressBar)
|
||||
EndSelect
|
||||
|
||||
' Draw Patcher Tasklog
|
||||
SetBlend ALPHABLEND;SetMaskColor 0, 0, 0
|
||||
SetColor 255, 255, 255;SetAlpha 0.66;SetImageFont fnSmallFont
|
||||
SetOrigin 0, 0;SetTransform 0, 1, 1
|
||||
SetViewport 11, 332, 600, 100
|
||||
|
||||
Local iLogNum:Int = 1, oLogEntry:TLink = oPatcher.m_oTaskList.FirstLink()
|
||||
While (iLogNum < 9) And (oLogEntry <> Null)
|
||||
Local stLine:String = String(oLogEntry.Value())
|
||||
If stLine[0..1] = "n" Then SetColor 204, 244, 255
|
||||
If stLine[0..1] = "e" Then SetColor 255, 222, 204
|
||||
If stLine[0..1] = "g" Then SetColor 204, 255, 204
|
||||
If stLine[0..1] = "h" Then SetColor 222, 222, 255
|
||||
DrawText stLine[1..], 11, 430 - iLogNum * 12
|
||||
|
||||
oLogEntry = oLogEntry.NextLink()
|
||||
iLogNum :+ 1
|
||||
Wend
|
||||
SetViewport 0, 0, 720, 460; SetColor 255,255,255; SetImageFont Null
|
||||
|
||||
Flip False
|
||||
Case tmPatch
|
||||
'=====> Patcher
|
||||
oPatcher.Update()
|
||||
|
||||
If oPatcher.GetShutdown() <> Null Then
|
||||
Local oProcess:TProcess = CreateProcess(oPatcher.GetShutdown())
|
||||
TProcess.ProcessList.Remove oProcess
|
||||
PostEvent(TEvent.Create(EVENT_WINDOWCLOSE, gdPatcherWindow, 0, 0, 684, 0, Null))
|
||||
EndIf
|
||||
Case tmResource
|
||||
LoadResource("GFX/LNC/LAUxPATxB.png",, imMainBackground, riMainBackground)
|
||||
LoadResource("GFX/LNC/LAUxPATxA.png",, imMainForeground, riMainForeground)
|
||||
LoadResource("GFX/LNC/BARxPROGRESS.png",, imProgressBar, riProgressBar)
|
||||
LoadResource("GFX/LNC/BTNxCLOSE.png",, imButtonClose, riButtonClose)
|
||||
LoadResource("GFX/LNC/BTNxACCOUNT.png",, imButtonAccount, riButtonAccount)
|
||||
LoadResource("GFX/LNC/BTNxWEBSITE.png",, imButtonWebsite, riButtonWebsite)
|
||||
LoadResource("GFX/LNC/BTNxSUPPORT.png",, imButtonSupport, riButtonSupport)
|
||||
LoadResource("GFX/LNC/BTNxEULATOS.png",, imButtonEULATOS, riButtonEULATOS)
|
||||
LoadResource("GFX/LNC/BTNxCHECK.png",, imButtonCheck, riButtonCheck)
|
||||
LoadResource("GFX/LNC/BTNxPATCH.png",, imButtonPatch, riButtonPatch)
|
||||
LoadResource("GFX/LNC/BTNxPLAY.png",, imButtonPlay, riButtonPlay)
|
||||
LoadFontResource("GFX/FNT/TranscencsGames.otf", 10,, fnSmallFont, rfSmallFont)
|
||||
LoadFontResource("GFX/FNT/TranscencsGames.otf", 12,, fnMediumFont, rfMediumFont)
|
||||
LoadFontResource("GFX/FNT/TranscencsGames.otf", 14,, fnBigFont, rfBigFont)
|
||||
Case gdPatcherWindow
|
||||
Select EventID()
|
||||
Case EVENT_WINDOWCLOSE
|
||||
'=====> End the patcher.
|
||||
End
|
||||
End Select
|
||||
EndSelect
|
||||
Forever
|
||||
|
||||
'=====> Functions
|
||||
Function PointInsideRect:Byte(PX:Int, PY:Int, RX:Int, RY:Int, RW:Int, RH:Int)
|
||||
If PX >= RX And PX < RX + RW Then
|
||||
If PY >= RY And PY < RY + RH Then
|
||||
Return True
|
||||
EndIf
|
||||
EndIf
|
||||
Return False
|
||||
EndFunction
|
||||
|
||||
Function GetButtonState:Byte(BS:Int, BX:Int, BY:Int, BW:Int, BH:Int, MX:Int, MY:Int, MB:Int)
|
||||
Local retVal:Int = BS
|
||||
If PointInsideRect(MX, MY, BX, BY, BW, BH) = True Then
|
||||
If BS = BTN_STT_NORMAL Then
|
||||
retVal = BTN_STT_HOVER
|
||||
ElseIf BS = BTN_STT_HOVER And MB = True Then
|
||||
retVal = BTN_STT_DOWN
|
||||
ElseIf BS = BTN_STT_DOWN And MB = False Then
|
||||
retVal = BTN_STT_ACTION
|
||||
ElseIf BS = BTN_STT_ACTION Then
|
||||
retVal = BTN_STT_HOVER
|
||||
EndIf
|
||||
Else
|
||||
retVal = BTN_STT_NORMAL
|
||||
EndIf
|
||||
Return retVal
|
||||
EndFunction
|
||||
|
||||
Function DrawBorder(X:Int, Y:Int, W:Int, H:Int)
|
||||
DrawLine X, Y, X+W, Y
|
||||
DrawLine X+W, Y, X+W, Y+H
|
||||
DrawLine X+W, Y+H, X, Y+H
|
||||
DrawLine X, Y+H, X, Y
|
||||
EndFunction
|
||||
|
||||
Function DrawButtonState(BS:Int, BX:Int, BY:Int, BW:Int, BH:Int, imButton:TImage, Text:String = "")
|
||||
SetBlend ALPHABLEND; SetAlpha 1.0; SetColor 255, 255, 255
|
||||
SetTransform 0, 1, 1;SetOrigin 0, 0; SetImageFont Null
|
||||
Select BS
|
||||
Case BTN_STT_NORMAL
|
||||
If imButton <> Null Then
|
||||
DrawSubImageRect(imButton, BX, BY, BW, BH, 0, 0, BW, BH, 0, 0, 0)
|
||||
Else
|
||||
SetColor 0, 0, 0;DrawRect BX, BY, BW, BH
|
||||
SetColor 255, 255, 255;DrawBorder(BX,BY,BW,BH)
|
||||
DrawText Text, BX + BW/2 - TextWidth(Text)/2, BY + BH/2 - TextHeight(Text)/2
|
||||
EndIf
|
||||
Case BTN_STT_HOVER
|
||||
If imButton <> Null Then
|
||||
DrawSubImageRect(imButton, BX, BY, BW, BH, 0, BH, BW, BH, 0, 0, 0)
|
||||
Else
|
||||
SetColor 0, 0, 0;DrawRect BX, BY, BW, BH
|
||||
SetColor 204, 225, 255;DrawBorder(BX,BY,BW,BH)
|
||||
DrawText Text, BX + BW/2 - TextWidth(Text)/2, BY + BH/2 - TextHeight(Text)/2
|
||||
EndIf
|
||||
Case BTN_STT_DOWN, BTN_STT_ACTION
|
||||
If imButton <> Null Then
|
||||
DrawSubImageRect(imButton, BX, BY, BW, BH, 0, BH*2, BW, BH, 0, 0, 0)
|
||||
Else
|
||||
SetColor 0, 0, 0;DrawRect BX, BY, BW, BH
|
||||
SetColor 102, 123, 188;DrawBorder(BX,BY,BW,BH)
|
||||
DrawText Text, BX + BW/2 - TextWidth(Text)/2, BY + BH/2 - TextHeight(Text)/2
|
||||
EndIf
|
||||
EndSelect
|
||||
EndFunction
|
||||
|
||||
Function DrawProgressBar(X:Int, Y:Int, W:Int, H:Int, fProgress:Float, imProgressBar:TImage)
|
||||
SetBlend ALPHABLEND; SetAlpha 1.0; SetColor 255, 255, 255
|
||||
SetTransform 0, 1, 1;SetOrigin 0, 0
|
||||
If imProgressBar = Null Then
|
||||
SetColor 255, 255, 255;DrawBorder(X,Y,W,H)
|
||||
SetColor 0, 0, 0;DrawRect X+1,Y+1,W-2,H-2
|
||||
SetColor 204, 225, 255;SetAlpha 0.75 + Sin(MilliSecs()/5) * 0.25;DrawRect X, Y, W * fProgress, H
|
||||
Else
|
||||
DrawSubImageRect(imProgressBar, X, Y, W, H, 0, 0, W, H, 0, 0, 0)
|
||||
SetAlpha 0.75 + Sin(MilliSecs()/5) * 0.25
|
||||
Local iLength:Int = (W-6) * fProgress
|
||||
DrawSubImageRect(imProgressBar, X, Y, 3, H, 0, H, 3, H, 0, 0, 0)
|
||||
DrawSubImageRect(imProgressBar, X+3, Y, iLength, H, 3, H, iLength, H, 0, 0, 0)
|
||||
DrawSubImageRect(imProgressBar, X+3+iLength, Y, 3, H, W-3, H, 3, H, 0, 0, 0)
|
||||
EndIf
|
||||
EndFunction
|
||||
|
||||
Function LoadResource(URL:String, Flags:Int = - 1, ImagePtr:TImage Var, InfoPtr:Int Var)
|
||||
Local iModTime:Int = FileTime(URL)
|
||||
If iModTime <> InfoPtr Then
|
||||
ImagePtr = LoadImage(URL, Flags)
|
||||
InfoPtr = iModTime
|
||||
EndIf
|
||||
EndFunction
|
||||
|
||||
Function LoadFontResource(URL:String, Size:Int, Style:Int = SMOOTHFONT, FontPtr:TImageFont Var, InfoPtr:Int Var)
|
||||
Local iModTime:Int = FileTime(URL)
|
||||
If iModTime <> InfoPtr Then
|
||||
FontPtr = LoadImageFont(URL, Size, Style)
|
||||
InfoPtr = iModTime
|
||||
EndIf
|
||||
EndFunction
|
||||
EndRem
|
||||
@@ -0,0 +1,300 @@
|
||||
SuperStrict
|
||||
|
||||
Import BRL.Max2D
|
||||
Import BRL.TextStream
|
||||
Import PUB.OpenGL
|
||||
Import PUB.Glew
|
||||
|
||||
Const MODE_REPEATX:Byte = $00000001 ' Repeat.
|
||||
Const MODE_REPEATY:Byte = $00000010
|
||||
Const MODE_MIRRORX:Byte = $00000100 ' Mirror every second repeat.
|
||||
Const MODE_MIRRORY:Byte = $00001000
|
||||
Const MODE_SCALEUPX:Byte = $00010000 ' Scale up to fit the destination area if the source doesn't fit exactly in.
|
||||
Const MODE_SCALEUPY:Byte = $00100000
|
||||
Const MODE_SCALEDOWNX:Byte = $01000000 ' Similar to MODE_SCALEUP*, except that it scales down to fit.
|
||||
Const MODE_SCALEDOWNY:Byte = $10000000
|
||||
Function DrawSubImageRectEx:Int(img:TImage, ..
|
||||
dstX:Float, dstY:Float, dstW:Float, dstH:Float, ..
|
||||
srcX:Float, srcY:Float, srcW:Float, srcH:Float, ..
|
||||
hndX:Float=0, hndY:Float=0, frame:Int=0, bFlags:Byte=0)
|
||||
Assert img <> Null Else "Image does Not exist"
|
||||
|
||||
Local bRepeatX:Byte = ((bFlags & MODE_REPEATX) <> 0)
|
||||
Local bRepeatY:Byte = ((bFlags & MODE_REPEATY) <> 0)
|
||||
Local bMirrorX:Byte = ((bFlags & MODE_MIRRORX) <> 0)
|
||||
Local bMirrorY:Byte = ((bFlags & MODE_MIRRORY) <> 0)
|
||||
Local bScaleUpX:Byte = ((bFlags & MODE_SCALEUPX) <> 0)
|
||||
Local bScaleUpY:Byte = ((bFlags & MODE_SCALEUPY) <> 0)
|
||||
Local bScaleDownX:Byte = ((bFlags & MODE_SCALEDOWNX) <> 0)
|
||||
Local bScaleDownY:Byte = ((bFlags & MODE_SCALEDOWNY) <> 0)
|
||||
|
||||
Local lXRepeat:Float = 1, lXScale:Float = 1
|
||||
If bRepeatX Then
|
||||
lXRepeat = dstW / srcW
|
||||
|
||||
If bScaleUpX Then
|
||||
lXRepeat = Floor(lXRepeat)
|
||||
lXScale = (dstW / srcW) / lXRepeat
|
||||
ElseIf bScaleDownX Then
|
||||
lXRepeat = Ceil(lXRepeat)
|
||||
lXScale = (dstW / srcW) / lXRepeat
|
||||
EndIf
|
||||
Else
|
||||
lXScale = dstW / srcW
|
||||
EndIf
|
||||
|
||||
Local lYRepeat:Float = 1, lYScale:Float = 1
|
||||
If bRepeatY Then
|
||||
lYRepeat = dstH / srcH
|
||||
|
||||
If bScaleUpY Then
|
||||
lYRepeat = Floor(lYRepeat)
|
||||
lYScale = (dstH / srcH) / lYRepeat
|
||||
ElseIf bScaleDownY Then
|
||||
lYRepeat = Ceil(lYRepeat)
|
||||
lYScale = (dstH / srcH) / lYRepeat
|
||||
EndIf
|
||||
Else
|
||||
lYScale = dstH / srcH
|
||||
EndIf
|
||||
|
||||
Local lXSize:Float = srcW * lXScale, lYSize:Float = srcH * lYScale
|
||||
Local lM2DScaleXOrig:Float, lM2DScaleYOrig:Float
|
||||
Local lM2DScaleX:Float, lM2DScaleY:Float
|
||||
GetScale(lM2DScaleXOrig, lM2DScaleYOrig)
|
||||
GetScale(lM2DScaleX, lM2DScaleY)
|
||||
|
||||
' Cache some variables, so that we don't waste CPU time
|
||||
Local lXRepeatFl:Int = Floor(lXRepeat), lXRepeatOverflow:Float = lXRepeat - lXRepeatFl
|
||||
Local lYRepeatFl:Int = Floor(lYRepeat), lYRepeatOverflow:Float = lYRepeat - lYRepeatFl
|
||||
For Local lYIndex:Int = 0 To lYRepeatFl
|
||||
Local lYSizeMul:Float = 1
|
||||
Local lYPos:Float = dstY + lYIndex * lYSize
|
||||
|
||||
If bMirrorY Then lM2DScaleY :* -1
|
||||
If (lYIndex = lYRepeatFl) Then lYSizeMul = lYRepeatOverflow
|
||||
|
||||
For Local lXIndex:Int = 0 To lXRepeatFl
|
||||
Local lXSizeMul:Float = 1
|
||||
Local lXPos:Float = dstX + lXIndex * lXSize
|
||||
|
||||
If bMirrorX Then lM2DScaleX :* -1
|
||||
If (lXIndex = lXRepeatFl) Then lXSizeMul = lXRepeatOverflow
|
||||
|
||||
SetScale lM2DScaleX, lM2DScaleY
|
||||
|
||||
DrawSubImageRect(img, lXPos, lYPos, lXSize * lXSizeMul, lYSize * lYSizeMul, srcX, srcY, srcW * lXSizeMul, srcH * lYSizeMul, hndX, hndY, frame)
|
||||
Next
|
||||
Next
|
||||
|
||||
SetScale(lM2DScaleXOrig, lM2DScaleYOrig)
|
||||
EndFunction
|
||||
|
||||
Function DrawTiledImage:Int(img:TImage, dstX:Float, dstY:Float, dstW:Float, dstH:Float, srcX:Float, srcY:Float, srcW:Float, srcH:Float, hndX:Float=0, hndY:Float=0, frame:Int=0, lft:Float, top:Float, rgt:Float, btm:Float, bBackground:Byte=True, bFlags:Byte=MODE_REPEATX | MODE_REPEATY)
|
||||
DrawSubImageRect(img, dstX, dstY, lft, top, srcX, srcY, lft, top, hndX, hndY, frame)
|
||||
DrawSubImageRect(img, dstX + dstW - rgt, dstY, rgt, top, srcX + srcW - rgt, srcY, rgt, top, hndX, hndY, frame)
|
||||
DrawSubImageRect(img, dstX, dstY + dstH - btm, lft, top, srcX, srcY + srcH - btm, lft, btm, hndX, hndY, frame)
|
||||
DrawSubImageRect(img, dstX + dstW - rgt, dstY + dstH - btm, rgt, top, srcX + srcW - rgt, srcY + srcH - btm, rgt, btm, hndX, hndY, frame)
|
||||
|
||||
' Left
|
||||
DrawSubImageRectEx(img, dstX, dstY + top, lft, dstH - top - btm, srcX, srcY + top, lft, srcH - top - btm, hndX, hndY, frame, bFlags)
|
||||
' Right
|
||||
DrawSubImageRectEx(img, dstX + dstW - rgt, dstY + top, rgt, dstH - top - btm, srcX + srcW - rgt, srcY + top, rgt, srcH - top - btm, hndX, hndY, frame, bFlags)
|
||||
' Top
|
||||
DrawSubImageRectEx(img, dstX + lft, dstY, dstW - lft - rgt, top, srcX + lft, srcY, srcW - lft - rgt, top, hndX, hndY, frame, bFlags)
|
||||
' Bottom
|
||||
DrawSubImageRectEx(img, dstX + lft, dstY + dstH - btm, dstW - lft - rgt, btm, srcX + lft, srcY + srcH - btm, srcW - lft - rgt, btm, hndX, hndY, frame, bFlags)
|
||||
|
||||
If bBackground Then DrawSubImageRectEx(img, dstX + lft, dstY + top, dstW - lft - rgt, dstH - top - btm, srcX + lft, srcY + top, srcW - lft - rgt, srcH - top - btm, hndX, hndY, frame, bFlags)
|
||||
End Function
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
' Max2D Shader Support ---------------------------------------------------------
|
||||
Type TShader
|
||||
' Functions ----------------------------------------------------------------
|
||||
Function Create:TShader()
|
||||
Return (New TShader)
|
||||
EndFunction
|
||||
|
||||
Function CreateVertex:TShader(oVertexCode:String)
|
||||
Local oShader:TShader = TShader.Create()
|
||||
oShader.Load(oVertexCode, True)
|
||||
Return oShader
|
||||
EndFunction
|
||||
|
||||
Function CreateFragement:TShader(oFragmentCode:String)
|
||||
Local oShader:TShader = TShader.Create()
|
||||
oShader.Load(oFragmentCode, True)
|
||||
Return oShader
|
||||
EndFunction
|
||||
|
||||
Function CreateCombined:TShader(oVertexCode:String, oFragmentCode:String)
|
||||
Local oShader:TShader = TShader.Create()
|
||||
oShader.Load(oVertexCode, True)
|
||||
oShader.Load(oFragmentCode, False)
|
||||
Return oShader
|
||||
EndFunction
|
||||
|
||||
Function CheckForErrors:Int(ShaderObject:Int, ErrorString:String Var, Compiled:Int = True)
|
||||
Local Successful:Int
|
||||
|
||||
If Compiled Then
|
||||
glGetShaderiv (ShaderObject, GL_COMPILE_STATUS, Varptr Successful)
|
||||
Else
|
||||
glGetProgramiv(ShaderObject, GL_LINK_STATUS, Varptr Successful)
|
||||
EndIf
|
||||
|
||||
If Not Successful Then
|
||||
Local ErrorLength:Int
|
||||
glGetObjectParameterivARB(ShaderObject, GL_OBJECT_INFO_LOG_LENGTH_ARB, Varptr ErrorLength)
|
||||
|
||||
Local Message:Byte Ptr = MemAlloc(ErrorLength), Dummy:Int
|
||||
|
||||
glGetInfoLogARB(ShaderObject, ErrorLength, Varptr Dummy, Message)
|
||||
|
||||
ErrorString = String.FromCString(Message)
|
||||
MemFree(Message)
|
||||
|
||||
Return True
|
||||
EndIf
|
||||
|
||||
Return False
|
||||
End Function
|
||||
|
||||
Function CheckCompatability:Int()
|
||||
Local Extensions:String = String.FromCString(Byte Ptr glGetString(GL_EXTENSIONS))
|
||||
Local GLVersion:String = String.FromCString(Byte Ptr glGetString(GL_VERSION))
|
||||
Local GLVersionInt:Int = GLVersion[.. 3].Replace(".", "").ToInt()
|
||||
|
||||
DebugLog Extensions
|
||||
If Extensions.Find("GL_ARB_shader_objects" ) >= 0 And ..
|
||||
Extensions.Find("GL_ARB_vertex_shader" ) >= 0 And ..
|
||||
Extensions.Find("GL_ARB_fragment_shader") >= 0 or GLVersionInt >= 20 Then
|
||||
Return True
|
||||
EndIf
|
||||
|
||||
Return False
|
||||
End Function
|
||||
|
||||
' Variables ----------------------------------------------------------------
|
||||
Field iProgramObject:Int ' Shader Program Object
|
||||
Field tError:String ' Shader Compile Errors & Warnings
|
||||
|
||||
' Members ------------------------------------------------------------------
|
||||
Method New()
|
||||
Self.iProgramObject = glCreateProgram()
|
||||
EndMethod
|
||||
|
||||
Method Delete()
|
||||
glDeleteProgram(Self.iProgramObject)
|
||||
EndMethod
|
||||
|
||||
'' Retrieves the error that happened during loading or linking.
|
||||
' @return <String> Error log retrieved from the
|
||||
Method GetError:String()
|
||||
Return Self.tError
|
||||
EndMethod
|
||||
|
||||
'' Loads a new shader and, if successful, attaches it to the program.
|
||||
' @param <String> tShaderCode A string containing the shader code.
|
||||
' @param <Bool> bIsVertexShader Is this code a vertex Shader
|
||||
' @return <Bool> Success
|
||||
Method Load:Byte(tShaderCode:String, bIsVertexShader:Byte = True)
|
||||
Local liShaderObject:Int
|
||||
|
||||
If tShaderCode = Null Then Return False
|
||||
If tShaderCode.length = 0 Then Return False
|
||||
|
||||
' Create a new Shader Object, either for Vertex or Fragment processing.
|
||||
If bIsVertexShader Then
|
||||
liShaderObject = glCreateShader(GL_VERTEX_SHADER)
|
||||
Else
|
||||
liShaderObject = glCreateShader(GL_FRAGMENT_SHADER)
|
||||
EndIf
|
||||
If liShaderObject = 0 Then Return False
|
||||
|
||||
' Load the shader source into the compiler.
|
||||
Local lbShaderCodePtr:Byte Ptr = tShaderCode.ToCString()
|
||||
Local liShaderLength:Int = tShaderCode.length
|
||||
glShaderSource(liShaderObject, 1, VarPtr lbShaderCodePtr, VarPtr liShaderLength)
|
||||
MemFree(lbShaderCodePtr)
|
||||
|
||||
' Compile the shader and check for errors
|
||||
glCompileShader(liShaderObject)
|
||||
If (TShader.CheckForErrors(liShaderObject, Self.tError, True) = False) Then
|
||||
glAttachShader(iProgramObject, liShaderObject)
|
||||
glDeleteShader(liShaderObject)
|
||||
Return True
|
||||
EndIf
|
||||
|
||||
glDeleteShader(liShaderObject)
|
||||
EndMethod
|
||||
|
||||
'' Links the attached shaders to the program, if successful.
|
||||
' @return <Bool> Success
|
||||
Method Link:Byte()
|
||||
glLinkProgramARB(Self.iProgramObject)
|
||||
Return (TShader.CheckForErrors(Self.iProgramObject, Self.tError, False) = False)
|
||||
EndMethod
|
||||
|
||||
'' Enable the this program and disable all other programs.
|
||||
' @return <Bool> Success
|
||||
Method Enable:Byte()
|
||||
glUseProgramObjectARB(Self.iProgramObject)
|
||||
Return (TShader.CheckForErrors(Self.iProgramObject, Self.tError, False) = False)
|
||||
End Method
|
||||
|
||||
'' Disable the all programs.
|
||||
' @return <Bool> Success
|
||||
Method Disable:Byte()
|
||||
glUseProgramObjectARB(0)
|
||||
Return (TShader.CheckForErrors(Self.iProgramObject, Self.tError, False) = False)
|
||||
End Method
|
||||
|
||||
'' Uniform Management
|
||||
Method GetUniformLocation:Int(tUniform:String)
|
||||
Return glGetUniformLocationARB(Self.iProgramObject, tUniform)
|
||||
End Method
|
||||
|
||||
Method SetUniform1F(tUniform:String, fValue1:Float)
|
||||
glUniform1f(GetUniformLocation(tUniform), fValue1)
|
||||
EndMethod
|
||||
Method SetUniform2F(tUniform:String, fValue1:Float, fValue2:Float)
|
||||
glUniform2f(GetUniformLocation(tUniform), fValue1, fValue2)
|
||||
EndMethod
|
||||
Method SetUniform3F(tUniform:String, fValue1:Float, fValue2:Float, fValue3:Float)
|
||||
glUniform3f(GetUniformLocation(tUniform), fValue1, fValue2, fValue3)
|
||||
EndMethod
|
||||
Method SetUniform4F(tUniform:String, fValue1:Float, fValue2:Float, fValue3:Float, fValue4:Float)
|
||||
glUniform4f(GetUniformLocation(tUniform), fValue1, fValue2, fValue3, fValue4)
|
||||
EndMethod
|
||||
|
||||
Method SetUniform1I(tUniform:String, iValue1:Int)
|
||||
glUniform1i(GetUniformLocation(tUniform), iValue1)
|
||||
EndMethod
|
||||
Method SetUniform2I(tUniform:String, iValue1:Int, iValue2:Int)
|
||||
glUniform2i(GetUniformLocation(tUniform), iValue1, iValue2)
|
||||
EndMethod
|
||||
Method SetUniform3I(tUniform:String, iValue1:Int, iValue2:Int, iValue3:Int)
|
||||
glUniform3i(GetUniformLocation(tUniform), iValue1, iValue2, iValue3)
|
||||
EndMethod
|
||||
Method SetUniform4I(tUniform:String, iValue1:Int, iValue2:Int, iValue3:Int, iValue4:Int)
|
||||
glUniform4i(GetUniformLocation(tUniform), iValue1, iValue2, iValue3, iValue4)
|
||||
EndMethod
|
||||
|
||||
Method SetUniform1UI(tUniform:String, iValue1:Int)
|
||||
glUniform1ui(GetUniformLocation(tUniform), iValue1)
|
||||
EndMethod
|
||||
Method SetUniform2UI(tUniform:String, iValue1:Int, iValue2:Int)
|
||||
glUniform2ui(GetUniformLocation(tUniform), iValue1, iValue2)
|
||||
EndMethod
|
||||
Method SetUniform3UI(tUniform:String, iValue1:Int, iValue2:Int, iValue3:Int)
|
||||
glUniform3ui(GetUniformLocation(tUniform), iValue1, iValue2, iValue3)
|
||||
EndMethod
|
||||
Method SetUniform4UI(tUniform:String, iValue1:Int, iValue2:Int, iValue3:Int, iValue4:Int)
|
||||
glUniform4ui(GetUniformLocation(tUniform), iValue1, iValue2, iValue3, iValue4)
|
||||
EndMethod
|
||||
EndType
|
||||
@@ -0,0 +1,9 @@
|
||||
Sirius Online Launcher
|
||||
=======================
|
||||
|
||||
Originally supposed to be the official launcher, it was later dumped as contact died off to the lead developer due to him going from 100mbit to potato quality internet. He didn't like the idea that it would check for an update and download it, instead of letting you play directly. Neither did he like the way the updates were handled, hash based checking for new files seemed to not go over well to him.
|
||||
The project contains some things from the forums for BlitzMax, as well as my try at adding some extra support to Max2D. Remember Blitz3D? The 2D system in BlitzMax is basically the same, except worse.
|
||||
|
||||
License
|
||||
=======
|
||||
Sirius Online Launcher by Michael Fabian Dirks is licensed under the Creative Commons Attribution-ShareAlike 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/4.0/.
|
||||
@@ -0,0 +1,285 @@
|
||||
Strict
|
||||
|
||||
Import BRL.Retro
|
||||
|
||||
Function MD5$(in:String Var)
|
||||
Local h0 = $67452301, h1 = $EFCDAB89, h2 = $98BADCFE, h3 = $10325476
|
||||
|
||||
Local r[] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,..
|
||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,..
|
||||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,..
|
||||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]
|
||||
|
||||
Local k[] = [$D76AA478, $E8C7B756, $242070DB, $C1BDCEEE, $F57C0FAF, $4787C62A,..
|
||||
$A8304613, $FD469501, $698098D8, $8B44F7AF, $FFFF5BB1, $895CD7BE,..
|
||||
$6B901122, $FD987193, $A679438E, $49B40821, $F61E2562, $C040B340,..
|
||||
$265E5A51, $E9B6C7AA, $D62F105D, $02441453, $D8A1E681, $E7D3FBC8,..
|
||||
$21E1CDE6, $C33707D6, $F4D50D87, $455A14ED, $A9E3E905, $FCEFA3F8,..
|
||||
$676F02D9, $8D2A4C8A, $FFFA3942, $8771F681, $6D9D6122, $FDE5380C,..
|
||||
$A4BEEA44, $4BDECFA9, $F6BB4B60, $BEBFBC70, $289B7EC6, $EAA127FA,..
|
||||
$D4EF3085, $04881D05, $D9D4D039, $E6DB99E5, $1FA27CF8, $C4AC5665,..
|
||||
$F4292244, $432AFF97, $AB9423A7, $FC93A039, $655B59C3, $8F0CCC92,..
|
||||
$FFEFF47D, $85845DD1, $6FA87E4F, $FE2CE6E0, $A3014314, $4E0811A1,..
|
||||
$F7537E82, $BD3AF235, $2AD7D2BB, $EB86D391]
|
||||
|
||||
Local intCount = (((in$.length + 8) Shr 6) + 1) Shl 4
|
||||
Local data[intCount]
|
||||
|
||||
For Local c=0 Until in$.length
|
||||
data[c Shr 2] = data[c Shr 2] | ((in$[c] & $FF) Shl ((c & 3) Shl 3))
|
||||
Next
|
||||
data[in$.length Shr 2] = data[in$.length Shr 2] | ($80 Shl ((in$.length & 3) Shl 3))
|
||||
data[data.length - 2] = (Long(in$.length) * 8) & $FFFFFFFF
|
||||
data[data.length - 1] = (Long(in$.length) * 8) Shr 32
|
||||
|
||||
For Local chunkStart=0 Until intCount Step 16
|
||||
Local a = h0, b = h1, c = h2, d = h3
|
||||
|
||||
For Local i=0 To 15
|
||||
Local f = d ~ (b & (c ~ d))
|
||||
Local t = d
|
||||
|
||||
d = c ; c = b
|
||||
b = Rol((a + f + k[i] + data[chunkStart + i]), r[i]) + b
|
||||
a = t
|
||||
Next
|
||||
|
||||
For Local i=16 To 31
|
||||
Local f = c ~ (d & (b ~ c))
|
||||
Local t = d
|
||||
|
||||
d = c ; c = b
|
||||
b = Rol((a + f + k[i] + data[chunkStart + (((5 * i) + 1) & 15)]), r[i]) + b
|
||||
a = t
|
||||
Next
|
||||
|
||||
For Local i=32 To 47
|
||||
Local f = b ~ c ~ d
|
||||
Local t = d
|
||||
|
||||
d = c ; c = b
|
||||
b = Rol((a + f + k[i] + data[chunkStart + (((3 * i) + 5) & 15)]), r[i]) + b
|
||||
a = t
|
||||
Next
|
||||
|
||||
For Local i=48 To 63
|
||||
Local f = c ~ (b | ~d)
|
||||
Local t = d
|
||||
|
||||
d = c ; c = b
|
||||
b = Rol((a + f + k[i] + data[chunkStart + ((7 * i) & 15)]), r[i]) + b
|
||||
a = t
|
||||
Next
|
||||
|
||||
h0 :+ a ; h1 :+ b
|
||||
h2 :+ c ; h3 :+ d
|
||||
Next
|
||||
|
||||
Return (LEHex(h0) + LEHex(h1) + LEHex(h2) + LEHex(h3))
|
||||
End Function
|
||||
|
||||
Function MD5Bank:String(inbank:TBank Var)
|
||||
Local h0 = $67452301, h1 = $EFCDAB89, h2 = $98BADCFE, h3 = $10325476
|
||||
|
||||
Local r[] = [7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,..
|
||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,..
|
||||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,..
|
||||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21]
|
||||
|
||||
Local k[] = [$D76AA478, $E8C7B756, $242070DB, $C1BDCEEE, $F57C0FAF, $4787C62A,..
|
||||
$A8304613, $FD469501, $698098D8, $8B44F7AF, $FFFF5BB1, $895CD7BE,..
|
||||
$6B901122, $FD987193, $A679438E, $49B40821, $F61E2562, $C040B340,..
|
||||
$265E5A51, $E9B6C7AA, $D62F105D, $02441453, $D8A1E681, $E7D3FBC8,..
|
||||
$21E1CDE6, $C33707D6, $F4D50D87, $455A14ED, $A9E3E905, $FCEFA3F8,..
|
||||
$676F02D9, $8D2A4C8A, $FFFA3942, $8771F681, $6D9D6122, $FDE5380C,..
|
||||
$A4BEEA44, $4BDECFA9, $F6BB4B60, $BEBFBC70, $289B7EC6, $EAA127FA,..
|
||||
$D4EF3085, $04881D05, $D9D4D039, $E6DB99E5, $1FA27CF8, $C4AC5665,..
|
||||
$F4292244, $432AFF97, $AB9423A7, $FC93A039, $655B59C3, $8F0CCC92,..
|
||||
$FFEFF47D, $85845DD1, $6FA87E4F, $FE2CE6E0, $A3014314, $4E0811A1,..
|
||||
$F7537E82, $BD3AF235, $2AD7D2BB, $EB86D391]
|
||||
|
||||
Local intCount = (((inbank.Size() + 8) Shr 6) + 1) Shl 4
|
||||
Local data[intCount]
|
||||
Local inPtr:Byte Ptr = inbank.Buf()
|
||||
|
||||
For Local c=0 Until inbank.Size()
|
||||
data[c Shr 2] = data[c Shr 2] | ((inPtr[c] & $FF) Shl ((c & 3) Shl 3))
|
||||
Next
|
||||
|
||||
data[inbank.Size() Shr 2] = data[inbank.Size() Shr 2] | ($80 Shl ((inbank.Size() & 3) Shl 3))
|
||||
data[data.length - 2] = (Long(inbank.Size()) * 8) & $FFFFFFFF
|
||||
data[data.length - 1] = (Long(inbank.Size()) * 8) Shr 32
|
||||
|
||||
For Local chunkStart=0 Until intCount Step 16
|
||||
Local a = h0, b = h1, c = h2, d = h3
|
||||
|
||||
For Local i=0 To 15
|
||||
Local f = d ~ (b & (c ~ d))
|
||||
Local t = d
|
||||
|
||||
d = c ; c = b
|
||||
b = Rol((a + f + k[i] + data[chunkStart + i]), r[i]) + b
|
||||
a = t
|
||||
Next
|
||||
|
||||
For Local i=16 To 31
|
||||
Local f = c ~ (d & (b ~ c))
|
||||
Local t = d
|
||||
|
||||
d = c ; c = b
|
||||
b = Rol((a + f + k[i] + data[chunkStart + (((5 * i) + 1) & 15)]), r[i]) + b
|
||||
a = t
|
||||
Next
|
||||
|
||||
For Local i=32 To 47
|
||||
Local f = b ~ c ~ d
|
||||
Local t = d
|
||||
|
||||
d = c ; c = b
|
||||
b = Rol((a + f + k[i] + data[chunkStart + (((3 * i) + 5) & 15)]), r[i]) + b
|
||||
a = t
|
||||
Next
|
||||
|
||||
For Local i=48 To 63
|
||||
Local f = c ~ (b | ~d)
|
||||
Local t = d
|
||||
|
||||
d = c ; c = b
|
||||
b = Rol((a + f + k[i] + data[chunkStart + ((7 * i) & 15)]), r[i]) + b
|
||||
a = t
|
||||
Next
|
||||
|
||||
h0 :+ a ; h1 :+ b
|
||||
h2 :+ c ; h3 :+ d
|
||||
Next
|
||||
|
||||
Return (LEHex(h0) + LEHex(h1) + LEHex(h2) + LEHex(h3))
|
||||
End Function
|
||||
|
||||
Function SHA1$(in$)
|
||||
Local h0 = $67452301, h1 = $EFCDAB89, h2 = $98BADCFE, h3 = $10325476, h4 = $C3D2E1F0
|
||||
|
||||
Local intCount = (((in$.length + 8) Shr 6) + 1) Shl 4
|
||||
Local data[intCount]
|
||||
|
||||
For Local c=0 Until in$.length
|
||||
data[c Shr 2] = (data[c Shr 2] Shl 8) | (in$[c] & $FF)
|
||||
Next
|
||||
data[in$.length Shr 2] = ((data[in$.length Shr 2] Shl 8) | $80) Shl ((3 - (in$.length & 3)) Shl 3)
|
||||
data[data.length - 2] = (Long(in$.length) * 8) Shr 32
|
||||
data[data.length - 1] = (Long(in$.length) * 8) & $FFFFFFFF
|
||||
|
||||
For Local chunkStart=0 Until intCount Step 16
|
||||
Local a = h0, b = h1, c = h2, d = h3, e = h4
|
||||
|
||||
Local w[] = data[chunkStart..chunkStart + 16]
|
||||
w = w[..80]
|
||||
|
||||
For Local i=16 To 79
|
||||
w[i] = Rol(w[i - 3] ~ w[i - 8] ~ w[i - 14] ~ w[i - 16], 1)
|
||||
Next
|
||||
|
||||
For Local i=0 To 19
|
||||
Local t = Rol(a, 5) + (d ~ (b & (c ~ d))) + e + $5A827999 + w[i]
|
||||
|
||||
e = d ; d = c
|
||||
c = Rol(b, 30)
|
||||
b = a ; a = t
|
||||
Next
|
||||
|
||||
For Local i=20 To 39
|
||||
Local t = Rol(a, 5) + (b ~ c ~ d) + e + $6ED9EBA1 + w[i]
|
||||
|
||||
e = d ; d = c
|
||||
c = Rol(b, 30)
|
||||
b = a ; a = t
|
||||
Next
|
||||
|
||||
For Local i=40 To 59
|
||||
Local t = Rol(a, 5) + ((b & c) | (d & (b | c))) + e + $8F1BBCDC + w[i]
|
||||
|
||||
e = d ; d = c
|
||||
c = Rol(b, 30)
|
||||
b = a ; a = t
|
||||
Next
|
||||
|
||||
For Local i=60 To 79
|
||||
Local t = Rol(a, 5) + (b ~ c ~ d) + e + $CA62C1D6 + w[i]
|
||||
|
||||
e = d ; d = c
|
||||
c = Rol(b, 30)
|
||||
b = a ; a = t
|
||||
Next
|
||||
|
||||
h0 :+ a ; h1 :+ b ; h2 :+ c
|
||||
h3 :+ d ; h4 :+ e
|
||||
Next
|
||||
|
||||
Return (Hex(h0) + Hex(h1) + Hex(h2) + Hex(h3) + Hex(h4)).ToLower()
|
||||
End Function
|
||||
|
||||
Function SHA256$(in$)
|
||||
Local h0 = $6A09E667, h1 = $BB67AE85, h2 = $3C6EF372, h3 = $A54FF53A
|
||||
Local h4 = $510E527F, h5 = $9B05688C, h6 = $1F83D9AB, h7 = $5BE0CD19
|
||||
|
||||
Local k[] = [$428A2F98, $71374491, $B5C0FBCF, $E9B5DBA5, $3956C25B, $59F111F1,..
|
||||
$923F82A4, $AB1C5ED5, $D807AA98, $12835B01, $243185BE, $550C7DC3,..
|
||||
$72BE5D74, $80DEB1FE, $9BDC06A7, $C19BF174, $E49B69C1, $EFBE4786,..
|
||||
$0FC19DC6, $240CA1CC, $2DE92C6F, $4A7484AA, $5CB0A9DC, $76F988DA,..
|
||||
$983E5152, $A831C66D, $B00327C8, $BF597FC7, $C6E00BF3, $D5A79147,..
|
||||
$06CA6351, $14292967, $27B70A85, $2E1B2138, $4D2C6DFC, $53380D13,..
|
||||
$650A7354, $766A0ABB, $81C2C92E, $92722C85, $A2BFE8A1, $A81A664B,..
|
||||
$C24B8B70, $C76C51A3, $D192E819, $D6990624, $F40E3585, $106AA070,..
|
||||
$19A4C116, $1E376C08, $2748774C, $34B0BCB5, $391C0CB3, $4ED8AA4A,..
|
||||
$5B9CCA4F, $682E6FF3, $748F82EE, $78A5636F, $84C87814, $8CC70208,..
|
||||
$90BEFFFA, $A4506CEB, $BEF9A3F7, $C67178F2]
|
||||
|
||||
Local intCount = (((in$.length + 8) Shr 6) + 1) Shl 4
|
||||
Local data[intCount]
|
||||
|
||||
For Local c=0 Until in$.length
|
||||
data[c Shr 2] = (data[c Shr 2] Shl 8) | (in$[c] & $FF)
|
||||
Next
|
||||
data[in$.length Shr 2] = ((data[in$.length Shr 2] Shl 8) | $80) Shl ((3 - (in$.length & 3)) Shl 3)
|
||||
data[data.length - 2] = (Long(in$.length) * 8) Shr 32
|
||||
data[data.length - 1] = (Long(in$.length) * 8) & $FFFFFFFF
|
||||
|
||||
For Local chunkStart=0 Until intCount Step 16
|
||||
Local a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7
|
||||
|
||||
Local w[] = data[chunkStart..chunkStart + 16]
|
||||
w = w[..64]
|
||||
|
||||
For Local i=16 To 63
|
||||
w[i] = w[i - 16] + (Ror(w[i - 15], 7) ~ Ror(w[i - 15], 18) ~ (w[i - 15] Shr 3))..
|
||||
+ w[i - 7] + (Ror(w[i - 2], 17) ~ Ror(w[i - 2], 19) ~ (w[i - 2] Shr 10))
|
||||
Next
|
||||
|
||||
For Local i=0 To 63
|
||||
Local t0 = (Ror(a, 2) ~ Ror(a, 13) ~ Ror(a, 22)) + ((a & b) | (b & c) | (c & a))
|
||||
Local t1 = h + (Ror(e, 6) ~ Ror(e, 11) ~ Ror(e, 25)) + ((e & f) | (~e & g)) + k[i] + w[i]
|
||||
|
||||
h = g ; g = f ; f = e ; e = d + t1
|
||||
d = c ; c = b ; b = a ; a = t0 + t1
|
||||
Next
|
||||
|
||||
h0 :+ a ; h1 :+ b ; h2 :+ c ; h3 :+ d
|
||||
h4 :+ e ; h5 :+ f ; h6 :+ g ; h7 :+ h
|
||||
Next
|
||||
|
||||
Return (Hex(h0) + Hex(h1) + Hex(h2) + Hex(h3) + Hex(h4) + Hex(h5) + Hex(h6) + Hex(h7)).ToLower()
|
||||
End Function
|
||||
|
||||
Function Rol(val, shift)
|
||||
Return (val Shl shift) | (val Shr (32 - shift))
|
||||
End Function
|
||||
|
||||
Function Ror(val, shift)
|
||||
Return (val Shr shift) | (val Shl (32 - shift))
|
||||
End Function
|
||||
|
||||
Function LEHex$(val)
|
||||
Local out$ = Hex(val)
|
||||
|
||||
Return out$[6..8] + out$[4..6] + out$[2..4] + out$[0..2]
|
||||
End Function
|
||||
@@ -0,0 +1,184 @@
|
||||
SuperStrict
|
||||
|
||||
Import BRL.LinkedList
|
||||
Import BRL.Map
|
||||
Import BRL.Graphics
|
||||
Import BRL.GLGraphics
|
||||
Import BRL.Max2D
|
||||
Import BRL.GLMax2D
|
||||
Import BRL.Pixmap
|
||||
Import Pub.OpenGL
|
||||
Import "Max2DExtended.bmx"
|
||||
|
||||
Import BRL.BMPLoader
|
||||
Import BRL.JPGLoader
|
||||
Import BRL.PNGLoader
|
||||
Import BRL.TGALoader
|
||||
|
||||
'-------------------------------------------------------------------------------
|
||||
Type TGUI
|
||||
' Variables ----------------------------------------------------------------
|
||||
' Skinning
|
||||
Field oSkinImageSet:TPixmap = Null
|
||||
' GUI Area
|
||||
Field oRootGadget:TGUIGadget = New TGUIGadget
|
||||
|
||||
' Functions ----------------------------------------------------------------
|
||||
Function Create:TGUI(X:Float, Y:Float, W:Float, H:Float, Skin:Object)
|
||||
Local loGUI:TGUI = New TGUI
|
||||
|
||||
Return loGUI
|
||||
EndFunction
|
||||
|
||||
' Members ------------------------------------------------------------------
|
||||
Method New()
|
||||
Self.oRootGadget = (New TGUIGadget)
|
||||
EndMethod
|
||||
|
||||
Method Destroy()
|
||||
Self.oRootGadget = Null
|
||||
EndMethod
|
||||
|
||||
Method Update:Int(fDelta:Float)
|
||||
oRootGadget.Update(fDelta)
|
||||
EndMethod
|
||||
|
||||
Method Render:Int(fDelta:Float)
|
||||
oRootGadget.Render(fDelta)
|
||||
EndMethod
|
||||
|
||||
'' Changes the
|
||||
Method SetRootGadget:TGUIGadget(oRootGadget:TGUIGadget)
|
||||
If oRootGadget = Null Or oRootGadget.Insane() Then Return Null
|
||||
|
||||
Local loRootWindow:TGUIGadget = Self.oRootGadget
|
||||
Self.oRootGadget = oRootGadget
|
||||
Return loRootWindow
|
||||
EndMethod
|
||||
|
||||
Method GetRootGadget:TGUIGadget()
|
||||
Return oRootGadget
|
||||
EndMethod
|
||||
EndType
|
||||
|
||||
'-------------------------------------------------------------------------------
|
||||
Type TGUIGadget
|
||||
' Constants ----------------------------------------------------------------
|
||||
Const COORD_ABSOLUTE:Byte = 0
|
||||
Const COORD_RELATIVE:Byte = 1
|
||||
|
||||
' Variables ----------------------------------------------------------------
|
||||
' Gadget Coordinates
|
||||
Field bLocalCoordType:Byte[] = New Byte[4]
|
||||
Field dLocalCoord:Double[] = New Double[4]
|
||||
Field dCoord:Double[] = New Double[4]
|
||||
' Parent and Childs
|
||||
Field oParentGUI:TGUI = Null
|
||||
Field oParent:TGUIGadget = Null
|
||||
Field oChildList:TList = New TList
|
||||
|
||||
' Members ------------------------------------------------------------------
|
||||
'' Deconstructor for TGUIGadget
|
||||
' Automatically removed itself from the parent and releases all pointers to chils
|
||||
Method Delete()
|
||||
' Unregister from parent gadget and release all pointers to childs.
|
||||
SetParent(Null)
|
||||
Self.oChildList.Clear()
|
||||
|
||||
' Destroy objects in reverse order.
|
||||
Self.bCoordType = Null
|
||||
Self.dCoord = Null
|
||||
Self.dLocalCoord = Null
|
||||
Self.oChildList = Null
|
||||
EndMethod
|
||||
|
||||
'' Checks if the Gadget went insane due to invalid usage or other influence.
|
||||
' @return <Bool> True if the TGUIGadget went insane, otherwise false.
|
||||
Method Insane:Byte()
|
||||
If Self.bCoordType = Null Then Return True
|
||||
If Self.dCoord = Null Then Return True
|
||||
If Self.dLocalCoord = Null Then Return True
|
||||
If Self.oChildList = Null Then Return True
|
||||
EndMethod
|
||||
|
||||
'' Updates the GUIGadget and any other objects in it.
|
||||
' @return <Int>
|
||||
Method Update:Int(fDelta:Float)
|
||||
EndMethod
|
||||
|
||||
Method Render:Int(fDelta:Float)
|
||||
EndMethod
|
||||
|
||||
' Parent Management
|
||||
Method SetParent(oParent:TGUIGadget)
|
||||
If Self.oParent <> Null Then Self.oParent.RemoveChild(Self)
|
||||
If oParent <> Null Then oParent.AddChild(Self)
|
||||
EndMethod
|
||||
|
||||
Method GetParent:TGUIGadget()
|
||||
Return Self.oParent
|
||||
EndMethod
|
||||
|
||||
' Child Management
|
||||
Method IsChild:Int(oChild:TGUIGadget)
|
||||
If oChild = Null Then Return False
|
||||
Return Self.oChildList.Contains(oChild)
|
||||
EndMethod
|
||||
|
||||
Method AddChild:Int(oChild:TGUIGadget)
|
||||
If oChild <> Null Then
|
||||
If IsChild(oChild) Then
|
||||
Return True
|
||||
Else
|
||||
Return (Self.oChildList.AddLast(oChild) <> Null)
|
||||
EndIf
|
||||
EndIf
|
||||
EndMethod
|
||||
|
||||
Method RemoveChild:Int(oChild:TGUIGadget)
|
||||
If oChild <> Null Then
|
||||
If IsChild(oChild) Then
|
||||
Return True
|
||||
Else
|
||||
Return Self.oChildList.Remove(oChild)
|
||||
EndIf
|
||||
EndIf
|
||||
EndMethod
|
||||
|
||||
Method GetChildAtIndex:TGUIGadget(iIndex:Int)
|
||||
If iIndex <> -1 Then
|
||||
Local liChildCount:Int = Self.oChildList.Count()
|
||||
If iIndex >= 0 And iIndex < liChildCount Then
|
||||
Return Self.oChildList.ValueAtIndex(iIndex)
|
||||
Else
|
||||
Return Null
|
||||
EndIf
|
||||
Else
|
||||
Return Self.oChildList.Last()
|
||||
EndIf
|
||||
EndMethod
|
||||
|
||||
Method SetChildIndex:Int(oChild:TGUIGadget, iIndex:Int)
|
||||
If oChild <> Null Then
|
||||
If IsChild(oChild) Then
|
||||
Local liChildCount:Int = Self.oChildList.Count()
|
||||
|
||||
If iIndex >= 0 And iIndex < liChildCount Then
|
||||
'Local loChild:TGUIGadget = Self.oChildList.ValueAtIndex(iIndex)
|
||||
'Local lChild:TGUIGadget = Self.oChildList.ValueAtIndex(iIndex)
|
||||
'Self.oChildList.Insert
|
||||
EndIf
|
||||
EndIf
|
||||
EndIf
|
||||
EndMethod
|
||||
|
||||
' Signal Handlers ----------------------------------------------------------
|
||||
|
||||
EndType
|
||||
|
||||
'-------------------------------------------------------------------------------
|
||||
Public
|
||||
Type TGUIWindow Extends TGUIGadget
|
||||
'-------------------------------------------------------------------------------
|
||||
|
||||
EndType
|
||||
@@ -0,0 +1,435 @@
|
||||
SuperStrict
|
||||
|
||||
Import BaH.libcurl
|
||||
Import BRL.Bank
|
||||
Import BRL.FileSystem
|
||||
Import BRL.LinkedList
|
||||
Import BRL.StandardIO
|
||||
Import BRL.Stream
|
||||
Import BRL.Timer
|
||||
Import "Clock.c"
|
||||
Import "Digest.bmx"
|
||||
|
||||
Type TPatcher
|
||||
Const STATE_DEFAULT:Byte = 0
|
||||
Const STATE_PATCHINFO:Byte = 1
|
||||
Const STATE_CHECKING:Byte = 2
|
||||
Const STATE_PREPATCH:Byte = 3
|
||||
Const STATE_PATCHING:Byte = 4
|
||||
Const STATE_COMPLETE:Byte = 5
|
||||
Const STATE_LAUNCHER:Byte = 6
|
||||
Const SSTATE_ENTER:Byte = 0
|
||||
Const SSTATE_WORK:Byte = 1
|
||||
Const SSTATE_LEAVE:Byte = 2
|
||||
Const SERVER:String = "http://sirius-online.us.to/patch/"
|
||||
|
||||
' State-based Patcher
|
||||
Field m_bState:Byte = TPatcher.STATE_DEFAULT
|
||||
Field m_bSubState:Byte = TPatcher.SSTATE_ENTER
|
||||
|
||||
' lib/cURL is used for downloading of data.
|
||||
Field m_oCurlMulti:TCurlMulti = Null
|
||||
Field m_oCurl:TCurlEasy = Null
|
||||
Field m_fCurlProgress:Float
|
||||
|
||||
' State: All
|
||||
Field m_oTaskList:TList = New TList
|
||||
Field m_fProgress:Float = 0
|
||||
|
||||
' State: Patchinfo, Checking, Patching
|
||||
Field m_oFileHashList:TList = New TList
|
||||
Field m_iFileCount:Int = 0
|
||||
|
||||
' State: Checking, Patching
|
||||
Field m_oFileLoader:TAsyncLoader = New TAsyncLoader
|
||||
Field m_oFileHashPair:TFileHash = Null
|
||||
|
||||
' State: Patching
|
||||
Field m_oFileList:TList = New TList
|
||||
Field m_oFile:String, m_oFileDL:String
|
||||
Field m_oFileStream:TStream
|
||||
|
||||
' Construction
|
||||
Method New()
|
||||
EndMethod
|
||||
|
||||
Function Create:TPatcher()
|
||||
Local oPatcher:TPatcher = New TPatcher
|
||||
Return oPatcher
|
||||
EndFunction
|
||||
|
||||
' Deconstruction
|
||||
Method Destroy()
|
||||
m_oCurlMulti.multiCleanup()
|
||||
m_oCurl.cleanup()
|
||||
EndMethod
|
||||
|
||||
|
||||
' Basically the Main Loop of the Patcher, handles everything. Call GetShutdown:String() if you want to know when the patcher is telling you to run an executable and close.
|
||||
Method Update()
|
||||
' Check
|
||||
Select m_bState
|
||||
Case TPatcher.STATE_DEFAULT
|
||||
If m_bSubState = TPatcher.SSTATE_ENTER Then
|
||||
m_oCurlMulti = TCurlMulti.Create()
|
||||
m_oCurl = m_oCurlMulti.newEasy()
|
||||
m_oCurl.setOptInt(CURLOPT_FOLLOWLOCATION, 1)
|
||||
m_oCurl.setOptInt(CURLOPT_CRLF, False)
|
||||
m_oCurl.setOptString(CURLOPT_USERAGENT, "Sirius Online Launcher")
|
||||
m_oCurl.setOptString(CURLOPT_REFERER, TPatcher.SERVER)
|
||||
m_oCurl.setOptString(CURLOPT_URL, TPatcher.SERVER + "info")
|
||||
m_oCurl.setProgressCallback(TPatcher.ProgressCallback, Self)
|
||||
m_oCurl.setWriteString()
|
||||
m_oTaskList.AddFirst("n[WAIT] Getting patch information...")
|
||||
|
||||
m_bSubState = TPatcher.SSTATE_WORK
|
||||
EndIf
|
||||
|
||||
If m_bSubState = TPatcher.SSTATE_WORK Then
|
||||
Local iResult:Int = Perform()
|
||||
|
||||
m_fProgress = m_fCurlProgress
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("g[" + RSet(String(Int(m_fProgress * 100)), 3) + "%] Retrieving patch information...")
|
||||
|
||||
If iResult = CURLM_OK Then
|
||||
If m_fCurlProgress = 1.0 And m_iCurlMultiHandles = 0 Then
|
||||
m_bSubState = TPatcher.SSTATE_LEAVE
|
||||
EndIf
|
||||
Else
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("g[FAIL] Retrieving patch information... ("+CurlError(iResult)+")")
|
||||
SetState(TPatcher.STATE_COMPLETE)
|
||||
EndIf
|
||||
EndIf
|
||||
|
||||
If m_bSubState = TPatcher.SSTATE_LEAVE Then
|
||||
m_oCurlMulti.multiRemove(m_oCurl)
|
||||
m_oCurlMulti.multiCleanup()
|
||||
m_oCurlMulti = Null
|
||||
|
||||
Local oCurlRCode:Int = m_oCurl.getInfo().responseCode()
|
||||
Local stResult:String = m_oCurl.toString()
|
||||
m_oCurl.cleanup()
|
||||
m_oCurl = Null
|
||||
|
||||
If oCurlRCode <> 404 Then
|
||||
m_oFileHashList.Clear()
|
||||
If stResult.length > 0 Then
|
||||
Local stFileHashArr:String[] = stResult.Split("~n")
|
||||
For Local stFileHashPair:String = EachIn stFileHashArr
|
||||
If stFileHashPair.length > 0 And stFileHashPair[0..1] <> "#" Then ' Ignore Comments
|
||||
Local stPairArr:String[] = stFileHashPair.Split(":")
|
||||
m_oFileHashList.AddLast(TFileHash.Create(stPairArr[0], stPairArr[1]))
|
||||
EndIf
|
||||
Next
|
||||
m_iFileCount = m_oFileHashList.Count()
|
||||
m_oFileList.Clear()
|
||||
SetState(TPatcher.STATE_PATCHINFO) ' Got Patchinfo, and it had information.
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("g[ OK ] Retrieving patch information... done.")
|
||||
Else
|
||||
SetState(TPatcher.STATE_COMPLETE)
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("e[FAIL] Retrieving patch information... invalid information file.")
|
||||
EndIf
|
||||
Else
|
||||
SetState(TPatcher.STATE_COMPLETE)
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("e[FAIL] Retrieving patch information... file not found.")
|
||||
EndIf
|
||||
EndIf
|
||||
Case TPatcher.STATE_CHECKING
|
||||
If m_bSubState = TPatcher.SSTATE_ENTER Then ' Used to load a new File
|
||||
m_oFileHashPair = TFileHash(m_oFileHashList.RemoveFirst())
|
||||
If m_oFileHashPair <> Null Then
|
||||
m_oFileLoader.Initialize(m_oFileHashPair.stName)
|
||||
m_oTaskList.AddFirst("n[WAIT] Checking '" + m_oFileHashPair.stName + "'...")
|
||||
|
||||
m_bSubState = TPatcher.SSTATE_WORK
|
||||
Else
|
||||
m_bSubState = TPatcher.SSTATE_LEAVE
|
||||
EndIf
|
||||
EndIf
|
||||
|
||||
If m_bSubState = TPatcher.SSTATE_WORK Then
|
||||
If m_oFileLoader.m_bComplete = 0 Then
|
||||
m_oFileLoader.Process(2, 1024)
|
||||
m_fProgress = ((m_iFileCount - (m_oFileHashList.Count() + 1)) / Float(m_iFileCount)) + m_oFileLoader.m_fProgress * (1.0 / m_iFileCount)
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("g[" + RSet(String(Int(m_fProgress * 100)), 3) + "%] Checking '" + m_oFileHashPair.stName + "'...")
|
||||
Else
|
||||
If m_oFileLoader.m_bComplete = 1
|
||||
If m_oFileLoader.m_oBank <> Null Then
|
||||
Local stHash:String = MD5Bank(m_oFileLoader.m_oBank).ToUpper()
|
||||
If stHash <> m_oFileHashPair.stHash Then
|
||||
m_oFileList.AddLast(m_oFileHashPair.stName)
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("h[ OK ] Checking '" + m_oFileHashPair.stName + "'... requires update.")
|
||||
Else
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("g[ OK ] Checking '" + m_oFileHashPair.stName + "'... up to date.")
|
||||
EndIf
|
||||
Else
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("e[FAIL] Checking '" + m_oFileHashPair.stName + "'... (File in use?)")
|
||||
EndIf
|
||||
Else
|
||||
m_oFileList.AddLast(m_oFileHashPair.stName)
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("h[ OK ] Checking '" + m_oFileHashPair.stName + "'... missing.")
|
||||
EndIf
|
||||
m_bSubState = TPatcher.SSTATE_ENTER
|
||||
m_oFileLoader.Cleanup()
|
||||
EndIf
|
||||
EndIf
|
||||
|
||||
If m_bSubState = TPatcher.SSTATE_LEAVE Then
|
||||
If m_oFileList.Count() > 0 Then
|
||||
m_iFileCount = m_oFileList.Count()
|
||||
SetState(TPatcher.STATE_PREPATCH)
|
||||
Else
|
||||
SetState(TPatcher.STATE_COMPLETE)
|
||||
EndIf
|
||||
EndIf
|
||||
Case TPatcher.STATE_PATCHING
|
||||
If m_bSubState = TPatcher.SSTATE_ENTER Then
|
||||
Local m_oEntry:Object = m_oFileList.RemoveFirst()
|
||||
If m_oEntry <> Null Then
|
||||
m_oFile = String(m_oEntry);m_oFileDL = m_oFile + ".part"
|
||||
|
||||
CreateDir(ExtractDir(m_oFile), True)
|
||||
m_oFileStream = WriteFile(m_oFileDL)
|
||||
If m_oFileStream <> Null Then
|
||||
m_oCurlMulti = TCurlMulti.Create()
|
||||
m_oCurl = m_oCurlMulti.newEasy()
|
||||
m_oCurl.setOptInt(CURLOPT_FOLLOWLOCATION, 1)
|
||||
m_oCurl.setOptInt(CURLOPT_CRLF, False)
|
||||
m_oCurl.setOptString(CURLOPT_USERAGENT, "Sirius Online Launcher")
|
||||
m_oCurl.setOptString(CURLOPT_REFERER, TPatcher.SERVER + "info")
|
||||
m_oCurl.setOptString(CURLOPT_URL, TPatcher.SERVER + m_oFile)
|
||||
m_oCurl.setWriteStream(m_oFileStream)
|
||||
m_oCurl.setProgressCallback(TPatcher.ProgressCallback, Self)
|
||||
m_oTaskList.AddFirst("n[WAIT] Downloading '" + m_oFile + "'...")
|
||||
|
||||
m_bSubState = TPatcher.SSTATE_WORK
|
||||
EndIf
|
||||
Else
|
||||
SetState(TPatcher.STATE_DEFAULT)
|
||||
EndIf
|
||||
EndIf
|
||||
|
||||
If m_bSubState = TPatcher.SSTATE_WORK Then
|
||||
Local iResult:Int = Perform()
|
||||
m_fProgress = ((m_iFileCount - (m_oFileList.Count() + 1)) / Float(m_iFileCount)) + m_fCurlProgress * (1.0 / m_iFileCount)
|
||||
If iResult = CURLM_OK Then
|
||||
m_oFileStream.Flush()
|
||||
If m_fCurlProgress = 1.0 And m_iCurlMultiHandles = 0 Then
|
||||
m_oCurlMulti.multiRemove(m_oCurl)
|
||||
m_oCurlMulti.multiCleanup()
|
||||
|
||||
Local oCurlRCode:Int = m_oCurl.getInfo().responseCode()
|
||||
m_oCurl.cleanup()
|
||||
|
||||
' Cleanup(1)
|
||||
m_oCurl = Null
|
||||
m_oCurlMulti = Null
|
||||
m_oFileStream.Close()
|
||||
m_oFileStream = Null
|
||||
|
||||
If oCurlRCode <> 404 Then
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("g[ OK ] Downloading '" + m_oFile + "'...")
|
||||
|
||||
' Rename files
|
||||
If m_oFile <> "Launcher.exe" Then
|
||||
RenameFile(m_oFile, m_oFile + ".old")
|
||||
If RenameFile(m_oFileDL, m_oFile) Then
|
||||
DeleteFile(m_oFile + ".old")
|
||||
Else
|
||||
RenameFile(m_oFile + ".old", m_oFile)
|
||||
EndIf
|
||||
Else' If we patched the launcher, tell the parent program to start the new one.
|
||||
RenameFile(m_oFileDL, "-" + m_oFile)
|
||||
m_oFileList.Clear() ' Clear the list to be sure
|
||||
SetState(TPatcher.STATE_LAUNCHER)
|
||||
EndIf
|
||||
|
||||
Else
|
||||
DeleteFile(m_oFileDL)
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("e[FAIL] Downloading '" + m_oFile + "'... file not found.")
|
||||
EndIf
|
||||
|
||||
'Cleanup (2)
|
||||
m_oFileDL = Null
|
||||
m_oFile = Null
|
||||
|
||||
If m_oFileList.Count() = 0 Then
|
||||
m_bSubState = TPatcher.SSTATE_LEAVE
|
||||
Else
|
||||
m_bSubState = TPatcher.SSTATE_ENTER
|
||||
EndIf
|
||||
Else
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("n[" + RSet(String(Int(m_fCurlProgress * 100)), 3) + "%] Downloading '" + m_oFile + "'...")
|
||||
EndIf
|
||||
Else
|
||||
m_oFileStream.Close()
|
||||
m_oTaskList.RemoveFirst()
|
||||
m_oTaskList.AddFirst("e[FAIL] Downloading '" + m_oFile + "'... " + CurlError(iResult))
|
||||
EndIf
|
||||
EndIf
|
||||
|
||||
If m_bSubState = TPatcher.SSTATE_LEAVE And m_bState = TPatcher.STATE_PATCHING Then
|
||||
SetState(TPatcher.STATE_DEFAULT)
|
||||
EndIf
|
||||
EndSelect
|
||||
EndMethod
|
||||
|
||||
Method Advance()
|
||||
Select m_bState
|
||||
Case TPatcher.STATE_PATCHINFO
|
||||
SetState(TPatcher.STATE_CHECKING)
|
||||
Case TPatcher.STATE_PREPATCH
|
||||
SetState(TPatcher.STATE_PATCHING)
|
||||
Case TPatcher.STATE_COMPLETE
|
||||
m_stProcessToRun = "ExeFile.exe"
|
||||
Case TPatcher.STATE_LAUNCHER
|
||||
m_stProcessToRun = "-Launcher.exe 1"
|
||||
EndSelect
|
||||
EndMethod
|
||||
|
||||
Field m_iCurlMultiHandles:Int, m_bCurlMultiState:Byte = 0
|
||||
Method Perform:Int()
|
||||
Local iResult:Int = 0
|
||||
|
||||
iResult = MultiPerform()
|
||||
Select m_bCurlMultiState
|
||||
Case 0, 2
|
||||
m_bCurlMultiState = (m_bCurlMultiState + 1) Mod 3
|
||||
Case 1
|
||||
If m_oCurlMulti.multiSelect(0.1) <> -1 And m_iCurlMultiHandles Then
|
||||
iResult = MultiPerform()
|
||||
If m_iCurlMultiHandles = 0 Then m_bCurlMultiState = 2
|
||||
EndIf
|
||||
EndSelect
|
||||
|
||||
Return iResult
|
||||
EndMethod
|
||||
|
||||
Method MultiPerform:Int()
|
||||
Local iResult:Int = m_oCurlMulti.multiPerform(m_iCurlMultiHandles)
|
||||
While iResult = CURLM_CALL_MULTI_PERFORM
|
||||
iResult = m_oCurlMulti.multiPerform(m_iCurlMultiHandles)
|
||||
Wend
|
||||
Return iResult
|
||||
EndMethod
|
||||
|
||||
' State Management
|
||||
Method SetState(bState:Byte)
|
||||
m_bState = bState
|
||||
m_bSubState = TPatcher.SSTATE_ENTER
|
||||
m_fProgress = 0.0
|
||||
EndMethod
|
||||
|
||||
Method GetState:Byte()
|
||||
Return m_bState
|
||||
EndMethod
|
||||
|
||||
' Information
|
||||
Method GetProgress:Float()
|
||||
Return m_fProgress
|
||||
EndMethod
|
||||
|
||||
|
||||
|
||||
Field m_stProcessToRun:String = NUll
|
||||
Method GetShutdown:String()
|
||||
Return m_stProcessToRun
|
||||
EndMethod
|
||||
' Callbacks
|
||||
Function ProgressCallback:Int(oPatcherObj:Object, dDownloadTotal:Double, dDownloadNow:Double, dUploadTotal:Double, dUploadNow:Double)
|
||||
If dDownloadTotal = 0 And dDownloadNow = 0 And dUploadTotal = 0 And dUploadNow = 0 Then TPatcher(oPatcherObj).m_fCurlProgress = 0.0;Return 0
|
||||
TPatcher(oPatcherObj).m_fCurlProgress = (dDownloadNow / dDownloadTotal)
|
||||
EndFunction
|
||||
EndType
|
||||
|
||||
Type TFileHash
|
||||
Field stName:String, stHash:String
|
||||
|
||||
Function Create:TFileHash(stName:String, stHash:String)
|
||||
Local oFH:TFileHash = New TFileHash
|
||||
oFH.stName = stName
|
||||
oFH.stHash = stHash
|
||||
Return oFH
|
||||
EndFunction
|
||||
EndType
|
||||
|
||||
Type TAsyncLoader
|
||||
Field m_oBank:TBank
|
||||
Field m_oStream:TStream, m_iFileSize:Int
|
||||
Field m_fProgress:Float, m_bComplete:Byte
|
||||
|
||||
Method Initialize(stFile:String)
|
||||
If FileType(stFile) = FILETYPE_FILE Then
|
||||
m_oStream = ReadFile(stFile)
|
||||
If m_oStream <> Null Then
|
||||
m_iFileSize = FileSize(stFile)
|
||||
m_oBank = CreateBank(m_iFileSize)
|
||||
If m_oBank <> Null Then
|
||||
m_fProgress = 0.0
|
||||
m_bComplete = False
|
||||
Else
|
||||
m_oStream.Close()
|
||||
EndIf
|
||||
Else
|
||||
m_fProgress = 1.0
|
||||
m_bComplete = -2
|
||||
EndIf
|
||||
Else
|
||||
m_fProgress = 1.0
|
||||
m_bComplete = -2
|
||||
EndIf
|
||||
EndMethod
|
||||
|
||||
Method Process(iMs:Float, iBufferSize:Int = 1024)
|
||||
Local iClockStart:Int = getClock()
|
||||
If (m_oStream <> Null And m_oBank <> Null) And m_oStream.Eof() = False Then
|
||||
Local iClockNow:Int = getClock()
|
||||
Repeat
|
||||
Local iRemaining:Int = Min(m_iFileSize - m_oStream.Pos(), iBufferSize)
|
||||
m_oBank.Read(m_oStream, m_oStream.Pos(), iRemaining)
|
||||
|
||||
iClockNow = getClock()
|
||||
Until m_oStream.Eof() = True or getClockDiff(iClockStart, iClockNow) > (iMs / 1000.0 * getClocksPerSecond())
|
||||
|
||||
m_fProgress = m_oStream.Pos() / Float(m_iFileSize)
|
||||
m_bComplete = m_oStream.Eof()
|
||||
If m_oStream.Eof() = True Then
|
||||
m_oStream.Close()
|
||||
m_oStream = Null
|
||||
EndIf
|
||||
ElseIf m_bComplete = 0 Then
|
||||
m_fProgress = 1.0
|
||||
m_bComplete = -1
|
||||
EndIf
|
||||
EndMethod
|
||||
|
||||
Method Cleanup()
|
||||
m_oBank = Null
|
||||
EndMethod
|
||||
EndType
|
||||
|
||||
|
||||
|
||||
|
||||
Function DebugClock(Text:String)
|
||||
DebugLog getClock() + ":" + Text
|
||||
EndFunction
|
||||
|
||||
Extern "c"
|
||||
Function getClocksPerSecond:Int()="getClocksPerSecond_"
|
||||
Function getClock:Int()="getClock_"
|
||||
Function getClockDiff:Int(clockStart:Int, clockEnd:Int)="getClockDiff_"
|
||||
EndExtern
|
||||