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,6 @@
|
||||
# Binary Files
|
||||
*.o
|
||||
*.a
|
||||
*.exe
|
||||
*/.bmx
|
||||
*/.indevIDE
|
||||
@@ -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
|
||||
@@ -0,0 +1,8 @@
|
||||
Sirius Online Server
|
||||
=======================
|
||||
|
||||
This project was supposed to be the official server software for Sirius Online, before the idea of multiplayer was dumped completely. Talk about sticking to the project plan. Oh wait, there was none. Why did I join that trainwreck of a team. Anyway, the server was designed to be somewhat efficient at its job of calculating and transferring. It supports up to 65535 players and will re-use Ids where possible instead of constantly incrementing. This makes memory management really easy, but join times are sometimes higher than normal. The project uses Xaymar.IOQueue, something which no longer exists. All it did was store packets to be sent off at a later point in time. Networking was done using UDP and TCP, i think. No idea anymore, don't care either, I'm now using Unreal Engine 4 for game development.
|
||||
|
||||
License
|
||||
=======
|
||||
Sirius Online Server 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,639 @@
|
||||
SuperStrict
|
||||
|
||||
'--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
||||
Framework BRL.Blitz
|
||||
Import BRL.Threads
|
||||
Import BRL.Timer
|
||||
|
||||
Import "BlitzNet.bmx"
|
||||
'--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
||||
|
||||
' Fix GC weirdness
|
||||
OnEnd(GCCollect)
|
||||
|
||||
Local Server:BNetServer = New BNetServer
|
||||
Server.Open(27000, 27001, 8)
|
||||
While
|
||||
Server.Update()
|
||||
Wend
|
||||
Server.Close()
|
||||
|
||||
|
||||
|
||||
'----------------------------------------------------------------
|
||||
'-- Types
|
||||
'----------------------------------------------------------------
|
||||
'Type Server
|
||||
' Field m_Server:BNetServer
|
||||
'End Type
|
||||
|
||||
Rem
|
||||
Const VersionMajor:Byte = 0
|
||||
Const VersionMinor:Byte = 40
|
||||
Const Net_VersionMajor:Byte = 0
|
||||
Const Net_VersionMinor:Byte = 1
|
||||
|
||||
' Network Initiation
|
||||
Global InfoSocket:TSocket = TSocket.CreateTCP()
|
||||
Global DataSocket:TSocket = TSocket.CreateUDP()
|
||||
|
||||
' Set up Information Socket.
|
||||
Const SOCKET_INFO_PORT:Short = 27000
|
||||
Const SOCKET_DATA_PORT:Short = 27001
|
||||
If InfoSocket.Bind(SOCKET_INFO_PORT) Then
|
||||
InfoSocket.SetTCPNoDelay(True)
|
||||
Else
|
||||
InfoSocket.Close()
|
||||
Print "[ERR] Unable to bind Information Socket to port " + SOCKET_INFO_PORT + ". Make sure it is not in use."
|
||||
End
|
||||
EndIf
|
||||
InfoSocket.Listen(128)
|
||||
|
||||
' Set up Data Socket.
|
||||
If Not DataSocket.Bind(SOCKET_DATA_PORT) Then
|
||||
DataSocket.Close()
|
||||
Print "[ERR] Unable to bind Data Socket to port " + SOCKET_DATA_PORT + ". Make sure it is not in use."
|
||||
End
|
||||
EndIf
|
||||
'END OF: Network Initiation
|
||||
|
||||
' Timers
|
||||
Const DataTicks:Int = 5
|
||||
Local l_LoopTimer:TTimer = TTimer.Create(120)
|
||||
|
||||
' Network Packet Buffer
|
||||
Const NetPacketBufferSize:Int = 64
|
||||
Local NetPacketBuffer:TBank = TBank.Create(NetPacketBufferSize)
|
||||
Local NetPacketBufferStream:TBankStream = TBankStream.Create(NetPacketBuffer)
|
||||
Local NetPacketQueueTCP:TList = (New TList)
|
||||
Local NetPacketQueueTCPSwap:TList = (New TList)
|
||||
Local NetPacketQueueUDP:TList = (New TList)
|
||||
Local NetPacketQueueUDPSwap:TList = (New TList)
|
||||
|
||||
Repeat
|
||||
Local l_LoopTime:Int = MilliSecs()
|
||||
|
||||
' Check for data on InfoSockets {
|
||||
' Check for new connections. {
|
||||
Local l_NewSocket:TSocket
|
||||
Repeat
|
||||
l_NewSocket = InfoSocket.Accept(0)
|
||||
|
||||
If l_NewSocket <> Null Then
|
||||
Local l_NewPlayer:TPlayer = TPlayer.Create(l_NewSocket)
|
||||
If l_NewPlayer <> Null Then
|
||||
Print RSet(l_NewPlayer.m_UniqueId, 6) + ": Connected from " + DottedIP(l_NewSocket.RemoteIp()) + ":" + l_NewSocket.RemotePort() + "."
|
||||
Else
|
||||
l_NewSocket.Close()
|
||||
Print "Server: New player tried connecting, but we are full."
|
||||
EndIf
|
||||
EndIf
|
||||
Until l_NewSocket = Null
|
||||
' }
|
||||
|
||||
' Check if a pregame client sent his login information {
|
||||
For Local l_PGPlayer:TPlayer = EachIn TPlayer.PreGame
|
||||
If l_PGPlayer.m_InfoSocket.Connected() = False Then
|
||||
Print RSet(l_PGPlayer.m_UniqueId, 6) + ": Closed connection."
|
||||
l_PGPlayer.Destroy();Continue
|
||||
EndIf
|
||||
|
||||
While l_PGPlayer.m_InfoSocket.ReadAvail() > 0
|
||||
Local l_ReadLength:Int = l_PGPlayer.m_InfoSocket.Recv(NetPacketBuffer._buf, 1);NetPacketBufferStream.Seek(0)
|
||||
If l_ReadLength = 1
|
||||
Local l_PacketId:Byte = NetPacketBufferStream.ReadByte()
|
||||
Select l_PacketId
|
||||
Case TInfoLogin.Id
|
||||
l_PGPlayer.m_InfoSocket.Recv(NetPacketBuffer._buf, TInfoLogin.Size);NetPacketBufferStream.Seek(0)
|
||||
Local l_InfoLogin:TInfoLogin = TInfoLogin(TInfoLogin.Read(NetPacketBufferStream))
|
||||
|
||||
If l_InfoLogin Then
|
||||
' Retrieve Information from Packet
|
||||
l_PGPlayer.m_Name = l_InfoLogin.m_Name
|
||||
l_PGPlayer.m_Position[0] = l_InfoLogin.m_Position[0]
|
||||
l_PGPlayer.m_Position[1] = l_InfoLogin.m_Position[1]
|
||||
l_PGPlayer.m_Position[2] = l_InfoLogin.m_Position[2]
|
||||
|
||||
' Create UDP Socket for Client.
|
||||
l_PGPlayer.m_DataSocket = TSocket.CreateUDP()
|
||||
l_PGPlayer.m_DataSocket.Connect(l_PGPlayer.m_InfoSocket.RemoteIp(), l_InfoLogin.m_PunchPort)
|
||||
|
||||
' Send information to this client (order is important!).
|
||||
Local l_InfoLogin:TInfoLogin = (New TInfoLogin)
|
||||
l_InfoLogin.m_UniqueId = l_PGPlayer.m_UniqueId
|
||||
l_InfoLogin.m_Name = l_PGPlayer.m_Name
|
||||
|
||||
'Local l_InfoUpdate:TInfoUpdate = (New TInfoUpdate)
|
||||
'l_InfoUpdate.m_UniqueId = l_PGPlayer.m_UniqueId
|
||||
'l_InfoUpdate.m_Name = l_PGPlayer.m_Name
|
||||
|
||||
'NetPacketBufferStream.Seek(0)
|
||||
'Local l_Size:Int = l_InfoUpdate.Write(NetPacketBufferStream)
|
||||
'l_PGPlayer.m_InfoSocket.Send(NetPacketBuffer._buf, l_Size)
|
||||
|
||||
' Add Player to ingame list.
|
||||
TPlayer.PreGame.Remove(l_PGPlayer)
|
||||
TPlayer.InGame.AddLast(l_PGPlayer)
|
||||
Print RSet(l_PGPlayer.m_UniqueId, 6) + ": Logged in at " + l_PGPlayer.m_Position[0] + ":" + l_PGPlayer.m_Position[1] + ":" + l_PGPlayer.m_Position[2] + "."
|
||||
Else
|
||||
Print RSet(l_PGPlayer.m_UniqueId, 6) + ": CheckSum did not match with ours, Client is probably outdated."
|
||||
l_PGPlayer.Destroy();Exit
|
||||
EndIf
|
||||
EndSelect
|
||||
Else
|
||||
Print RSet(l_PGPlayer.m_UniqueId, 6) + ": Unable to read first byte, socket might be corrupted. Dropping client."
|
||||
l_PGPlayer.Destroy();Exit
|
||||
EndIf
|
||||
Wend
|
||||
|
||||
' If we still have no login packet, check if they are supposed to be dropped by timeout.
|
||||
If l_PGPlayer.m_InfoSocket And (l_LoopTime - l_PGPlayer.m_Time) > 5000 Then
|
||||
Print RSet(l_PGPlayer.m_UniqueId, 6) + ": Did not login, dropped."
|
||||
l_PGPlayer.Destroy();Continue
|
||||
EndIf
|
||||
Next
|
||||
' }
|
||||
|
||||
' Check if an ingame client sent packets. {
|
||||
While DataSocket.ReadAvail() > 0
|
||||
Local l_ReadLength:Int = DataSocket.Recv(NetPacketBuffer._buf, 1);NetPacketBufferStream.Seek(0)
|
||||
If l_ReadLength = 1
|
||||
Local l_PacketId:Byte = NetPacketBufferStream.ReadByte()
|
||||
|
||||
Select l_PacketId
|
||||
Case TDataUpdate.Id
|
||||
l_ReadLength = DataSocket.Recv(NetPacketBuffer._buf, NetPacketBufferSize)
|
||||
Local l_DataUpdate:TDataUpdate = TDataUpdate(TDataUpdate.Read(NetPacketBufferStream))
|
||||
|
||||
Local l_Player:TPlayer = TPlayer.UIDToPlayer[l_DataUpdate.m_UniqueId]
|
||||
If l_Player And l_Player.m_DataSocket Then ' Player exists and is logged in.
|
||||
If DataSocket.RemoteIp() = l_Player.m_DataSocket.RemoteIp() And DataSocket.RemotePort() = l_Player.m_DataSocket.RemotePort() Then ' It is the same player.
|
||||
If l_DataUpdate.m_Changed & TPlayer.CHANGED_POSX <> 0 Then l_Player.m_Position[0] = l_DataUpdate.m_Position[0]
|
||||
If l_DataUpdate.m_Changed & TPlayer.CHANGED_POSY <> 0 Then l_Player.m_Position[1] = l_DataUpdate.m_Position[1]
|
||||
If l_DataUpdate.m_Changed & TPlayer.CHANGED_POSZ <> 0 Then l_Player.m_Position[2] = l_DataUpdate.m_Position[2]
|
||||
If l_DataUpdate.m_Changed & TPlayer.CHANGED_ROTX <> 0 Then l_Player.m_Rotation[0] = l_DataUpdate.m_Rotation[0]
|
||||
If l_DataUpdate.m_Changed & TPlayer.CHANGED_ROTY <> 0 Then l_Player.m_Rotation[1] = l_DataUpdate.m_Rotation[1]
|
||||
If l_DataUpdate.m_Changed & TPlayer.CHANGED_ROTZ <> 0 Then l_Player.m_Rotation[2] = l_DataUpdate.m_Rotation[1]
|
||||
If l_DataUpdate.m_Changed & TPlayer.CHANGED_VEL <> 0 Then
|
||||
l_Player.m_Velocity[0] = l_DataUpdate.m_Velocity[0]
|
||||
l_Player.m_Velocity[1] = l_DataUpdate.m_Velocity[1]
|
||||
l_Player.m_Velocity[2] = l_DataUpdate.m_Velocity[2]
|
||||
EndIf
|
||||
Else
|
||||
Print "Server: Recieved update for another player from " + DottedIP(DataSocket.RemoteIp()) + ":" + DataSocket.RemotePort() + "."
|
||||
EndIf
|
||||
EndIf
|
||||
EndSelect
|
||||
EndIf
|
||||
Wend
|
||||
' }
|
||||
|
||||
' Check if an ingame client sent packets or packets need sending. {
|
||||
For Local l_IGPlayer:TPlayer = EachIn TPlayer.InGame
|
||||
Local l_Skip:Byte = False
|
||||
If l_IGPlayer = Null Then Print "Fatal Error: Ran into ingame client, which apparently doesn't exist. Skipping."; Continue
|
||||
|
||||
' Check if the Player still has his TCP Socket open, otherwise drop him.
|
||||
If l_IGPlayer.m_InfoSocket.Connected() = False Then
|
||||
Print RSet(l_IGPlayer.m_UniqueId, 6) + ": Closed connection."
|
||||
|
||||
' Create InfoLogout packet.
|
||||
Local l_InfoLogout:TInfoLogout = New TInfoLogout
|
||||
l_InfoLogout.m_UniqueId = l_IGPlayer.m_UniqueId
|
||||
|
||||
' Remove the player from nearby other players.
|
||||
NetPacketBufferStream.Seek(0)
|
||||
Local l_Size:Int = l_InfoLogout.Write(NetPacketBufferStream)
|
||||
For Local l_IGPlayerKnown:TPlayer = EachIn l_IGPlayer.__KnownPlayers:TList
|
||||
l_IGPlayerKnown.m_InfoSocket.Send(NetPacketBuffer._buf, l_Size)
|
||||
l_IGPlayerKnown.__KnownPlayers.Remove(l_IGPlayer)
|
||||
Next
|
||||
|
||||
l_IGPlayer.Destroy();Continue
|
||||
EndIf
|
||||
|
||||
' TCP: Do we have any incoming data from this player?
|
||||
While l_IGPlayer.m_InfoSocket.ReadAvail() > 0
|
||||
Local l_ReadLength:Int = l_IGPlayer.m_InfoSocket.Recv(NetPacketBuffer._buf, 1);NetPacketBufferStream.Seek(0)
|
||||
If l_ReadLength = 1
|
||||
Local l_PacketId:Byte = NetPacketBufferStream.ReadByte()
|
||||
NetPacketBufferStream.Seek(0)
|
||||
|
||||
Select l_PacketId
|
||||
Case TInfoLogin.Id
|
||||
l_IGPlayer.m_InfoSocket.Recv(NetPacketBuffer._buf, TInfoLogin.Size)
|
||||
Case TInfoLogout.Id
|
||||
l_IGPlayer.m_InfoSocket.Recv(NetPacketBuffer._buf, TInfoLogout.Size)
|
||||
|
||||
Local l_InfoLogout:TInfoLogout = TInfoLogout(TInfoLogout.Read(NetPacketBufferStream))
|
||||
l_InfoLogout.m_UniqueId = l_IGPlayer.m_UniqueId
|
||||
|
||||
' Send information to other clients.
|
||||
NetPacketQueueTCPSwap.AddLast(l_InfoLogout)
|
||||
|
||||
Print RSet(l_IGPlayer.m_UniqueId, 6) + ": Logged out."
|
||||
l_IGPlayer.Destroy();l_Skip = True;Exit
|
||||
EndSelect
|
||||
EndIf
|
||||
Wend
|
||||
If l_Skip = True Then Continue
|
||||
|
||||
' TCP: Do we have any data for this player? If so then send it out.
|
||||
If NetPacketQueueTCP.Count() > 0 Then
|
||||
For Local l_Packet:TNetPacket = EachIn NetPacketQueueTCP
|
||||
NetPacketBufferStream.Seek(0)
|
||||
l_IGPlayer.m_InfoSocket.Send(NetPacketBuffer._buf, l_Packet.Write(NetPacketBufferStream))
|
||||
Next
|
||||
EndIf
|
||||
|
||||
' UDP: If a DataUpdate is needed, send it.
|
||||
If l_IGPlayer.m_TicksOnline Mod DataTicks Then
|
||||
For Local l_IGPlayer2:TPlayer = EachIn TPlayer.InGame
|
||||
If l_IGPlayer2 = l_IGPlayer Then Continue
|
||||
|
||||
If l_IGPlayer.IsInRange(l_IGPlayer2) Then ' Is this player even in range? If yes, continue
|
||||
If Not l_IGPlayer.IsKnown(l_IGPlayer2) Then ' This client is new to him, need to introduce him first.
|
||||
Local l_InfoLogin:TInfoLogin = (New TInfoLogin)
|
||||
l_InfoLogin.m_UniqueId = l_IGPlayer2.m_UniqueId
|
||||
l_InfoLogin.m_Name = l_IGPlayer2.m_Name
|
||||
l_InfoLogin.m_Position[0] = l_IGPlayer2.m_Position[0]
|
||||
l_InfoLogin.m_Position[1] = l_IGPlayer2.m_Position[1]
|
||||
l_InfoLogin.m_Position[2] = l_IGPlayer2.m_Position[2]
|
||||
l_InfoLogin.m_Rotation[0] = l_IGPlayer2.m_Rotation[0]
|
||||
l_InfoLogin.m_Rotation[1] = l_IGPlayer2.m_Rotation[1]
|
||||
l_InfoLogin.m_Rotation[2] = l_IGPlayer2.m_Rotation[2]
|
||||
|
||||
NetPacketBufferStream.Seek(0)
|
||||
l_IGPlayer.m_InfoSocket.Send(NetPacketBuffer._buf, l_InfoLogin.Write(NetPacketBufferStream))
|
||||
EndIf
|
||||
|
||||
Local l_DataUpdate:TDataUpdate = l_IGPlayer.GetDataUpdate(l_IGPlayer)
|
||||
If l_DataUpdate Then
|
||||
NetPacketBufferStream.Seek(0)
|
||||
l_IGPlayer.m_DataSocket.Send(NetPacketBuffer._buf, l_DataUpdate.Write(NetPacketBufferStream))
|
||||
EndIf
|
||||
Else
|
||||
If l_IGPlayer.IsKnownEx(l_IGPlayer2) Then ' This client is known to him, need to remove him.
|
||||
Local l_InfoLogout:TInfoLogout = (New TInfoLogout)
|
||||
l_InfoLogout.m_UniqueId = l_IGPlayer2.m_UniqueId
|
||||
|
||||
NetPacketBufferStream.Seek(0)
|
||||
l_IGPlayer.m_InfoSocket.Send(NetPacketBuffer._buf, l_InfoLogout.Write(NetPacketBufferStream))
|
||||
EndIf
|
||||
EndIf
|
||||
Next
|
||||
EndIf
|
||||
|
||||
' UDP: Do we have any data for this player? If so then send it out.
|
||||
If NetPacketQueueUDP.Count() > 0 Then
|
||||
For Local l_Packet:TNetPacket = EachIn NetPacketQueueUDP
|
||||
NetPacketBufferStream.Seek(0)
|
||||
l_IGPlayer.m_DataSocket.Send(NetPacketBuffer._buf, l_Packet.Write(NetPacketBufferStream))
|
||||
Next
|
||||
EndIf
|
||||
|
||||
l_IGPlayer.m_TicksOnline :+ 1
|
||||
Next
|
||||
' }
|
||||
' }
|
||||
|
||||
|
||||
' Swap Network Packet Queue.
|
||||
NetPacketQueueTCP.Swap(NetPacketQueueTCPSwap)
|
||||
NetPacketQueueUDP.Swap(NetPacketQueueUDPSwap)
|
||||
NetPacketQueueTCPSwap.Clear()
|
||||
NetPacketQueueUDPSwap.Clear()
|
||||
|
||||
l_LoopTimer.Wait()
|
||||
Until False
|
||||
DataSocket.Close()
|
||||
InfoSocket.Close()
|
||||
End
|
||||
|
||||
'--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
||||
Type TPlayer
|
||||
'! Array that tells us if an Id is in use. Toggle the bit you were using if an object is created or dies.
|
||||
Global UniqueIds:Byte[] = (New Byte[8192])
|
||||
Global UIDToPlayer:TPlayer[] = (New TPlayer[65536])
|
||||
'! List of active players
|
||||
Global PreGame:TList = (New TList)
|
||||
Global InGame:TList = (New TList)
|
||||
|
||||
' Constants {
|
||||
Const NAME_LENGTH:Int = 16
|
||||
|
||||
Const CHANGED_POSX:Byte = $00000001
|
||||
Const CHANGED_POSY:Byte = $00000010
|
||||
Const CHANGED_POSZ:Byte = $00000100
|
||||
Const CHANGED_ROTX:Byte = $00001000
|
||||
Const CHANGED_ROTY:Byte = $00010000
|
||||
Const CHANGED_ROTZ:Byte = $00100000
|
||||
Const CHANGED_VEL:Byte = $01000000
|
||||
Const CHANGED_SHOOT:Byte = $10000000
|
||||
' }
|
||||
|
||||
' Identification
|
||||
Field m_UniqueId:Short
|
||||
Field m_Name:Byte[]
|
||||
|
||||
' Ship Data
|
||||
Field m_Changed:Byte
|
||||
Field m_Position:Float[]
|
||||
Field m_Rotation:Short[]
|
||||
Field m_Velocity:Short[]
|
||||
|
||||
' Network Data
|
||||
Field m_InfoSocket:TSocket
|
||||
Field m_DataSocket:TSocket
|
||||
Field m_Time:Int
|
||||
Field m_TicksOnline:Int
|
||||
|
||||
' Initialize and Create new Players {
|
||||
Method New()
|
||||
' Some Network Data
|
||||
m_Time = MilliSecs()
|
||||
m_TicksOnline = 0
|
||||
|
||||
' Identification
|
||||
m_Name = New Byte[TPlayer.NAME_Length]
|
||||
m_UniqueID = 0
|
||||
|
||||
' Ship Data
|
||||
m_Position = New Float[3]
|
||||
m_Rotation = New Short[3]
|
||||
m_Velocity = New Short[3]
|
||||
|
||||
TPlayer.PreGame.AddLast(Self)
|
||||
EndMethod
|
||||
|
||||
Function Create:TPlayer(p_InfoSocket:TSocket)
|
||||
' Make sure the Socket is still alive.
|
||||
If p_InfoSocket <> Null And p_InfoSocket.Connected() Then
|
||||
Local l_Player:TPlayer = (New TPlayer)
|
||||
|
||||
' Find a Unique ID that is not yet in use.
|
||||
Local l_UniqueId:Int = 0
|
||||
While l_UniqueId < 8192
|
||||
Local l_SubUniqueId:Byte = 0
|
||||
While l_SubUniqueId < 8
|
||||
If (TPlayer.UniqueIds[l_UniqueId] & (1 shl l_SubUniqueId)) = 0 Then
|
||||
' Mark UniqueId as used.
|
||||
TPlayer.UniqueIds[l_UniqueId] :| (1 shl l_SubUniqueId)
|
||||
l_Player.m_UniqueId = l_UniqueId * 8 + l_SubUniqueId
|
||||
|
||||
' Exit Loops.
|
||||
l_UniqueId = 65535;l_SubUniqueId = 7
|
||||
EndIf
|
||||
|
||||
l_SubUniqueId :+ 1
|
||||
Wend
|
||||
|
||||
l_UniqueId :+ 1
|
||||
Wend
|
||||
|
||||
If l_UniqueId = 65536 Then ' We have a Unique Id if we hit the unsigned limit for Short.
|
||||
TPlayer.UIDToPlayer[l_Player.m_UniqueId] = l_Player
|
||||
|
||||
l_Player.m_InfoSocket = p_InfoSocket
|
||||
Return l_Player
|
||||
EndIf
|
||||
EndIf
|
||||
EndFunction
|
||||
' }
|
||||
|
||||
' Deinitalize and Destroy old Players {
|
||||
Method Destroy()
|
||||
' Mark UniqueId as unused.
|
||||
TPlayer.UniqueIds[Int(m_UniqueId / 8)] :& ~(1 Shl (m_UniqueId Mod 8))
|
||||
TPlayer.UIDToPlayer[m_UniqueId] = Null
|
||||
|
||||
' Try and remove from both Player lists.
|
||||
TPlayer.PreGame.Remove(Self)
|
||||
TPlayer.InGame.Remove(Self)
|
||||
|
||||
' Close remaining Sockets.
|
||||
If m_InfoSocket Then m_InfoSocket.Close()
|
||||
If m_DataSocket Then m_DataSocket.Close()
|
||||
|
||||
' Destroy Data
|
||||
m_Name = Null
|
||||
m_Position = Null
|
||||
m_Rotation = Null
|
||||
m_Velocity = Null
|
||||
m_InfoSocket = Null
|
||||
m_DataSocket = Null
|
||||
EndMethod
|
||||
' }
|
||||
|
||||
' Update {
|
||||
Method Update(p_Multiplier:Float)
|
||||
Local m_OPositionX:Float = m_Position[0]
|
||||
Local m_OPositionY:Float = m_Position[1]
|
||||
Local m_OPositionZ:Float = m_Position[2]
|
||||
|
||||
m_Position[0] :+ m_Velocity[0] * p_Multiplier
|
||||
m_Position[1] :+ m_Velocity[1] * p_Multiplier
|
||||
m_Position[2] :+ m_Velocity[2] * p_Multiplier
|
||||
|
||||
If m_Position[0] <> m_OPositionX Then m_Changed :| TPlayer.CHANGED_POSX
|
||||
If m_Position[1] <> m_OPositionY Then m_Changed :| TPlayer.CHANGED_POSY
|
||||
If m_Position[2] <> m_OPositionZ Then m_Changed :| TPlayer.CHANGED_POSZ
|
||||
EndMethod
|
||||
' }
|
||||
|
||||
' Packets {
|
||||
Const Range:Int = 3000
|
||||
Method IsInRange:Byte(p_Player:TPlayer)
|
||||
Local l_Distance:Float = Abs(p_Player.m_Position[0] - m_Position[0]) + Abs(p_Player.m_Position[1] - m_Position[1]) + Abs(p_Player.m_Position[2] - m_Position[2])
|
||||
If l_Distance < TPlayer.Range Then Return True
|
||||
Return False
|
||||
EndMethod
|
||||
|
||||
Field __KnownPlayers:TList = New TList
|
||||
Method IsKnown:Byte(p_Player:TPlayer)
|
||||
If Not __KnownPlayers.Contains(p_Player) Then
|
||||
__KnownPlayers.AddLast(p_Player)
|
||||
Return False
|
||||
EndIf
|
||||
Return True
|
||||
EndMethod
|
||||
|
||||
Method IsKnownEx:Byte(p_Player:TPlayer)
|
||||
If __KnownPlayers.Contains(p_Player) Then
|
||||
__KnownPlayers.Remove(p_Player)
|
||||
Return True
|
||||
EndIf
|
||||
Return False
|
||||
EndMethod
|
||||
|
||||
Method GetDataUpdate:TDataUpdate(p_Player:TPlayer)
|
||||
Local l_Distance:Float = Abs(p_Player.m_Position[0] - m_Position[0]) + Abs(p_Player.m_Position[1] - m_Position[1]) + Abs(p_Player.m_Position[2] - m_Position[2])
|
||||
If l_Distance < TPlayer.Range And m_Changed Then
|
||||
Local l_DataUpdate:TDataUpdate = New TDataUpdate
|
||||
Local l_Changed:Byte = $00000000
|
||||
|
||||
l_Changed = m_Changed & (TPlayer.CHANGED_POSX | TPlayer.CHANGED_POSY | TPlayer.CHANGED_POSZ)
|
||||
If l_Distance < 2000 Then l_Changed = m_Changed & (TPlayer.CHANGED_ROTX | TPlayer.CHANGED_ROTY | TPlayer.CHANGED_ROTZ)
|
||||
If l_Distance < 1000 Then l_Changed = m_Changed & TPlayer.CHANGED_VEL
|
||||
|
||||
l_DataUpdate.m_UniqueId = m_UniqueId
|
||||
l_DataUpdate.m_Changed = m_Changed
|
||||
l_DataUpdate.m_Position[0] = m_Position[0]
|
||||
l_DataUpdate.m_Position[1] = m_Position[1]
|
||||
l_DataUpdate.m_Position[2] = m_Position[2]
|
||||
l_DataUpdate.m_Rotation[0] = m_Rotation[0]
|
||||
l_DataUpdate.m_Rotation[1] = m_Rotation[1]
|
||||
l_DataUpdate.m_Rotation[2] = m_Rotation[2]
|
||||
l_DataUpdate.m_Velocity[0] = m_Velocity[0]
|
||||
l_DataUpdate.m_Velocity[1] = m_Velocity[1]
|
||||
l_DataUpdate.m_Velocity[2] = m_Velocity[2]
|
||||
|
||||
Return l_DataUpdate
|
||||
EndIf
|
||||
Return Null
|
||||
EndMethod
|
||||
' }
|
||||
EndType
|
||||
|
||||
' Basic Network Packet
|
||||
Type TNetPacket
|
||||
Field m_UniqueId:Short
|
||||
|
||||
Function Read:TNetPacket(p_Stream:TStream)
|
||||
EndFunction
|
||||
|
||||
Method Write(p_Stream:TStream)
|
||||
EndMethod
|
||||
EndType
|
||||
|
||||
Type TInfoLogin Extends TNetPacket
|
||||
Const Id:Byte = 0
|
||||
Const Size:Int = 34
|
||||
Global Version:Short = Net_VersionMajor Shl 8 + Net_VersionMinor
|
||||
|
||||
Field m_Name:Byte[] = New Byte[TPlayer.NAME_LENGTH]
|
||||
Field m_Position:Float[] = New Float[3]
|
||||
Field m_Rotation:Float[] = New Float[3]
|
||||
Field m_PunchPort:Short
|
||||
|
||||
Function Read:TNetPacket(p_Stream:TStream)
|
||||
Local l_UPDPort:Short = p_Stream.ReadShort()
|
||||
Local l_Version:Short = p_Stream.ReadShort()
|
||||
|
||||
If l_Version = TInfoLogin.Version Then
|
||||
Local l_Packet:TInfoLogin = New TInfoLogin
|
||||
p_Stream.ReadBytes(l_Packet.m_Name, TPlayer.NAME_LENGTH)
|
||||
l_Packet.m_Position[0] = p_Stream.ReadFloat()
|
||||
l_Packet.m_Position[1] = p_Stream.ReadFloat()
|
||||
l_Packet.m_Position[2] = p_Stream.ReadFloat()
|
||||
l_Packet.m_Rotation[0] = p_Stream.ReadFloat()
|
||||
l_Packet.m_Rotation[1] = p_Stream.ReadFloat()
|
||||
l_Packet.m_Rotation[2] = p_Stream.ReadFloat()
|
||||
l_Packet.m_PunchPort = l_UDPPort
|
||||
Return l_Packet
|
||||
EndIf
|
||||
EndFunction
|
||||
|
||||
Method Write:Int(p_Stream:TStream)
|
||||
Local l_Pos:Int = p_Stream.Pos()
|
||||
p_Stream.WriteByte(TInfoLogin.Id)
|
||||
p_Stream.WriteShort(m_UniqueId)
|
||||
p_Stream.WriteShort(TInfoLogin.Version)
|
||||
p_Stream.WriteBytes(m_Name, TPlayer.NAME_LENGTH)
|
||||
p_Stream.WriteFloat(m_Position[0])
|
||||
p_Stream.WriteFloat(m_Position[1])
|
||||
p_Stream.WriteFloat(m_Position[2])
|
||||
p_Stream.WriteFloat(m_Rotation[0])
|
||||
p_Stream.WriteFloat(m_Rotation[1])
|
||||
p_Stream.WriteFloat(m_Rotation[2])
|
||||
Return p_Stream.Pos() - l_Pos
|
||||
EndMethod
|
||||
EndType
|
||||
|
||||
Type TInfoLogout Extends TNetPacket
|
||||
Const Id:Byte = 1
|
||||
Const Size:Int = 2
|
||||
|
||||
Function Read:TNetPacket(p_Stream:TStream)
|
||||
Local l_Packet:TInfoLogout = New TInfoLogout
|
||||
Return l_Packet
|
||||
EndFunction
|
||||
|
||||
Method Write:Int(p_Stream:TStream)
|
||||
Local l_Pos:Int = p_Stream.Pos()
|
||||
p_Stream.WriteByte(TInfoLogout.Id)
|
||||
p_Stream.WriteShort(m_UniqueId)
|
||||
Return p_Stream.Pos() - l_Pos
|
||||
EndMethod
|
||||
EndType
|
||||
|
||||
Type TInfoUpdate Extends TNetPacket
|
||||
Const Id:Byte = 2
|
||||
Const Size:Int = 18
|
||||
|
||||
Field m_Name:Byte[] = New Byte[TPlayer.NAME_LENGTH]
|
||||
|
||||
Function Read:TNetPacket(p_Stream:TStream)
|
||||
Local l_Packet:TInfoUpdate = New TInfoUpdate
|
||||
l_Packet.m_UniqueId = p_Stream.ReadShort() ~ p_Stream.ReadShort()
|
||||
p_Stream.ReadBytes(l_Packet.m_Name, TPlayer.NAME_LENGTH)
|
||||
Return l_Packet
|
||||
EndFunction
|
||||
|
||||
Method Write:Int(p_Stream:TStream)
|
||||
Local l_Pos:Int = p_Stream.Pos()
|
||||
p_Stream.WriteByte(TInfoUpdate.Id)
|
||||
p_Stream.WriteShort(m_UniqueId)
|
||||
p_Stream.WriteBytes(m_Name, TPlayer.NAME_LENGTH)
|
||||
Return p_Stream.Pos() - l_Pos
|
||||
EndMethod
|
||||
EndType
|
||||
|
||||
Type TDataUpdate Extends TNetPacket
|
||||
Const Id:Byte = 3
|
||||
Const Size:Int = 3
|
||||
|
||||
Field m_Changed:Byte
|
||||
Field m_Position:Float[] = New Float[3]
|
||||
Field m_Rotation:Float[] = New Float[3]
|
||||
Field m_Velocity:Float[] = New Float[3]
|
||||
|
||||
Function Read:TNetPacket(p_Stream:TStream)
|
||||
Local l_Packet:TDataUpdate = New TDataUpdate
|
||||
l_Packet.m_UniqueId = p_Stream.ReadShort()
|
||||
l_Packet.m_Changed = p_Stream.ReadByte()
|
||||
If l_Packet.m_Changed & TPlayer.CHANGED_POSX <> 0 Then l_Packet.m_Position[0] = p_Stream.ReadFloat()
|
||||
If l_Packet.m_Changed & TPlayer.CHANGED_POSY <> 0 Then l_Packet.m_Position[1] = p_Stream.ReadFloat()
|
||||
If l_Packet.m_Changed & TPlayer.CHANGED_POSZ <> 0 Then l_Packet.m_Position[2] = p_Stream.ReadFloat()
|
||||
If l_Packet.m_Changed & TPlayer.CHANGED_ROTX <> 0 Then l_Packet.m_Rotation[0] = Min(Max(p_Stream.ReadShort() / 32767.0, -1.0), 1.0) * 180.0
|
||||
If l_Packet.m_Changed & TPlayer.CHANGED_ROTY <> 0 Then l_Packet.m_Rotation[1] = Min(Max(p_Stream.ReadShort() / 32767.0, -1.0), 1.0) * 180.0
|
||||
If l_Packet.m_Changed & TPlayer.CHANGED_ROTZ <> 0 Then l_Packet.m_Rotation[2] = Min(Max(p_Stream.ReadShort() / 32767.0, -1.0), 1.0) * 180.0
|
||||
If l_Packet.m_Changed & TPlayer.CHANGED_VEL <> 0 Then
|
||||
l_Packet.m_Velocity[0] = Min(Max(p_Stream.ReadShort() / 32767.0, -1.0), 1.0) * 128.0
|
||||
l_Packet.m_Velocity[1] = Min(Max(p_Stream.ReadShort() / 32767.0, -1.0), 1.0) * 128.0
|
||||
l_Packet.m_Velocity[2] = Min(Max(p_Stream.ReadShort() / 32767.0, -1.0), 1.0) * 128.0
|
||||
EndIf
|
||||
Return l_Packet
|
||||
EndFunction
|
||||
|
||||
Method Write:Int(p_Stream:TStream)
|
||||
Local l_Pos:Int = p_Stream.Pos()
|
||||
p_Stream.WriteByte(TDataUpdate.Id)
|
||||
p_Stream.WriteShort(m_UniqueId)
|
||||
p_Stream.WriteByte(m_Changed)
|
||||
If m_Changed & TPlayer.CHANGED_POSX <> 0 Then p_Stream.WriteFloat(m_Position[0])
|
||||
If m_Changed & TPlayer.CHANGED_POSY <> 0 Then p_Stream.WriteFloat(m_Position[1])
|
||||
If m_Changed & TPlayer.CHANGED_POSZ <> 0 Then p_Stream.WriteFloat(m_Position[2])
|
||||
If m_Changed & TPlayer.CHANGED_ROTX <> 0 Then p_Stream.WriteShort(Min(Max(m_Rotation[0] / 180.0, -1), 1) * 32767)
|
||||
If m_Changed & TPlayer.CHANGED_ROTY <> 0 Then p_Stream.WriteShort(Min(Max(m_Rotation[1] / 180.0, -1), 1) * 32767)
|
||||
If m_Changed & TPlayer.CHANGED_ROTZ <> 0 Then p_Stream.WriteShort(Min(Max(m_Rotation[2] / 180.0, -1), 1) * 32767)
|
||||
If m_Changed & TPlayer.CHANGED_VEL <> 0 Then
|
||||
p_Stream.WriteShort(Min(Max(m_Velocity[0] / 128.0, -1.0), 1.0) * 32767)
|
||||
p_Stream.WriteShort(Min(Max(m_Velocity[1] / 128.0, -1.0), 1.0) * 32767)
|
||||
p_Stream.WriteShort(Min(Max(m_Velocity[2] / 128.0, -1.0), 1.0) * 32767)
|
||||
EndIf
|
||||
Return p_Stream.Pos() - l_Pos
|
||||
EndMethod
|
||||
EndType
|
||||
'--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
|
||||
EndRem
|
||||
@@ -0,0 +1,9 @@
|
||||
xaymar.config
|
||||
=======================
|
||||
|
||||
An easy way to load configurations from so called 'DataPaks'. DataPaks were inspired by Minecraft's NBT format and were able to store any arbitrary data. It's still more efficient to have a dedicated format instead of DataPaks, but it helps with compatability across versions. As far as I remember, this is thread-safe.
|
||||
Documentation at: http://www.blitzforum.de/forum/viewtopic.php?p=388595#388595
|
||||
|
||||
License
|
||||
=======
|
||||
xaymar.config 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,366 @@
|
||||
SuperStrict
|
||||
|
||||
Import xaymar.datapak
|
||||
|
||||
Module xaymar.config
|
||||
ModuleInfo "License: Public Domain"
|
||||
ModuleInfo "Original Author: Michael Dirks <support@levelnull.de>"
|
||||
ModuleInfo "Purpose: Easily read and write configuration files by using xaymar.datapak."
|
||||
|
||||
Type TConfig
|
||||
Field __MainDP:TDataPak
|
||||
Field __CurrentDP:TDataPak
|
||||
|
||||
Method CreateConfig(name:String="Master")
|
||||
__CurrentDP = Null
|
||||
If __MainDP <> Null
|
||||
__MainDP.Destroy()
|
||||
__MainDP = Null
|
||||
End If
|
||||
__MainDP = TDataPak.Create(name)
|
||||
End Method
|
||||
Method OpenConfig(url:String,pwd:String="")
|
||||
__CurrentDP = Null
|
||||
If __MainDP <> Null
|
||||
__MainDP.Destroy()
|
||||
__MainDP = Null
|
||||
End If
|
||||
__MainDP = TDataPak.FromFile(url,pwd)
|
||||
End Method
|
||||
Method SaveConfig(url:String,pwd:String="")
|
||||
__MainDP.ToFile(url, TDP_FLAG_COMPRESSED | TDP_FLAG_PASSWORDED, pwd)
|
||||
End Method
|
||||
Method CloseConfig()
|
||||
__CurrentDP = Null
|
||||
__MainDP.Destroy()
|
||||
__MainDP = Null
|
||||
End Method
|
||||
Method IsConfigOpen:Int()
|
||||
Return (__MainDP <> Null)
|
||||
End Method
|
||||
|
||||
Method CreateGroup(name:String)
|
||||
If __MainDP <> Null
|
||||
Local TVarDP:TDataPakType[] = Null
|
||||
If __MainDP.GetDataByName(name) <> Null Then
|
||||
TVarDP = __MainDP.GetDataByName(name)
|
||||
End If
|
||||
If TVarDP <> Null And TVarDP[0].GetType() = TDP_CONTAINER
|
||||
__CurrentDP = TDataPak(TVarDP[0])
|
||||
Else
|
||||
__CurrentDP = __MainDP.AddDataContainer(name)
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Config open.")
|
||||
End If
|
||||
End Method
|
||||
Method OpenGroup(name:String)
|
||||
If __MainDP <> Null
|
||||
Local TVarDP:TDataPakType[] = Null
|
||||
If __MainDP.GetDataByName(name) <> Null Then
|
||||
TVarDP = __MainDP.GetDataByName(name)
|
||||
End If
|
||||
If TVarDP <> Null And TVarDP[0].GetType() = TDP_CONTAINER
|
||||
__CurrentDP = TDataPak(TVarDP[0])
|
||||
Else
|
||||
Throw TConfigException.Create("Group '"+name+"' does not exist.")
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Config open.")
|
||||
End If
|
||||
End Method
|
||||
Method CloseGroup()
|
||||
__CurrentDP = Null
|
||||
End Method
|
||||
Method IsGroupOpen:Int()
|
||||
Return (__CurrentDP <> Null)
|
||||
End Method
|
||||
|
||||
Method GetGroupByte:Byte(name:String)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_BYTE
|
||||
Return TDataPakByte(TVarDP).GetData()
|
||||
Else
|
||||
Throw TConfigException.Create("Byte '"+name+"' does not exist.")
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method GetGroupShort:Short(name:String)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_SHORT
|
||||
Return TDataPakShort(TVarDP).GetData()
|
||||
Else
|
||||
Throw TConfigException.Create("Short '"+name+"' does not exist.")
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method GetGroupInt:Int(name:String)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_INT
|
||||
Return TDataPakInt(TVarDP).GetData()
|
||||
Else
|
||||
Throw TConfigException.Create("Int '"+name+"' does not exist.")
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method GetGroupLong:Long(name:String)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_LONG
|
||||
Return TDataPakLong(TVarDP).GetData()
|
||||
Else
|
||||
Throw TConfigException.Create("Long '"+name+"' does not exist.")
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method GetGroupFloat:Float(name:String)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_FLOAT
|
||||
Return TDataPakFloat(TVarDP).GetData()
|
||||
Else
|
||||
Throw TConfigException.Create("Float '"+name+"' does not exist.")
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method GetGroupDouble:Double(name:String)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_DOUBLE
|
||||
Return TDataPakDouble(TVarDP).GetData()
|
||||
Else
|
||||
Throw TConfigException.Create("Double '"+name+"' does not exist.")
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method GetGroupString:String(name:String)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_STRING
|
||||
Return TDataPakString(TVarDP).GetData()
|
||||
Else
|
||||
Throw TConfigException.Create("String '"+name+"' does not exist.")
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
|
||||
Method GetGroupByteEx:Byte(name:String, def:Byte)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_BYTE
|
||||
Return TDataPakByte(TVarDP).GetData()
|
||||
Else
|
||||
Return def
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method GetGroupShortEx:Short(name:String, def:Short)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_SHORT
|
||||
Return TDataPakShort(TVarDP).GetData()
|
||||
Else
|
||||
Return def
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method GetGroupIntEx:Int(name:String, def:Int)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_INT
|
||||
Return TDataPakInt(TVarDP).GetData()
|
||||
Else
|
||||
Return def
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method GetGroupLongEx:Long(name:String, def:Long)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_LONG
|
||||
Return TDataPakLong(TVarDP).GetData()
|
||||
Else
|
||||
Return def
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method GetGroupFloatEx:Float(name:String, def:Float)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_FLOAT
|
||||
Return TDataPakFloat(TVarDP).GetData()
|
||||
Else
|
||||
Return def
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method GetGroupDoubleEx:Double(name:String, def:Double)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_DOUBLE
|
||||
Return TDataPakDouble(TVarDP).GetData()
|
||||
Else
|
||||
Return def
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method GetGroupStringEx:String(name:String, def:String)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_STRING
|
||||
Return TDataPakString(TVarDP).GetData()
|
||||
Else
|
||||
Return def
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
|
||||
Method SetGroupByte(name:String,data:Byte)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_BYTE
|
||||
TDataPakByte(TVarDP).SetData(data)
|
||||
Else
|
||||
__CurrentDP.AddDataByte(name,data)
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method SetGroupShort(name:String,data:Short)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_SHORT
|
||||
TDataPakShort(TVarDP).SetData(data)
|
||||
Else
|
||||
__CurrentDP.AddDataShort(name,data)
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method SetGroupInt(name:String,data:Int)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_INT
|
||||
TDataPakInt(TVarDP).SetData(data)
|
||||
Else
|
||||
__CurrentDP.AddDataInt(name,data)
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method SetGroupLong(name:String,data:Long)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_LONG
|
||||
TDataPakLong(TVarDP).SetData(data)
|
||||
Else
|
||||
__CurrentDP.AddDataLong(name,data)
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method SetGroupFloat(name:String,data:Float)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_FLOAT
|
||||
TDataPakFloat(TVarDP).SetData(data)
|
||||
Else
|
||||
__CurrentDP.AddDataFloat(name,data)
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method SetGroupDouble(name:String,data:Double)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_DOUBLE
|
||||
TDataPakDouble(TVarDP).SetData(data)
|
||||
Else
|
||||
__CurrentDP.AddDataDouble(name,data)
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
Method SetGroupString(name:String,data:String)
|
||||
If __CurrentDP <> Null
|
||||
Local TVarDP:TDataPakType = Null, TVarDPA:TDataPakType[] = __CurrentDP.GetDataByName(name)
|
||||
If TVarDPA.Length > 0 Then TVarDP = TVarDPA[0]
|
||||
If TVarDP <> Null And TVarDP.GetType() = TDP_STRING
|
||||
TDataPakString(TVarDP).SetData(data)
|
||||
Else
|
||||
__CurrentDP.AddDataString(name,data)
|
||||
End If
|
||||
Else
|
||||
Throw TConfigException.Create("No Group selected.")
|
||||
End If
|
||||
End Method
|
||||
End Type
|
||||
|
||||
Type TConfigException
|
||||
Field Error:String
|
||||
Method ToString:String()
|
||||
Return Error
|
||||
End Method
|
||||
Function Create:TConfigException(Error:String)
|
||||
Local TCE:TConfigException = New TConfigException
|
||||
TCE.Error = Error
|
||||
Return TCE
|
||||
End Function
|
||||
End Type
|
||||
@@ -0,0 +1,11 @@
|
||||
xaymar.datapak
|
||||
=======================
|
||||
|
||||
A newer iteration of DataCollector, named DataPaks. It was inspired by Minecraft's NBT format and as such has similar features. It supports many types, as well as arrays of such types (in case you don't want to name each entry, useful for inventories). Saved and loaded archives can be passworded and compressed, it is up to you to use that feature. The project includes two examples, which just show how to use the module.
|
||||
|
||||
First iteration at: http://www.blitzforum.de/forum/viewtopic.php?t=36694
|
||||
Documentation at: http://www.blitzforum.de/forum/viewtopic.php?p=388429#388429
|
||||
|
||||
License
|
||||
=======
|
||||
xaymar.datapak 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,35 @@
|
||||
Framework brl.retro
|
||||
Import xaymar.datapak
|
||||
|
||||
'Advanced: Create a new Container
|
||||
Local DPCnt:TDataPak = New TDataPak
|
||||
DPCnt.SetName("MyContainer")
|
||||
|
||||
'Advanced: Add A new String (or any other Type: Byte, Short, Int, Long, Float, Double, Container)
|
||||
Local DPStr:TDataPakString = New TDataPakString
|
||||
DPStr.SetName("MyString")
|
||||
DPStr.SetData("Hello :D")
|
||||
DPCnt.AddData(DPStr)
|
||||
|
||||
'Easy: Add A new String (or any other Type: Byte, Short, Int, Long, Float, Double, Container)
|
||||
DPCnt.AddDataString("MyString2", "Hallo :D")
|
||||
|
||||
'Easy: Safe to File
|
||||
'Uncompressed & Unpassworded [sdp = Standard Data Pak]
|
||||
DPCnt.ToFile("Test.sdp")
|
||||
'Compressed & Unpassworded [cdp = Compressed Data Pak]
|
||||
DPCnt.ToFile("Test.cdp", TDP_FLAG_COMPRESSED)
|
||||
'Uncompressed & Passworded [pdp = Passworded Data Pak]
|
||||
DPCnt.ToFile("Test.pdp", TDP_FLAG_PASSWORDED, "MyPassword")
|
||||
'Compressed & Passworded [mdp = Merged Data Pak]
|
||||
DPCnt.ToFile("Test.mdp", TDP_FLAG_PASSWORDED | TDP_FLAG_COMPRESSED, "MyPassword")
|
||||
|
||||
'Easy: Loading from File
|
||||
'Uncompressed & Unpassworded [sdp = Standard Data Pak]
|
||||
Local DPCntS:TDataPak = TDataPak.FromFile("Test.sdp")
|
||||
'Compressed & Unpassworded [cdp = Compressed Data Pak]
|
||||
Local DPCntC:TDataPak = TDataPak.FromFile("Test.cdp")
|
||||
'Uncompressed & Passworded [pdp = Passworded Data Pak]
|
||||
Local DPCntP:TDataPak = TDataPak.FromFile("Test.pdp", "MyPassword")
|
||||
'Compressed & Passworded [mdp = Merged Data Pak]
|
||||
Local DPCntM:TDataPak = TDataPak.FromFile("Test.mdp", "MyPassword")
|
||||
@@ -0,0 +1,27 @@
|
||||
Framework brl.retro
|
||||
Import xaymar.datapak
|
||||
|
||||
'Testing consistency of DataPaks
|
||||
Local DPCnt:TDataPak = New TDataPak
|
||||
DPCnt.SetName("My Container")
|
||||
|
||||
DPCnt.AddDataByte("My Byte", 127)
|
||||
DPCnt.AddDataShort("My Short", 256)
|
||||
DPCnt.AddDataInt("My Int", 65536)
|
||||
DPCnt.AddDataLong("My Long", 618317896391:Long)
|
||||
DPCnt.AddDataFloat("My Float", 1.23456789)
|
||||
DPCnt.AddDataDouble("My Double", 1.2345678912345:Double)
|
||||
DPCnt.AddDataString("My String", "Totally not yours!")
|
||||
Local DPSCnt:TDataPak = DPCnt.AddDataContainer("My SubContainer")
|
||||
DPSCnt.AddDataByte("Sub Byte", 127)
|
||||
DPSCnt.AddDataShort("Sub Short", 256)
|
||||
DPSCnt.AddDataInt("Sub Int", 65536)
|
||||
DPSCnt.AddDataLong("Sub Long", 618317896391:Long)
|
||||
DPSCnt.AddDataFloat("Sub Float", 1.23456789)
|
||||
DPSCnt.AddDataDouble("Sub Double", 1.2345678912345:Double)
|
||||
DPSCnt.AddDataString("Sub String", "Totally not hub!")
|
||||
|
||||
DPCnt.ToFile("Consistency.sdp")
|
||||
DPCnt.ToFile("Consistency.cdp", TDP_FLAG_COMPRESSED)
|
||||
DPCnt.ToFile("Consistency.pdp", TDP_FLAG_PASSWORDED, "ThisIsATotallyUnsecurePasswordWithUnknownLengthToYouBecauseIDidn'tTellYouItsLength!")
|
||||
DPCnt.ToFile("Consistency.mdp", TDP_FLAG_COMPRESSED | TDP_FLAG_PASSWORDED, "ThisIsATotallyUnsecurePasswordWithUnknownLengthToYouBecauseIDidn'tTellYouItsLength!")
|
||||
@@ -0,0 +1,8 @@
|
||||
xaymar.desktop
|
||||
=======================
|
||||
|
||||
An attempt at rendering to the desktop. Failed, mind you. The module it references no longer exists, no idea what it even added.
|
||||
|
||||
License
|
||||
=======
|
||||
xaymar.desktop 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,104 @@
|
||||
SuperStrict
|
||||
|
||||
Framework BRL.StandardIO
|
||||
Import Xaymar.Desktop
|
||||
Import Pub.DirectX
|
||||
Import Pub.Win32
|
||||
Import MaxGUI.Win32MaxGUIEx
|
||||
|
||||
Extern "win32"
|
||||
Function GetLastError() = "GetLastError@0"
|
||||
EndExtern
|
||||
|
||||
Global d3dx9Lib:Int = LoadLibraryA( "d3dx9" )
|
||||
DebugLog GetLastError()
|
||||
If d3dx9Lib Then
|
||||
Global D3DXAssembleShader:Int(pSrcData:Byte Ptr, SrcDataLen:Int, pDefines:Byte Ptr, pInclude:Byte Ptr, FLAGS:Int, ppShader:ID3DXBuffer Var, ppErrorMsgs:ID3DXBuffer Var)"win32"=GetProcAddress( d3dx9Lib,"D3DXAssembleShader" )
|
||||
Global D3DXSaveSurfaceToFile:Int(pConstString:Byte Ptr, DestFormat:Int, pSurface:Byte Ptr, pSrcPalette:Byte Ptr, pSrcRect:Byte Ptr)"win32"=GetProcAddress( d3dx9Lib, "D3DXSaveSurfaceToFile" )
|
||||
EndIf
|
||||
|
||||
Local l_Displays:TList = GetDisplayList()
|
||||
For Local l_Display:Rect = EachIn l_Displays
|
||||
Print "[" + l_Display.Left + ", " + l_Display.Top + "]:[" + l_Display.Right + ", " + l_Display.Bottom + "]"
|
||||
Next
|
||||
Local l_Display:Rect = Rect(l_Displays.ValueAtIndex(0))
|
||||
|
||||
Local l_D3D:IDirect3D9 = Direct3DCreate9( 32 )
|
||||
If Not l_D3D Then
|
||||
Print "0x00000001"
|
||||
Else
|
||||
Local l_D3DCaps:D3DCAPS9 = New D3DCAPS9
|
||||
If l_D3D.GetDeviceCaps(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, l_D3DCaps) < 0
|
||||
Print "0x00000002"
|
||||
Else
|
||||
Local l_D3DPresentParam:D3DPRESENT_PARAMETERS = New D3DPRESENT_PARAMETERS
|
||||
l_D3DPresentParam.BackBufferWidth = (l_Display.Right - l_Display.Left)
|
||||
l_D3DPresentParam.BackBufferHeight = (l_Display.Bottom - l_Display.Top)
|
||||
l_D3DPresentParam.BackBufferCount = 1
|
||||
l_D3DPresentParam.BackBufferFormat = D3DFMT_UNKNOWN
|
||||
l_D3DPresentParam.MultiSampleType = D3DMULTISAMPLE_NONE
|
||||
l_D3DPresentParam.SwapEffect = D3DSWAPEFFECT_DISCARD
|
||||
l_D3DPresentParam.hDeviceWindow = Null
|
||||
l_D3DPresentParam.Windowed = True
|
||||
l_D3DPresentParam.Flags = D3DPRESENTFLAG_LOCKABLE_BACKBUFFER | D3DPRESENTFLAG_VIDEO
|
||||
l_D3DPresentParam.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE
|
||||
|
||||
Local l_WindowName:String = "Null"
|
||||
Local l_hWnd:Int = CreateWindowExW(0, TWindowsGUIDriver.ClassName(), l_WindowName, 0, 0, 0, 1, 1, Null, Null, Null, Null)
|
||||
If l_hWnd = 0 Then
|
||||
Print GetLastError()
|
||||
Print "0x00000003"
|
||||
Else
|
||||
Local l_D3DDevice:IDirect3DDevice9 = Null
|
||||
If l_D3D.CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, l_hWnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, l_D3DPresentParam, l_D3DDevice) < 0
|
||||
Print "0x00000004"
|
||||
Else
|
||||
Local l_DesktopRT:IDirect3DSurface9 = Null
|
||||
Local l_RecordRT:IDirect3DSurface9 = Null
|
||||
|
||||
If l_D3DDevice.GetRenderTarget(0, l_DesktopRT) < 0
|
||||
Print "0x00000005"
|
||||
Else
|
||||
Local l_D3DDisplayMode:D3DDISPLAYMODE = New D3DDISPLAYMODE
|
||||
If l_D3D.GetAdapterDisplayMode(D3DADAPTER_DEFAULT, l_D3DDisplayMode) < 0
|
||||
Print "0x00000006"
|
||||
Else
|
||||
If l_D3DDevice.CreateOffscreenPlainSurface(l_D3DDisplayMode.Width, l_D3DDisplayMode.Height, l_D3DDisplayMode.Format, D3DPOOL_SYSTEMMEM, l_RecordRT, Null) < 0
|
||||
Print "0x00000007"
|
||||
Else
|
||||
If l_D3DDevice.GetRenderTargetData(l_DesktopRT, l_RecordRT) < 0
|
||||
Print "0x00000008"
|
||||
Else
|
||||
Local File:String = "C:\Dokumente und Einstellungen\Teilnehmer\Desktop\" + MilliSecs() + ".png"
|
||||
Local FileCStr:Byte Ptr = File.ToCString()
|
||||
Print D3DXSaveSurfaceToFile(FileCStr, 3, Byte Ptr(l_RecordRT), Null, Null)
|
||||
If D3DXSaveSurfaceToFile(FileCStr, 3, Byte Ptr(l_RecordRT), Null, Null) <> 0
|
||||
Print "0x00000009"
|
||||
Else
|
||||
Print "Success?"
|
||||
EndIf
|
||||
MemFree FileCStr
|
||||
EndIf
|
||||
l_RecordRT.Release_
|
||||
EndIf
|
||||
l_D3DDisplayMode = Null
|
||||
EndIf
|
||||
l_DesktopRT.Release_
|
||||
EndIf
|
||||
EndIf
|
||||
DestroyWindow l_hWnd
|
||||
EndIf
|
||||
EndIf
|
||||
l_D3D.Release_
|
||||
EndIf
|
||||
|
||||
|
||||
Rem
|
||||
//copy the render target to the destination surface.
|
||||
hr = Device->GetRenderTargetData(pRenderTarget, pDestTarget);
|
||||
//save its contents to a bitmap file.
|
||||
hr = D3DXSaveSurfaceToFile(file,
|
||||
D3DXIFF_BMP,
|
||||
pDestTarget,
|
||||
NULL,
|
||||
NULL);
|
||||
@@ -0,0 +1,11 @@
|
||||
xaymar.resource
|
||||
=======================
|
||||
|
||||
I created this back when multi-threading was highly praised for the features it could give you. This allows you to load anything asynchronous and still know how far the loading process is. Easily extendable as it was designed to work flawlessly with as many types as possible. Requires threading, otherwise it will just be synchronous.
|
||||
Supports both basic BRL modules as well as xaymar.datapak, which allows you to load large files without the program hanging up for a while. Thank god for threading!
|
||||
|
||||
Documentation at: http://www.blitzforum.de/forum/viewtopic.php?p=390021#390021
|
||||
|
||||
License
|
||||
=======
|
||||
xaymar.resource 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,166 @@
|
||||
'!BRL.Audio + AudioSample
|
||||
Import brl.audio
|
||||
Import brl.audiosample
|
||||
Type TSoundResource Extends TResource
|
||||
Field Flags:Int
|
||||
Method SetSound(Name:String, File:String, Flags:Int=-1)
|
||||
Self.Flags = Flags
|
||||
Set(Name,File)
|
||||
EndMethod
|
||||
|
||||
Method _Load()
|
||||
Self.Resource = LoadSound(Self.File, Self.Flags)
|
||||
EndMethod
|
||||
End Type
|
||||
Type TAudioSampleResource Extends TResource
|
||||
Method _Load()
|
||||
Self.Resource = LoadAudioSample(Self.File)
|
||||
End Method
|
||||
End Type
|
||||
|
||||
'!BRL.Bank + BRL.BankStream
|
||||
Import brl.bank
|
||||
Type TBankResource Extends TResource
|
||||
Method _Load()
|
||||
Self.Resource = LoadBank(Self.File)
|
||||
End Method
|
||||
Method _Save()
|
||||
SaveBank(TBank(Self.Resource), Self.File)
|
||||
End Method
|
||||
End Type
|
||||
|
||||
'!BRL.Font
|
||||
Import brl.font
|
||||
Type TFontResource Extends TResource
|
||||
Field Size:Int
|
||||
Field Style:Int
|
||||
|
||||
Method SetFont(Name:String, File:String, Size:Int, Style:Int=SMOOTHFONT)
|
||||
Self.Size = Size
|
||||
Self.Style = Style
|
||||
Set(Name,File)
|
||||
EndMethod
|
||||
|
||||
Method _Load()
|
||||
Self.Resource = LoadFont(Self.File, Self.Size, Self.Style)
|
||||
End Method
|
||||
End Type
|
||||
|
||||
'BRL.Max2D
|
||||
Import brl.max2d
|
||||
Type TImageResource Extends TResource
|
||||
Field Flags:Int = -1
|
||||
Field Animated:Int = False
|
||||
Field CellWidth:Int = 0
|
||||
Field CellHeight:Int = 0
|
||||
Field FirstCell:Int = 0
|
||||
Field CellCount:Int = 0
|
||||
|
||||
Method SetImage(Name:String, File:String, Flags:Int=-1)
|
||||
Self.Flags = Flags
|
||||
Self.Animated = False
|
||||
Set(Name,File)
|
||||
End Method
|
||||
Method SetAnimImage(Name:String, File:String, CellWidth:Int, CellHeight:Int, FirstCell:Int, CellCount:Int, Flags:Int=-1)
|
||||
Self.Flags = Flags
|
||||
Self.Animated = True
|
||||
Self.CellWidth = CellWidth
|
||||
Self.CellHeight = CellHeight
|
||||
Self.FirstCell = FirstCell
|
||||
Self.CellCount = CellCount
|
||||
Set(Name,File)
|
||||
EndMethod
|
||||
|
||||
Method _Load()
|
||||
If Self.Animated = False
|
||||
Self.Resource = LoadImage(Self.File, Self.Flags)
|
||||
Else
|
||||
Self.Resource = LoadAnimImage(Self.File, Self.CellWidth, Self.CellHeight, Self.FirstCell, Self.CellCount, Self.Flags)
|
||||
EndIf
|
||||
EndMethod
|
||||
End Type
|
||||
|
||||
'BRL.Pixmap
|
||||
Import brl.pixmap
|
||||
Import brl.bmploader
|
||||
Import brl.jpgloader
|
||||
Import brl.pngloader
|
||||
Import brl.tgaloader
|
||||
Type TPixmapResource Extends TResource
|
||||
Field IsPNG:Int
|
||||
Field Parameter:Int
|
||||
|
||||
Method SetPixmapJPG(Name:String, File:String, Quality:Int=75)
|
||||
Self.IsPNG = False
|
||||
Self.Parameter = Quality
|
||||
Set(Name, File)
|
||||
End Method
|
||||
Method SetPixmapPNG(Name:String, File:String, Compression:Int=5)
|
||||
Self.IsPNG = True
|
||||
Self.Parameter = Compression
|
||||
Set(Name, File)
|
||||
End Method
|
||||
|
||||
Method _Load()
|
||||
Self.Resource = LoadPixmap(Self.File)
|
||||
End Method
|
||||
Method _Save()
|
||||
If IsPNG = True
|
||||
SavePixmapPNG(TPixmap(Self.Resource), Self.File, Self.Parameter)
|
||||
Else
|
||||
SavePixmapJPeg(TPixmap(Self.Resource), Self.File, Self.Parameter)
|
||||
EndIf
|
||||
End Method
|
||||
End Type
|
||||
|
||||
'BRL.Stream
|
||||
Import brl.stream
|
||||
Type TByteArrayResource Extends TResource
|
||||
Method _Load()
|
||||
Self.Resource = LoadByteArray(Self.File)
|
||||
End Method
|
||||
Method _Save()
|
||||
SaveByteArray(Byte[](Self.Resource), Self.File)
|
||||
End Method
|
||||
End Type
|
||||
Type TObjectResource Extends TResource
|
||||
Method _Load()
|
||||
Self.Resource = LoadObject(Self.File)
|
||||
End Method
|
||||
Method _Save()
|
||||
SaveObject(Self.Resource, Self.File)
|
||||
End Method
|
||||
End Type
|
||||
Type TStringResource Extends TResource
|
||||
Method _Load()
|
||||
Self.Resource = LoadString(Self.File)
|
||||
End Method
|
||||
Method _Save()
|
||||
SaveString(String(Self.Resource), Self.File)
|
||||
End Method
|
||||
End Type
|
||||
Type TStreamResource Extends TResource
|
||||
Field Readable:Int = False
|
||||
Field Writeable:Int = False
|
||||
|
||||
Method SetStream(Name:String, File:String, Readable:Int, Writeable:Int)
|
||||
Readable = Readable
|
||||
Writeable = Writeable
|
||||
Set(Name, File)
|
||||
End Method
|
||||
|
||||
Method _Load()
|
||||
Self.Resource = OpenStream(Self.File, Self.Readable, Self.Writeable)
|
||||
End Method
|
||||
Method _Save()
|
||||
FlushStream(TStream(Self.Resource))
|
||||
End Method
|
||||
End Type
|
||||
|
||||
'BRL.TextStream
|
||||
Import brl.textstream
|
||||
Type TTextResource Extends TResource
|
||||
Method _Load()
|
||||
Self.Resource = LoadText(Self.File)
|
||||
End Method
|
||||
End Type
|
||||
@@ -0,0 +1,37 @@
|
||||
'Xaymar.DataPak
|
||||
Import xaymar.datapak
|
||||
Type TDataPakResource Extends TResource
|
||||
Field Password:String
|
||||
Field Compressed:Int
|
||||
Field Stream:TStream
|
||||
|
||||
Method SetDataPak(Name:String, URL:Object, Password:String="", Compressed:Int=False)
|
||||
Self.Password = Password
|
||||
Self.Compressed = Compressed
|
||||
If TStream(URL) <> Null Then
|
||||
Self.Stream = TStream(URL)
|
||||
Set(Name, "")
|
||||
ElseIf String(URL) <> Null Then
|
||||
Self.Stream = Null
|
||||
Set(Name, String(URL))
|
||||
EndIf
|
||||
End Method
|
||||
|
||||
Method _Load()
|
||||
If Stream = Null
|
||||
Self.Resource = TDataPak.FromFile(Self.File, Self.Password)
|
||||
Else
|
||||
Self.Resource = TDataPak.FromStream(Self.Stream)
|
||||
End If
|
||||
End Method
|
||||
Method _Save()
|
||||
Local _Flags:Byte
|
||||
If Self.Password <> "" Then _Flags :+ TDP_FLAG_PASSWORDED
|
||||
If Self.Compressed <> 0 Then _Flags :+ TDP_FLAG_COMPRESSED
|
||||
If Stream = Null
|
||||
TDataPak(Self.Resource).ToFile(Self.File, _Flags, Self.Password)
|
||||
Else
|
||||
TDataPak(Self.Resource).ToStream(Self.Stream)
|
||||
End If
|
||||
End Method
|
||||
End Type
|
||||
@@ -0,0 +1,106 @@
|
||||
'Xaymar.Resource: Test 01
|
||||
' Loading of Images and Sounds
|
||||
SuperStrict
|
||||
|
||||
Import xaymar.resource
|
||||
Import xaymar.brlaudio
|
||||
Import xaymar.brlmax2d
|
||||
Import brl.audio
|
||||
Import brl.max2d
|
||||
|
||||
Graphics(800,600,0,60)
|
||||
SetVirtualResolution(100,100)
|
||||
|
||||
Global MyResource:TResourceManager = New TResourceManager
|
||||
|
||||
Local imgDir:String[] = LoadDir("data/img/")
|
||||
For Local fileImg:String = EachIn imgDir
|
||||
Local _Res:TImageResource = New TImageResource
|
||||
_Res.SetImage(fileImg, "data/img/"+fileImg)
|
||||
MyResource.AddResource(_Res)
|
||||
Next
|
||||
|
||||
Local sndDir:String[] = LoadDir("data/snd/")
|
||||
For Local fileSnd:String = EachIn sndDir
|
||||
Local _Res:TSoundResource = New TSoundResource
|
||||
_Res.SetSound(fileSnd, "data/snd/"+fileSnd)
|
||||
MyResource.AddResource(_Res)
|
||||
Next
|
||||
|
||||
Local _ExitLoad:Int = False
|
||||
Repeat
|
||||
Cls
|
||||
|
||||
Local _BarPerc:Float = Float(MyResource.GetCount(TRM_LOADED)) / Float(MyResource.GetCount(TRM_ALL))
|
||||
Local _BarPercLoad:Float = Float(MyResource.GetCount(TRM_LOADING)) / Float(MyResource.GetCount(TRM_ALL))
|
||||
Local _BarPercError:Float = Float(MyResource.GetCount(TRM_ERROR)) / Float(MyResource.GetCount(TRM_ALL))
|
||||
Local _BarColorMod:Float = 0.5+Sin( Float(MilliSecs()) / Float(1000/360) )*0.5
|
||||
|
||||
SetBlend ALPHABLEND
|
||||
SetColor 102+153*_BarColorMod, 102+153*_BarColorMod, 102+153*_BarColorMod
|
||||
DrawLine( 5, 90, 95, 90)
|
||||
DrawLine( 5, 90, 5, 95)
|
||||
DrawLine( 5, 95, 95, 95)
|
||||
DrawLine(95, 90, 95, 95)
|
||||
|
||||
SetAlpha 0.9+0.1*_BarColorMod
|
||||
SetColor 51, 255, 51
|
||||
DrawRect( 6, 91, 89*_BarPerc, 4)
|
||||
|
||||
SetAlpha 0.8+0.2*_BarColorMod
|
||||
SetColor 255, 255, 51
|
||||
DrawRect( 6+89*_BarPerc, 91, 89*_BarPercLoad, 4)
|
||||
|
||||
SetAlpha 0.7+0.3*_BarColorMod
|
||||
SetColor 255, 51, 51
|
||||
DrawRect( 6+89*_BarPerc+89*_BarPercLoad, 91, 89*_BarPercError, 4)
|
||||
|
||||
SetColor 255,255,255
|
||||
SetAlpha 1.0*_BarColorMod*_BarPerc
|
||||
DrawRect( 5.5, 90.5, 90, 5)
|
||||
|
||||
|
||||
SetAlpha 0.8
|
||||
SetVirtualResolution(GraphicsWidth(),GraphicsHeight())
|
||||
DrawText("Complete %:"+Int(_BarPerc*100),0,0)
|
||||
DrawText("Loading %:"+Int(_BarPercLoad*100),0,15)
|
||||
DrawText("Errored %:"+Int(_BarPercError*100),0,30)
|
||||
|
||||
If MyResource.GetResource(TRM_NONE) <> Null
|
||||
DrawText(MyResource.GetResource(TRM_NONE).File,800*0.05,600*0.80)
|
||||
Else
|
||||
DrawText("Done, Press any key to continue...",800*0.05,600*0.80)
|
||||
EndIf
|
||||
SetVirtualResolution(100,100)
|
||||
|
||||
Flip
|
||||
|
||||
Local LRCode:Int = MyResource.LoadResource()
|
||||
MyResource.Update() 'Update Count
|
||||
|
||||
If AppTerminate()
|
||||
End
|
||||
End If
|
||||
If LRCode = TRM_LS_NORESOURCE
|
||||
For Local I:Int = 0 To 255
|
||||
If KeyDown(I) = True
|
||||
_ExitLoad = True
|
||||
End If
|
||||
Next
|
||||
End If
|
||||
Until _ExitLoad = True
|
||||
|
||||
SetVirtualResolution(GraphicsWidth(),GraphicsHeight())
|
||||
|
||||
Print "Resource List:"
|
||||
For Local _Res:TResource = EachIn MyResource.GetResources(TRM_ALL)
|
||||
Select _Res._State
|
||||
Case TRM_LOADED, TRM_SAVED
|
||||
Print " SUCCESS: ["+_Res.Name+"]"+_Res.File
|
||||
Case TRM_LOADING, TRM_SAVING
|
||||
Print " STUCK: ["+_Res.Name+"]"+_Res.File
|
||||
Case TRM_ERROR, TRM_NONE
|
||||
Print " FAILED: ["+_Res.Name+"]"+_Res.File + " //"+_Res.Exception.ToString()
|
||||
End Select
|
||||
Next
|
||||
End
|
||||
@@ -0,0 +1,299 @@
|
||||
SuperStrict
|
||||
|
||||
?Threaded
|
||||
Import brl.threads
|
||||
?
|
||||
Import brl.linkedlist
|
||||
|
||||
Module xaymar.resource
|
||||
ModuleInfo "License: Public Domain"
|
||||
ModuleInfo "Original Author: Michael Dirks <support@levelnull.de>"
|
||||
ModuleInfo "Purpose: Load your Files the better way! (Threading supported)"
|
||||
|
||||
Const TRM_SAVED:Int = -2
|
||||
Const TRM_SAVING:Int = -1
|
||||
Const TRM_NONE:Int = +0
|
||||
Const TRM_LOADING:Int = +1
|
||||
Const TRM_LOADED:Int = +2
|
||||
Const TRM_ERROR:Int = $FF
|
||||
Const TRM_ALL:Int = $FE
|
||||
|
||||
Const TRM_LS_ERROR:Int = 0
|
||||
Const TRM_LS_SUCCESS:Int = 1
|
||||
Const TRM_LS_NORESOURCE:Int = 2
|
||||
|
||||
Type TRLException
|
||||
Method ToString:String()
|
||||
Return "An Error appeared during Loading/Saving the Object."
|
||||
End Method
|
||||
End Type
|
||||
Type TResourceManager
|
||||
'Members
|
||||
Field _ResList:TList = New TList
|
||||
Field _ResourceLoaderFunc(Res:TResource)
|
||||
Field _ResourceSaverFunc(Res:TResource)
|
||||
|
||||
'Members: Stats
|
||||
Field _SavingRes:Int, _SavedRes:Int
|
||||
Field _TotalRes:Int, _ErrorRes:Int
|
||||
Field _LoadingRes:Int, _LoadedRes:Int
|
||||
|
||||
'Threaded Members
|
||||
?Threaded Field _ResMutex:TMutex = CreateMutex()
|
||||
?
|
||||
|
||||
'Methods
|
||||
Method New();SetLoaderFunc(TResourceLoaderFunc);SetSaverFunc(TResourceSaverFunc);End Method
|
||||
Method Remove()
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
_ResList.Clear()
|
||||
_ResList = Null
|
||||
?Threaded _ResMutex.Unlock()
|
||||
_ResMutex.Close()
|
||||
_ResMutex = Null
|
||||
?
|
||||
End Method
|
||||
|
||||
Method SetLoaderFunc(LoaderFunc:Byte Ptr)
|
||||
_ResourceLoaderFunc = LoaderFunc
|
||||
End Method
|
||||
Method SetSaverFunc(SaverFunc:Byte Ptr)
|
||||
_ResourceSaverFunc = SaverFunc
|
||||
End Method
|
||||
|
||||
Method Update()
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
_TotalRes = _ResList.Count()
|
||||
_LoadingRes = 0;_SavingRes = 0
|
||||
_LoadedRes = 0;_SavedRes = 0
|
||||
_ErrorRes = 0;
|
||||
|
||||
For Local _Res:TResource = EachIn _ResList
|
||||
Select _Res._State
|
||||
Case TRM_LOADING
|
||||
_LoadingRes :+ 1
|
||||
Case TRM_LOADED
|
||||
_LoadedRes :+ 1
|
||||
Case TRM_SAVING
|
||||
_SavingRes :+ 1
|
||||
Case TRM_SAVED
|
||||
_SavedRes :+ 1
|
||||
Case TRM_NONE
|
||||
Default
|
||||
_ErrorRes :+ 1
|
||||
End Select
|
||||
Next
|
||||
?Threaded _ResMutex.Unlock()
|
||||
?
|
||||
End Method
|
||||
Method GetCount:Int(Which:Int)
|
||||
Select Which
|
||||
Case TRM_NONE
|
||||
Return _TotalRes-_LoadedRes-_LoadingRes-_SavedRes-_SavingRes-_ErrorRes
|
||||
Case TRM_LOADING
|
||||
Return _LoadingRes
|
||||
Case TRM_LOADED
|
||||
Return _LoadedRes
|
||||
Case TRM_SAVING
|
||||
Return _SavingRes
|
||||
Case TRM_SAVED
|
||||
Return _SavedRes
|
||||
Case TRM_ERROR
|
||||
Return _ErrorRes
|
||||
Case TRM_ALL
|
||||
Return _TotalRes
|
||||
Default
|
||||
Return 0
|
||||
End Select
|
||||
EndMethod
|
||||
|
||||
Method AddResource(Res:TResource)
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
_ResList.AddLast(Res)
|
||||
Res._State = TRM_NONE
|
||||
?Threaded _ResMutex.Unlock()
|
||||
?
|
||||
End Method
|
||||
Method RemoveResourceName(Name:String)
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
For Local _Res:TResource = EachIn _ResList
|
||||
If _Res.Name = Name Then
|
||||
_ResList.Remove(_Res)
|
||||
_Res = Null
|
||||
End If
|
||||
Next
|
||||
?Threaded _ResMutex.Unlock()
|
||||
?
|
||||
End Method
|
||||
Method RemoveResource(Res:TResource)
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
_ResList.Remove(Res)
|
||||
?Threaded _ResMutex.Unlock()
|
||||
?
|
||||
End Method
|
||||
Method ClearResource(Which:Int=TRM_ALL)
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
_ResList.Clear()
|
||||
?Threaded _ResMutex.Unlock()
|
||||
?
|
||||
End Method
|
||||
|
||||
Method GetResourceName:TResource(Name:String, Which:Int=TRM_ALl)
|
||||
Local _rRes:TResource
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
For Local _Res:TResource = EachIn _ResList
|
||||
If _Res.Name = Name And (_Res._State = Which Or Which = TRM_ALL)
|
||||
_rRes = _Res
|
||||
Exit
|
||||
EndIf
|
||||
Next
|
||||
?Threaded _ResMutex.Unlock()
|
||||
?
|
||||
Return _rRes
|
||||
End Method
|
||||
Method GetResourcesName:TResource[](Name:String, Which:Int=TRM_ALL)
|
||||
Local _rList:TList = New TList
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
For Local _Res:TResource = EachIn _ResList
|
||||
If _Res.Name = Name And (_Res._State = Which Or Which = TRM_ALL)
|
||||
_rList.AddLast(_Res)
|
||||
EndIf
|
||||
Next
|
||||
?Threaded _ResMutex.Unlock()
|
||||
?
|
||||
Return TResource[](_rList.ToArray())
|
||||
End Method
|
||||
Method GetResource:TResource(Which:Int=TRM_ALl)
|
||||
Local _rRes:TResource
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
For Local _Res:TResource = EachIn _ResList
|
||||
If (_Res._State = Which Or Which = TRM_ALL)
|
||||
_rRes = _Res
|
||||
Exit
|
||||
EndIf
|
||||
Next
|
||||
?Threaded _ResMutex.Unlock()
|
||||
?
|
||||
Return _rRes
|
||||
End Method
|
||||
Method GetResources:TResource[](Which:Int=TRM_ALL)
|
||||
Local _rList:TList = New TList
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
For Local _Res:TResource = EachIn _ResList
|
||||
If (_Res._State = Which Or Which = TRM_ALL)
|
||||
_rList.AddLast(_Res)
|
||||
EndIf
|
||||
Next
|
||||
?Threaded _ResMutex.Unlock()
|
||||
?
|
||||
Return TResource[](_rList.ToArray())
|
||||
End Method
|
||||
|
||||
Method LoadResource:Int(Which:Int=TRM_NONE)
|
||||
Local _Res:TResource = GetResource(Which), _rVal:Int
|
||||
If _Res = Null
|
||||
Return TRM_LS_NORESOURCE
|
||||
Else
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
_Res._State = TRM_LOADING
|
||||
?Threaded _ResMutex.Unlock()
|
||||
?
|
||||
|
||||
_ResourceLoaderFunc(_Res)
|
||||
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
If _Res.Exception = Null And _Res.Resource <> Null
|
||||
_Res._State = TRM_LOADED
|
||||
_rVal = TRM_LS_SUCCESS
|
||||
Else
|
||||
If _Res.Exception = Null
|
||||
_Res.Exception = New TRLException
|
||||
End If
|
||||
_Res._State = TRM_ERROR
|
||||
_rVal = TRM_LS_ERROR
|
||||
End If
|
||||
?Threaded _ResMutex.Unlock()
|
||||
?
|
||||
Return _rVal
|
||||
End If
|
||||
End Method
|
||||
Method SaveResource:Int(Which:Int=TRM_NONE)
|
||||
Local _Res:TResource = GetResource(Which), _rVal:Int
|
||||
If _Res = Null
|
||||
Return TRM_LS_NORESOURCE
|
||||
Else
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
_Res._State = TRM_SAVING
|
||||
?Threaded _ResMutex.Unlock()
|
||||
?
|
||||
|
||||
_ResourceSaverFunc(_Res)
|
||||
|
||||
?Threaded _ResMutex.Lock()
|
||||
?
|
||||
If _Res.Exception = Null
|
||||
_Res._State = TRM_SAVED
|
||||
_rVal = TRM_LS_SUCCESS
|
||||
Else
|
||||
_Res._State = TRM_ERROR
|
||||
_rVal = TRM_LS_ERROR
|
||||
End If
|
||||
?Threaded _ResMutex.Unlock()
|
||||
?
|
||||
Return _rVal
|
||||
End If
|
||||
End Method
|
||||
End Type
|
||||
Type TResource
|
||||
Field _State:Int
|
||||
|
||||
Field Name:String, File:String
|
||||
Field Resource:Object, Exception:Object
|
||||
|
||||
Method New();EndMethod
|
||||
Method Set(Name:String, File:String)
|
||||
Self.Name = Name
|
||||
Self.File = File
|
||||
Self.Resource = Null
|
||||
Self.Exception = Null
|
||||
End Method
|
||||
Method Remove()
|
||||
Self.Resource = Null
|
||||
Self.Exception = Null
|
||||
Self.File = Null
|
||||
Self.Name = Null
|
||||
End Method
|
||||
|
||||
Method _Load();End Method
|
||||
Method _Save();End Method
|
||||
End Type
|
||||
|
||||
Function TResourceLoaderFunc(Res:TResource)
|
||||
Try
|
||||
Res._Load()
|
||||
Catch E:Object
|
||||
Res.Exception = E
|
||||
Res.Resource = Null
|
||||
EndTry
|
||||
End Function
|
||||
Function TResourceSaverFunc(Res:TResource)
|
||||
Try
|
||||
Res._Save()
|
||||
Catch E:Object
|
||||
Res.Exception = E
|
||||
Res.Resource = Null
|
||||
EndTry
|
||||
End Function
|
||||