Serializer

Übersicht BlitzBasic Codearchiv

Neue Antwort erstellen

DAK

Betreff: Serializer

BeitragMi, Jul 09, 2014 20:29
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich wollte schon länger das hier machen, da es das in Java gibt, und dort einiges stark erleichtert. Jetzt bin ich endlich mal dazu gekommen.

Serialisierung bedeutet, ein Objekt so zu verpacken, dass es abspeicherbar oder verschickbar ist. Deserialisierung ist das Gegenstück dazu, wo ein verpacktes Objekt wieder entpackt wird, und dadurch verwendbar gemacht wird.
Dadurch kann man ein beliebiges Objekt mit nur einer Zeile Code verschicken/empfangen oder abspeichern/auslesen.

Für dieses Framework wird die Pointers-Userlib benötigt.

Was bringt diese Library?
Mit Hilfe dieser Library kann ein beliebiges Objekt mit gerade mal ein bis vier Zeilen Code (je nach benötigten Metadaten) abgespeichert oder über einen Internet-Stream verschickt werden. Das vereinfacht das Netzwerkprogrammieren sowie das Abspeichern enorm. Gleichzeitig packt die Libary die gegebenen Daten gut zusammen, was für einen niedrigeren Speicherbedarf sorgt.


Diese Funktionen kommen hierdurch dazu:
Code: [AUSKLAPPEN]
    serialize(ptr%, format$, stream%)
Serialisiert ein Objekt und schreibt es in den gegebenen Stream hinein.
ptr%    : Pointer auf das Objekt, das serialisiert werden soll (bekommt man mittels pointers_getPointer()
format$ : Hier sollten alle Felder des Objekts in der folgenden Syntax stehen:
         b = byte
         h = short
         i = int
         f = float
         s = String
         x = Feld wird ignoriert
stream$ : Ein File- oder Netzwerk-Stream in den geschrieben werden soll

    deserialize(ptr%, format$, stream%)
Liest ein Objekt aus dem Stream aus und schreibt die Werte in das gegebene Objekt hinein.
ptr%    : Pointer auf das Objekt, in deserialisiert werden soll (bekommt man mittels pointers_getPointer()
format$ : Muss das gleiche Format sein, wie beim Serialisieren
stream$ : Ein File- oder Netzwerk-Stream aus dem gelesen werden soll


Beispielcode für Speichern:
BlitzBasic: [AUSKLAPPEN]
;Author: David Krywult

Include "serializer.bb"

Const TAnimalTypeNr = 1
Type TAnimal
Field x#
Field y#
Field hp%
Field image% ;Handles duerfen nicht serialisiert/deserialisiert werden!
Field species$
Field name$
End Type
;Format: ffixss (alles ausser image% wird gespeichert)

Const THouseTypeNr = 2
Type THouse
Field address$
Field number%
Field height#
End Type
;Format: sif (alles wird gespeichert)

Local dog1.TAnimal = New TAnimal
dog1\x# = 75.3
dog1\y# = 400.2
dog1\hp = 10
dog1\species$ = "Dog"
dog1\name$ = "Max"
dog1\image = CreateImage(20,20)

Local dog2.TAnimal = New TAnimal
dog2\x# = 12.3
dog2\y# = 46.7
dog2\hp = 80
dog2\species$ = "Dog"
dog2\name$ = "Hasso"
dog2\image = CreateImage(20,20)

Local cat.TAnimal = New TAnimal
cat\x# = 78.5
cat\y# = 88.5
cat\hp = 5
cat\species$ = "Cat"
cat\name$ = "Kitty"
cat\image = CreateImage(20,20)

Local house1.THouse = New THouse
house1\address = "Waldstrasse"
house1\number = 82
house1\height = 12.5

Local house2.THouse = New THouse
house2\address = "Dorfgasse"
house2\number = 70
house2\height = 8.9

Print("Initial state:")
printObjects()
Print("")
Print("Saving...")
saveObjects("animals.sav")
Print("Deleting...")
deleteObjects()
Print("")
Print("Current state (everything deleted):")
printObjects()
Print("")
Print("Loading...")
loadObjects("animals.sav")
Print("")
Print("Current state (everything reloaded):")
printObjects()
Input("Press Enter to close...")
End

Function saveObjects(path$)
stream% = WriteFile(path$)
For a.TAnimal = Each TAnimal
WriteByte(stream%, TAnimalTypeNr)
serialize(pointers_getPointer(a), "ffixss", stream%)
Next
For h.THouse = Each THouse
WriteByte(stream%, THouseTypeNr)
serialize(pointers_getPointer(h), "sif", stream%)
Next
CloseFile(stream%)
End Function

Function deleteObjects()
For a.TAnimal = Each TAnimal
If (a\image<>0) Then FreeImage a\image
Delete a
Next
For h.THouse = Each THouse
Delete h
Next
End Function

Function loadObjects(path$)
stream% = ReadFile(path$)
While (Not Eof(stream%))
typeNr = ReadByte(stream%)
If (typeNr=TAnimalTypeNr) Then
Local a.TAnimal = New TAnimal
deserialize(pointers_getPointer(a), "ffixss", stream%)
ElseIf (typeNr=THouseTypeNr) Then
Local h.THouse = New THouse
deserialize(pointers_getPointer(h), "sif", stream%)
EndIf
Wend
CloseFile(stream)
End Function

Function printObjects()
Print("")
Print("##### Animals:")
For a.TAnimal = Each TAnimal
Print("### "+a\species$+" "+a\name$+" ###")
Print("Pos: "+a\x#+"/"+a\y#)
Print("HP : "+a\hp)
Print("Image handle: "+a\image)
Next
Print("##### Houses:")
For h.THouse = Each THouse
Print("### "+h\address$+" "+h\number%+" ###")
Print("Height: "+h\height#)
Next
End Function


Beispielcode für Netzwerkübertragung:
BlitzBasic: [AUSKLAPPEN]
;Author: David Krywult

Include "serializer.bb"

Const WIDTH=800
Const HEIGHT=600

Const ISSERVER = False

Const SENDFREQ = 250 ;Sende alle 250 ms sofern möglich

Const ENABLE_CLIENT_SIMULATION = True

Const ENABLE_FRAME_INDEPENDENCE = True

Graphics(WIDTH, HEIGHT)

Const TNetTextTypeNr = 1
Const NetActionCreate = 1
Const NetActionUpdate = 2
Const NetActionDelete = 3
Type TNetText
Field x#
Field y#
Field xs#
Field ys#
Field txt$
End Type
;Format fuer Create: ffffs (Alles wird geschickt)
;Format fuer Delete: ffxxx (Geschwindigkeit wird nicht geschickt,
; da sich diese nicht aendert. Auch der
; Text ändert sich nicht, und muss somit
; nicht geschickt werden.)

Const MAX_TEXTS = 100
Dim texts.TNetText(MAX_TEXTS)
Global textCt = 0

If (ISSERVER) Then
runServer()
Else
runClient()
EndIf

Function runServer()
server% = CreateTCPServer(30000)
stream% = 0
While (stream=0)
Cls
stream% = AcceptTCPStream(server)
Text(WIDTH/2, HEIGHT/2, "Waiting for a client", True, True)
Flip(1)
Wend

nextSend = MilliSecs()+SENDFREQ
While (Not KeyHit(1))

Cls
Text(5, 5, "Press left mouse button", False, False)
If (MouseHit(1)) Then
createNetText(MouseX(), MouseY(), Rnd(-20,20), Rnd(-20,20), "Text "+textCt, stream%)
EndIf

updateTexts()
drawTexts()

If (nextSend<MilliSecs()) Then
sendNetTexts(stream%)
nextSend = MilliSecs()+SENDFREQ
EndIf

Flip(0)
Wend
End
End Function

Function runClient()
Cls
Text(WIDTH/2, HEIGHT/2, "Connecting...", True, True)
Flip(1)
stream% = OpenTCPStream("127.0.0.1", 30000)
If (stream%=0) Then
Cls
Text(WIDTH/2, HEIGHT/2, "Connection failed!", True, True)
Text(WIDTH/2, HEIGHT/2+50, "Press any key", True, True)
Flip(1)
WaitKey
End
EndIf
While (Not KeyHit(1))
Cls
If (ENABLE_CLIENT_SIMULATION) Then
updateTexts()
EndIf
receiveNetTexts(stream%)
drawTexts()

Flip(0)
Wend
End
End Function

Global lastUpdateMs = -1
Function updateTexts()
If (ENABLE_FRAME_INDEPENDENCE) Then
If (lastUpdateMs<>-1) Then
deltaT# = (MilliSecs()-lastUpdateMs)/1000.0
Else
deltaT# = 1.0/60.0
EndIf
lastUpdateMs = MilliSecs()

For t.TNetText = Each TNetText
t\x# = t\x#+t\xs#*deltaT#
t\y# = t\y#+t\ys#*deltaT#

t\x# = t\x# Mod WIDTH
t\y# = t\y# Mod HEIGHT
Next
Else
For t.TNetText = Each TNetText
t\x# = t\x#+t\xs#
t\y# = t\y#+t\ys#

t\x# = t\x# Mod WIDTH
t\y# = t\y# Mod HEIGHT
Next
EndIf
End Function

Function drawTexts()
For t.TNetText = Each TNetText
Text(t\x#, t\y#, t\txt$, True, True)
Next
End Function

Function createNetText(x#, y#, xs#, ys#, txt$, stream%)
If (textCt>=MAX_TEXTS) Then Return

Local t.TNetText = New TNetText
texts(textCt) = t
t\x# = x#
t\y# = y#
t\xs# = xs#
t\ys# = ys#
t\txt$ = txt$

WriteByte(stream%, TNetTextTypeNr)
WriteByte(stream%, NetActionCreate)
WriteInt(stream, textCt)
serialize(pointers_getPointer(t), "ffffs", stream%)

textCt = textCt+1
End Function

Function sendNetTexts(stream%)
For i=0 To textCt-1
WriteByte(stream%, TNetTextTypeNr)
WriteByte(stream%, NetActionUpdate)
WriteInt(stream, i) ;ID
serialize(pointers_getPointer(texts(i)), "ffxxx", stream%)
Next
End Function

Function receiveNetTexts(stream%)
While (ReadAvail(stream%)>0)
typeNr = ReadByte(stream%)
action = ReadByte(stream%)
id = ReadInt(stream%)

If (typeNr = TNetTextTypeNr) Then
If (action = NetActionCreate) Then
If (texts(id)=Null) Then
texts(id) = New TNetText
EndIf
deserialize(pointers_getPointer(texts(id)), "ffffs", stream%)
ElseIf (action = NetActionUpdate) Then
If (texts(id)=Null) Then
texts(id) = New TNetText
EndIf
deserialize(pointers_getPointer(texts(id)), "ffxxx", stream%)
ElseIf (action = NetActionDelete And texts(id)<>Null)
Delete texts(id)
EndIf
EndIf
Wend
End Function




Hier noch der Source-Code:
BlitzBasic: [AUSKLAPPEN]
;Author: David Krywult

Include "pointers.bb"


;format:
; b = byte
; h = short
; i = int
; f = float
; s = String
; x = Ignore field
Function serialize(ptr%, format$, stream%)
For i=0 To Len(format)-1
token$ = Mid(format,i+1,1)
If (token$="b") Then ;Byte
v = pointers_getInt(ptr + i*4) And 255
WriteByte(stream%,v)
ElseIf (token$="h") Then ;Short
v = pointers_getInt(ptr + i*4) And 65535
WriteShort(stream%,v)
ElseIf (token$="i") Then ;Int
v = pointers_getInt(ptr + i*4)
WriteInt(stream%,v)
ElseIf (token$="f") Then ;Float
vf# = pointers_getFloat(ptr + i*4)
WriteFloat(stream%,vf#)
ElseIf (token$="s") Then ;String
vs$ = pointers_getString(ptr + i*4)
WriteString(stream%,vs$)
ElseIf (token$="x") Then ;Ignore
Else
DebugLog("Unexpected token while serializing: "+token$)
EndIf
Next
End Function

;format:
; b = byte
; h = short
; i = int
; f = float
; s = String
; x = Do not fill field
Function deserialize(ptr%, format$, stream%)
For i=0 To Len(format)-1
token$ = Mid(format,i+1,1)
If (token$="b") Then ;Byte
v = ReadByte(stream%)
pointers_setInt(ptr + i*4, v)
ElseIf (token$="h") Then ;Short
v = ReadShort(stream%)
pointers_setInt(ptr + i*4, v)
ElseIf (token$="i") Then ;Int
v = ReadInt(stream%)
pointers_setInt(ptr + i*4, v)
ElseIf (token$="f") Then ;Float
vf# = ReadFloat(stream%)
pointers_setFloat(ptr + i*4, vf#)
ElseIf (token$="s") Then ;String
vs$ = ReadString(stream%)
pointers_setString(ptr + i*4, vs$)
ElseIf (token$="x") Then ;Do not fill field
Else
DebugLog("Unexpected token while deserializing: "+token$)
EndIf
Next
End Function



Und schlussendlich alles (inklusive der Pointers-Userlib) zusammen in einem Paket: *klick*


Wichtiger Hinweis:
Handles auf Bilder usw. dürfen nicht serialisiert werden, da sie auf einem anderen Computer / nach dem Speichern und Laden wohl nicht mehr an der gleichen Position liegen!


Edit: Habe das Netzwerk-Beispiel noch um Frameunabhängigkeit und Client-Side-Simulation erweitert, sowie die Senderate runtergeschraubt.

Update 11.07.2014:
-) Ein Update in der Pointers-Userlib hat Anpassungen im Serializer notwendig gemacht.

Neue Antwort erstellen


Übersicht BlitzBasic Codearchiv

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group