SyntaxBomb - Indie Coders

Languages & Coding => Blitz Code Archives => File Utilities => Topic started by: BlitzBot on June 29, 2017, 00:28:42

Title: [bmx] Simple OOP Database engine with Threaded loading *SVN Blitz Required* by DavidSimon [ 1+ years ago ]
Post by: BlitzBot on June 29, 2017, 00:28:42
Title : Simple OOP Database engine with Threaded loading *SVN Blitz Required*
Author : DavidSimon
Posted : 1+ years ago

Description : Tested in my own game, which it was wrote for. Now my map editor boots up instantly, and the tiles just 'stream' in one by one.

In case you're wondering, it IS possible to load graphics in an external thread, you will just most likely have to use your own format. Because any DX/GL stuff most likely has to be done within the main thread. Not sure how you could call loadimage without that occuring. LoadPixMap perhaps?
 
Also included is a oop approach to threading, the athread and amutex classes.


Code :
Code (blitzmax) Select
Type TZoneRecord Extends TDataRecord
Field mZone:TMapZone
Field mWorkZone:TMapZone

Method New()

mDataType = "Zone"

End Method

Function CreateZoneRecord:TZoneRecord(z:TMapZone)

Local r:TZoneRecord = New TZoneRecord
r.mZone = z
Return r

End Function

Method SyncFrom()

mWorkZone = New TMapZone
mWorkZone.mX = mZone.mX
mWorkZone.mY = mZone.mY
mworkZone.mZ = mZone.mZ
mworkZone.mRadius = mZone.mRadius
mWorkZone.Name = mZone.name
' mworkLight.mGreen = mLight.mGreen
' mWorkLight.mBlue = mLight.mBlue

' mWorkLight.mRange = mLight.mRange

End Method

Method SyncTo()
If mZone = Null
mZone = TMapZone.CreateCircle("", 0, 0, 0, 0, Null)
End If
mZone.Name = mworkzone.Name
mZone.mx = mworkZone.mx
mZone.my = mworkZone.my
mZone.mz = mworkZone.mz

mZone.mRadius = mworkZone.mRadius

End Method

Method WriteHeader()

mfile.WriteLine(mWorkZone.Name)
mfile.WriteFloat(mWorkZone.mX)
mfile.WriteFloat(mWorkZone.mY)
mFile.WriteFloat(mWorkzone.mZ)

mFile.WriteFloat(mWorkZone.mRadius)

End Method

Method ReadHeader()

Local name:String = mfile.ReadLine()
Local lx:Float = mfile.ReadFloat()
Local ly:Float = mfile.ReadFloat()
Local lz:Float = mfile.ReadFloat()

Local lradius:Float = mfile.ReadFloat()

mWorkZone = TMapZone.CreateCircle(name, lx, ly, lz, lradius, Null)

End Method

End Type

Type TLightRecord Extends TDataRecord
Field mLight:TMapLight
Field mWorkLight:TMapLight

Method New()

mDataType = "Light"

End Method

Function CreateLightRecord:TLightRecord(l:TMapLight)

Local r:TLightRecord = New TLightRecord

r.mLight = l

Return r

End Function

Method SyncFrom()

mWorkLight = New TMapLight
mWorkLight.mX = mLight.mX
mWorkLight.mY = mLight.mY
mworklight.mZ = mLight.mZ

mworkLight.mRed = mLight.mRed
mworkLight.mGreen = mLight.mGreen
mWorkLight.mBlue = mLight.mBlue

mWorkLight.mRange = mLight.mRange

End Method

Method SyncTo()
If mlight = Null
mLight = TMapLight.Create(0, 0, 0, 0, 0, 0, 0, Null)
End If
mLight.mx = mworklight.mx
mlight.my = mworklight.my
mlight.mz = mworklight.mz

mlight.mRed = mworklight.mRed
mlight.mGreen = mworklight.mGreen
mLight.mBlue = mWorkLight.mBlue

mLight.mRange = mWorkLight.mRange

End Method

Method WriteHeader()

mfile.WriteFloat(mWorkLight.mX)
mfile.WriteFloat(mWorkLight.mY)
mFile.WriteFloat(mWorkLight.mZ)

mFile.WriteFloat(mWorkLight.mRed)
mFile.WriteFloat(Self.mWorkLight.mGreen)
mFile.WriteFloat(Self.mWorkLight.mBlue)

mFile.WriteFloat(Self.mWorkLight.mRange)


End Method

Method ReadHeader()

Local lx:Float = mfile.ReadFloat()
Local ly:Float = mfile.ReadFloat()
Local lz:Float = mfile.ReadFloat()

Local lr:Float = mfile.ReadFloat()
Local lg:Float = mfile.ReadFloat()
Local lb:Float = mfile.ReadFloat()

Local lrange:Float = mfile.ReadFloat()

mWorkLight = TMapLight.Create(lx, ly, lz, lr, lg, lb, lrange, Null)

End Method

End Type

Type TMapRecord Extends TDataRecord

Field mMap:TMap
Field mWorkMap:TMap

Method New()
mDataType = "Map"
End Method

Function CreateMapRecord:TMapRecord(m:TMap)

Local r:TMapRecord = New TMapRecord

r.mMap = m

Return r

End Function

Method SyncFrom()

mWorkMap = New TMap
mWorkMap.mMapWidth = mMap.mMapWidth
mWorkMap.mMapHeight = mmap.mMapHeight
mworkmap.mMapDepth = mmap.mMapDepth

mworkmap.mTileWidth = mmap.mTileWidth
mworkmap.mTileHeight = mmap.mTileHeight

mworkmap.mTile = New TTile[mWorkMap.mMapWidth, mWorkMap.mMapHeight, mWorkMap.mMapDepth]
mworkmap.mDrawInfo = New TDrawInfo[mworkmap.mMapWidth, mworkmap.mMapHeight]

For Local x:Int = 0 Until mworkmap.mMapWidth
For Local y:Int = 0 Until mworkmap.mMapHeight

mworkmap.mDrawInfo[x, y] = mMap.mDrawInfo[x, y]

For Local z:Int = 0 Until mworkmap.mMapDepth
mWorkMAp.mTile[x, y, z] = mMap.mTile[x, y, z]

Next
Next
Next

End Method

Method SyncTo()
If mMap = Null
mMap = New TMap
End If
mMap.mMapWidth = mworkMap.mMapWidth
mMap.mMapHeight = mworkmap.mMapHeight
mmap.mMapDepth = mworkmap.mMapDepth

mmap.mTileWidth = mworkmap.mTileWidth
mmap.mTileHeight = mworkmap.mTileHeight

mmap.mTile = New TTile[mWorkMap.mMapWidth, mWorkMap.mMapHeight, mWorkMap.mMapDepth]
mmap.mDrawInfo = New TDrawInfo[mworkmap.mMapWidth, mworkmap.mMapHeight]

For Local x:Int = 0 Until mworkmap.mMapWidth
For Local y:Int = 0 Until mworkmap.mMapHeight

mmap.mDrawInfo[x, y] = mworkMap.mDrawInfo[x, y]

For Local z:Int = 0 Until mworkmap.mMapDepth
mMAp.mTile[x, y, z] = mworkMap.mTile[x, y, z]
Next

Next
Next

End Method

Method WriteHeader()

mfile.WriteInt(mWorkMap.mMapWidth)
mfile.WriteInt(mWorkMap.mMapHeight)
mFile.WriteInt(mWorkMap.mMapDepth)

mFile.WriteInt(mWorkmap.mTileWidth)
mFile.WriteInt(Self.mWorkMap.mTileWidth)

For Local x:Int = 0 Until mworkmap.mMapWidth
For Local y:Int = 0 Until mworkmap.mMapHeight
For Local z:Int = 0 Until mworkmap.mMapDepth
If mworkmap.mTile[x, y, z] <> Null
mFile.WriteByte(1)
mFile.WriteLine(mworkmap.mTile[x, y, z].dPath)
mFile.WriteLine(mworkmap.mTile[x, y, z].nPath)
Else
mFile.WriteByte(0)
EndIf
Next
Next
Next


End Method

Method ReadHeader()

Local mw:Int = mfile.ReadInt()
Local mh:Int = mfile.ReadInt()
Local md:Int = mfile.ReadInt()

Local tw:Int = mfile.ReadInt()
Local th:Int = mfile.ReadInt()

mworkMap = TMap.Create(mw, mh, md, tw, th)

Local tl:TList = CreateList()

For Local x = 0 Until mw
For Local y = 0 Until mh
For Local z = 0 Until md
Local it:Int = mfile.ReadByte()
If it
Local t:TTile = New TTile
t.dPath = mfile.ReadLine()
t.nPath = mfile.ReadLine()
mworkmap.mTile[x, y, z] = t
End If
Next
Next
Next

End Method

End Type

Type TTextureRecord Extends TDataRecord

Field mTexture:Texture

Method New()

mDataType = "Texture"

End Method

Function CreateTextureRecord:TTextureRecord(tex:Texture)

Local r:TTextureRecord = New TTextureRecord

r.mTexture = tex
If r.mTexture.Path = ""
Notify "Texture has no path. Aborting."
EndIf


Return r

End Function

Method SyncFrom()

mBuf = mTexture.buf
mSize = mtexture.Width * mTexture.Height * mTexture.depth
mbufstream = CreateRamStream(mbuf, msize, True, True)
InFile = False

End Method

Method SyncTo()

Local pa:String = mtexture.Path
mTexture = Texture.FromBuf(mbuf, mtexture.Width, mtexture.Height, mtexture.depth)
mtexture.Path = pa
'mTexture.buf = mBuf
'mTexture.Bind()
'mTexture.Upload()
'mTexture.Unbind()

End Method

Method WriteHeader()

mfile.WriteInt(mTexture.Width)
mFile.WriteInt(mTexture.Height)
mFile.WriteInt(mTexture.depth)
mFile.WriteLine(mTexture.Path)
End Method

Method ReadHeader()

Local w:Int = mFile.ReadInt()
Local H:Int = mFile.ReadInt()
Local depth:Int = mFile.ReadInt()
Local path:String = mfile.ReadLine()
' If mtexture = Null

mTexture = Texture.Blank(w, h, depth)
mtexture.Path = path
' Else

' mtexture.Width = w
' mtexture.Height = h
' mtexture.depth = depth

' EndIf

End Method

End Type

Type TDataRecord

Field InMemory:Int, InFile:Int
Field Name:String
Field mDataType:String
Field mBuf:Byte Ptr
Field mSize:Int
Field mBufStream:TRamStream
Field mPath:String
Field mFile:TStream

Method SyncFrom() Abstract

Method SyncTo() Abstract


Method WriteHeader() Abstract

Method ReadHeader() Abstract

Method CreateBuffer(size:Int)

If mbuf <> Null
MemFree mbuf
EndIf
mbuf = MemAlloc(size)
mbufstream = CreateRamStream(mbuf, msize, True, True)
msize = size

End Method

Method Open()
If FileType(mPath) = 0
mFile = WriteFile(mPath)
If mFile = Null
Notify "Could not create file:" + mPath + " Aborting program."
End If
CloseFile mfile
EndIf
mFile = OpenFile(mPath)
End Method


Method Write()

Open()

mFile.Seek(0)

SyncFrom()

WriteHeader()



Local ed:Byte Ptr = MemAlloc(mSize * 2)

Local el:Int = mSize * 2

compress2(ed, el, mbuf, msize, 9)

mFile.WriteInt(mSize)
mFile.WriteInt(el)
mFile.Write(ed, el)

MemFree ed

Close()


End Method

Field LoadThread:TLoadRecordThread


Method IsReady:Int()


If LoadThread = Null

Return True

EndIf

Local ret:Int = False

LoadThread.mMutex.Lock()
ret = loadthread.mDone
LoadThread.mMutex.Unlock()

Return ret

End Method

Field mThreadDoned = False

Method ThreadDone()

If mThreadDoned = False

mThreadDoned = True
SyncTo()
LoadThread = Null

EndIf

End Method

Method Read()

LoadThread = New TLoadRecordThread
LoadThread.mRecord = Self
LoadThread.run()
Print "Started Load Thread. Item:"+name+" DataType:"+mDataType+" Size:"+mSize

End Method

Method Close()

CloseFile mFile

End Method

End Type

Type TLoadRecordThread Extends AThread

Field mRecord:TDataRecord
Field mDone:Int = False
Field mMutex:AMutex

Method Init()

mMutex = New AMutex
mDone = False

End Method



Method ThreadLogic:Object()

Print "Loading DataRecord assets. Item:"+mRecord.name+" DataType:"+mRecord.mDataType+" Size:"+mRecord.mSize

mRecord.Open()

Print "Open succesfull"

mRecord.mFile.Seek(0)

Print "Seek succesfull"

mRecord.ReadHeader()

Print "Read Header OK."

Local os:Int = mRecord.mfile.ReadInt()
Local ds:Int = mRecord.mFile.ReadInt()

Print "Read Size OK."

Local cb:Byte Ptr = MemAlloc(ds)

Print "Allocated Memory OK."

mRecord.CreateBuffer(os)

Print "Create Internal Buffer OK."

mRecord.mfile.Read(cb, ds)

Print "Read Record OK."

uncompress(mRecord.mBuf, os, cb, ds)

Print "Uncompressed data into original form OK."

mRecord.mSize = os

Print "Set Size OK."

mRecord.close()

Print "Closed Record OK."

'mRecord.SyncTo()

Print "Synced Resource OK."

mMutex.Lock()

Print "Locked Mutex OK."

mDone = True

Print "Set External Variable OK."

mMutex.unlock()

Print "DataRecord assets loaded. Item:"+mRecord.name+" DataType:"+mRecord.mDataType+" Size:"+mRecord.mSize


End Method


End Type

Type TDatabase

Field mName:String
Field mAuthor:String
Field mCopyright:String
Field mPath:String
Field mRecords:TList = CreateList()
Field mFile:TStream
Field mMainPath:String

Method Finished()

Save()

End Method

Function Create:TDatabase(name:String, path:String)

Local r:TDatabase = New TDatabase

r.mName = name

r.mAuthor = "Dreambreaker Software"

r.mCopyright = "(c)Dreambreaker Software 2008"

r.mPath = path

Local fp:String = Path + "DATA"
If FileType(fp) = 0
CreateDir(fp, True)
End If

Local ind:String = path + ".wdb"
r.mMainPath:String = ind
Select FileType(ind)
Case 1
r.SyncIndex()
End Select

Return r

End Function

Method AddRecord(t:TDataRecord, name:String)

t.mPath = mPath + "DATA" + name
t.InMemory = True
t.InFile = False
t.Name = name
mRecords.addlast(t)
WriteIndex()
Save()

End Method

Method Save()

For Local r:TDataRecord = EachIn mRecords
If r.InFile = False
r.Write()
r.InFile = True
End If
Next

End Method

Method GetAllOfType:TList(name:String, LoadIfNotInMemory:Int = True)

name:String = name.ToLower()

Local ret:TList = CreateList()

For Local r:TDataRecord = EachIn mrecords

If r.mDataType.ToLower() = name.ToLower()

If LoadIfNotInMemory

If r.InMemory = False
Local ms:Int = MilliSecs()
r.read()
r.InMemory = True
Print "Loaded Record:" + r.Name + " in ms:" + (MilliSecs() - ms)

End If

End If

ret.AddLast(r)
End If

Next

Return ret

End Method

Method FindRecord:TDataRecord(name:String, LoadIfNotInMemory:Int = True)

name = name.ToLower()

For Local r:TDataRecord = EachIn mRecords

If r.Name.ToLower() = name
If r.InMemory = False And LoadIfNotInMemory = True And r.LoadThread = Null
r.Read()
r.InMemory = True
EndIf
Return r
EndIf

Next


Print "Record List"

For Local r:TDataRecord = EachIn mRecords
Print "Record:" + r.Name
Next
Print "Fin"

Notify "Record Named:" + name + " was not found in db."

End Method

Method SyncIndex()

mRecords.Clear()

Open()

mFile.Seek(0)

Local i:Int = mFile.ReadInt()

While i > 0



Local path:String = mfile.ReadLine()
Local dtype:String = mFile.ReadLine()
Local siz:Int = mFile.ReadInt()
Local nam:String = mFile.ReadLine()
Local d:TDataRecord

Select dtype.ToLower()
Case "zone"
d = TDataRecord(New TZoneRecord)
Case "texture"
d = TDataRecord(New TTextureRecord)
Case "map"
d = TDataRecord(New TMapRecord)
Case "light"
d = TDataRecord(New TLightRecord)
Default
Notify "Unsupported Data Type."
End Select

d.mPath = path
d.mDataType = dtype
d.mSize = siz
d.InMemory = False
d.InFile = True
d.Name = nam
mRecords.AddLast(d)
i:-1
Wend

Close()

End Method

Method WriteIndex()

Open()

mFile.Seek(0)

mFile.WriteInt(mRecords.Count())

For Local r:TDataRecord = EachIn mRecords

mFile.WriteLine(r.mPath)
mfile.WriteLine(r.mDataType)
mFile.WriteInt(r.mSize)
mFile.WriteLine(r.Name)

Next

Close()

End Method

Method Open()
If FileType(mMainPath) = 0
mFile = WriteFile(mMainPath)
CloseFile mFile
End If
mFile = OpenFile(mMainPath, True, True)
If mFile = Null
Notify "Could not open Database:" + mMainPath
End
End If
End Method

Method Close()

mFile.Close()

End Method

Method SyncFrom()


End Method

End Type
'
'--[ A.B.E Threading Component ]--
'
'
'-[
'
'
'Threads are objects that you are supposed to extend to utilize their functionality.
'
'See the Examples/Threading test for an easy to follow example.
'
'-]

SuperStrict

Import pub.threads
Import brl.linkedList

Type AMutex

Field mHandle:Int

Method New()

mHandle = CreateMutex()

End Method

Method Delete()

CloseMutex(mHandle)

End Method



Method Lock()

LockMutex(mHandle)

End Method

Method Unlock()

UnlockMutex(mHandle)

End Method




End Type


Type AThread

Field mHandle : Int


Method Init() Abstract

Method New()

mHandle = 0
WaitOnDelete = False


End Method

Field WaitOnDelete:Int

Method Delete()

If WaitOnDelete
WaitFor()
Else
detach()
EndIf

End Method


Method Run()

If mhandle <>0
Detach()
EndIf

Init()

mHandle = CreateThread(RunThread_A,Object(Self))

End Method

Method WaitFor:Object()
If mHandle = 0 Return Null
Local ret:Object = WaitThread(mHandle)
mHandle = 0
Return ret

End Method


Method Detach()
If mhandle=0 Return
DetachThread(mHandle)
mHandle = 0
End Method

Method ThreadLogic:Object() Abstract


End Type


Function RunThread_A:Object(thread:Object)

Local t:AThread = AThread(thread)

Return t.ThreadLogic()

End Function


Comments :


DavidSimon(Posted 1+ years ago)

 You'll have to comment out the example datarecord types. it just shows that to create a new type of record, you extend the base class and override a few methods.