Results 1 to 18 of 18

Thread: Save and load a class

  1. #1

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Posts
    118

    Save and load a class

    Hey,

    I need a code so I can save this class. The problem is that it cant be done with XML-serialazation because it as initial arrays. [Attribute(50,50), Tile(50,50) etc.)
    How will I save/load this class with initial arrays?

    Code:
    Public Class Map
    
        Public Attribute(50, 50) As AttributeRec
        Public Tile(50, 50) As LayerRec
    
        Public Npc(50) As MapNpcRec
        Public Item(50) As MapItemRec
    
        Public Structure MapItemRec
    
            Public X As Integer
            Public Y As Integer
            Public ItemID As Integer
            Public ItemAmmount As Integer
    
        End Structure
    
        Public Structure MapNpcRec
    
            Public SpawnX As Integer
            Public SpawnY As Integer
            Public X As Integer
            Public Y As Integer
            Public NpcID As Integer
    
        End Structure
    
        Public Structure LayerRec
    
            Public Ground As TileRec
            Public Mask As TileRec
            Public Mask2 As TileRec
            Public Fringe As TileRec
            Public Fringe2 As TileRec
    
        End Structure
    
        Public Structure TileRec
    
            Public imgX As Integer
            Public imgY As Integer
            Public Tileset As Integer
    
        End Structure
    
        Public Structure AttributeRec
    
            Public Attribute As Integer
            Public Value As Integer
    
        End Structure
    
    End Class
    thanks

  2. #2
    Fanatic Member BenJones's Avatar
    Join Date
    Mar 2010
    Location
    Wales UK
    Posts
    814

    Re: Save and load a class

    I used something like this before.
    http://www.vbforums.com/showthread.p...Structure-Easy

  3. #3

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Posts
    118

    Re: Save and load a class

    I can't get it work, I don't understand it

    I've done the following:
    Code:
        Public objMap(50) As Map
    Code:
        Private Sub SaveToolStripMenuItem_Click(sender As System.Object, e As System.EventArgs) Handles SaveToolStripMenuItem.Click
    
            objMap(0) = New Map
            objMap(0).Name = "Test Map"
            objMap(0).Tile(5, 5).Ground.imgX = 5
            objMap(0).Tile(5, 5).Ground.imgY = 5
            objMap(0).Tile(5, 5).Ground.Tileset = 1
    
            MapSL.SaveMap(0)
            MsgBox("SAVED")
    
        End Sub
    Code:
        Public Shared Sub SaveMap(ByVal Map As Integer)
    
            Dim FF As Integer = FreeFile()
    
            FileOpen(FF, Windows.Forms.Application.StartupPath & "/Maps/1.map", OpenMode.Binary, OpenAccess.Write)
    
            FilePutObject(FF, objMap(0))
            FileClose(FF)
    
        End Sub
    and if I use FilePut instead of FilePutObject I'll get the next warning:

    code
    Code:
        Public Shared Sub SaveMap(ByVal Map As Integer)
    
            Dim FF As Integer = FreeFile()
    
            FileOpen(FF, Windows.Forms.Application.StartupPath & "/Maps/1.map", OpenMode.Binary, OpenAccess.Write)
    
            FilePut(FF, objMap(0))
            FileClose(FF)
    
        End Sub
    warning:

    Code:
    Warning	1	'Public Sub FilePut(FileNumber As Object, Value As Object, [RecordNumber As Object = -1])' is obsolete: 'This member has been deprecated. Please use FilePutObject to write Object types, or coerce FileNumber and RecordNumber to Integer for writing non-Object types. http://go.microsoft.com/fwlink/?linkid=14202'.	C:\Users\Jim Paul\Dropbox\Prive\Game Editor 1.0\Game Editor 1.0\Game Editor 1.0\Map Editor\Map.vb	66	9	Game Editor 1.0

  4. #4
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Save and load a class

    Binary serialization is the solution, and it is far easier than writing to a file like that. However, it creates a binary file, which you won't be able to edit, or even easily view, by hand. Here's one thread of many on the subject:

    http://www.vbforums.com/showthread.php?699885

    In this thread, I show a pair of methods I use to serialize to a string for storage in My.Settings, but that could just as easily be serialized to a file, as well. There are many more examples if you search on Binary Serialization.
    My usual boring signature: Nothing

  5. #5

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Posts
    118

    Re: Save and load a class

    Quote Originally Posted by Shaggy Hiker View Post
    Binary serialization is the solution, and it is far easier than writing to a file like that. However, it creates a binary file, which you won't be able to edit, or even easily view, by hand. Here's one thread of many on the subject:

    http://www.vbforums.com/showthread.php?699885

    In this thread, I show a pair of methods I use to serialize to a string for storage in My.Settings, but that could just as easily be serialized to a file, as well. There are many more examples if you search on Binary Serialization.
    I don't understand the code

    Code:
        Private Function SerializeTheme() As String
            If mConfiguration IsNot Nothing AndAlso mConfiguration.ThemeID <> -1 Then
                Try
                    Dim bf As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
                    Dim mStream As New System.IO.MemoryStream
                    Dim bReader As New System.IO.BinaryReader(mStream)
    
                    bf.Serialize(mStream, mConfiguration)
                    mStream.Position = 0
    
                    Return Convert.ToBase64String(bReader.ReadBytes(CInt(mStream.Length)))
                Catch ex As Exception
                    Windows.Forms.MessageBox.Show("Failed while saving the theme. The default will be used next time. The error message was: " & Environment.NewLine & Environment.NewLine & ex.Message, "Serial Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
                    Return String.Empty
                End Try
            Else
                Return String.Empty
            End If
        End Function
    
        Private Shared Function DeSerializeTheme(ByVal themeAsString As String) As ThemeWrapper
            Dim bf As New System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
            Dim mStream As New System.IO.MemoryStream
            Dim bWriter As New System.IO.BinaryWriter(mStream)
    
            If themeAsString = String.Empty Then
                Return Nothing
            End If
            Try
                bWriter.Write(Convert.FromBase64String(themeAsString))
                mStream.Position = 0
    
                Return DirectCast(bf.Deserialize(mStream), ThemeWrapper)
            Catch ex As Exception
                Return Nothing
            End Try
    
        End Function
    But also, you said

    Binary serialization is the solution, and it is far easier than writing to a file like that. However, it creates a binary file, which you won't be able to edit, or even easily view, by hand.
    The file should be readable by another application. This is because I work with a map editor. The main game should read the map (the file you create) - what you can make with the map editor. I have not build in my map editor in my game. So it wont be handy to save it in my.settings

    Isn't there an easy way to save a class with initial arrays?

  6. #6
    Fanatic Member BenJones's Avatar
    Join Date
    Mar 2010
    Location
    Wales UK
    Posts
    814

    Re: Save and load a class

    and if I use FilePut instead of FilePutObject I'll get the next warning:

    have you tryed putting FilePutObject for the link I suguested instade of fileput as it states in the error.
    here something else I found to duno if it's any good.

    http://www.programmersheaven.com/mb/...t-into-a-file/
    Last edited by BenJones; Jan 22nd, 2013 at 06:49 AM.

  7. #7
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Save and load a class

    Readable by a different process certainly does complicate binary serialization, because information about the serialization context is stored into the binary stream. This means that to use it between two different apps, the binary serialization would have to be performed in a dll that both apps referenced. That isn't all that hard to do, since you'd only need two functions in the dll, but it is certainly harder.

    Still, you may say that you don't understand the code, but I'm storing an object of any arbitrary complexity using 6 lines of which three are object declarations, so you'd be hard pressed to come up with something that is more versatile and efficient.

    There isn't some inherently "easy" way to save an array, nor can there be if you think about it. Your array is an array of objects that contain 2D arrays of objects that, themselves, contain members or structures. If you were to lay that out in memory, what would it look like? Ultimately, it would look like a whole series of bytes, since arrays are stored in order. However, the actual array only need hold the address of the objects that it contains, so storing the bytes that make up the array would be entirely meaningless, since those bytes would be addresses for memory that would immediately go away when the program unloaded, and they wouldn't be restored the same way except by accident. So, how would you expect it to be simple to store such complex data in any simple fashion if the data doesn't even have to exist in contiguous memory blocks in memory?

    In some way, you are hoping to have a mechanism that will hide the real difficulty of the layout of the complex data you wish to store. In both approaches, you are looking at storage into a binary file, where all the complexity is hidden behind some magic that you need not understand. So, the answer is: No, there is no simple solution, nor can there be, but binary serialization will work and is simple, even if you don't understand it, and the FilePut method is just an older version (and potentially less effective) of working with binary files.
    My usual boring signature: Nothing

  8. #8

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Posts
    118

    Re: Save and load a class

    Quote Originally Posted by Shaggy Hiker View Post
    Readable by a different process certainly does complicate binary serialization, because information about the serialization context is stored into the binary stream. This means that to use it between two different apps, the binary serialization would have to be performed in a dll that both apps referenced. That isn't all that hard to do, since you'd only need two functions in the dll, but it is certainly harder.

    Still, you may say that you don't understand the code, but I'm storing an object of any arbitrary complexity using 6 lines of which three are object declarations, so you'd be hard pressed to come up with something that is more versatile and efficient.

    There isn't some inherently "easy" way to save an array, nor can there be if you think about it. Your array is an array of objects that contain 2D arrays of objects that, themselves, contain members or structures. If you were to lay that out in memory, what would it look like? Ultimately, it would look like a whole series of bytes, since arrays are stored in order. However, the actual array only need hold the address of the objects that it contains, so storing the bytes that make up the array would be entirely meaningless, since those bytes would be addresses for memory that would immediately go away when the program unloaded, and they wouldn't be restored the same way except by accident. So, how would you expect it to be simple to store such complex data in any simple fashion if the data doesn't even have to exist in contiguous memory blocks in memory?

    In some way, you are hoping to have a mechanism that will hide the real difficulty of the layout of the complex data you wish to store. In both approaches, you are looking at storage into a binary file, where all the complexity is hidden behind some magic that you need not understand. So, the answer is: No, there is no simple solution, nor can there be, but binary serialization will work and is simple, even if you don't understand it, and the FilePut method is just an older version (and potentially less effective) of working with binary files.
    I got this code from a VB6 Map Editor what works fine.

    Code:
    ' **********
    ' ** Maps **
    ' **********
    Sub SaveMap(ByVal mapNum As Long)
        Dim filename As String
        Dim F As Long
        Dim x As Long
        Dim y As Long
        filename = App.Path & "\data\maps\map" & mapNum & ".dat"
        F = FreeFile
        
        Open filename For Binary As #F
        Put #F, , Map(mapNum).Name
        Put #F, , Map(mapNum).Music
        Put #F, , Map(mapNum).Revision
        Put #F, , Map(mapNum).Moral
        Put #F, , Map(mapNum).Up
        Put #F, , Map(mapNum).Down
        Put #F, , Map(mapNum).Left
        Put #F, , Map(mapNum).Right
        Put #F, , Map(mapNum).BootMap
        Put #F, , Map(mapNum).BootX
        Put #F, , Map(mapNum).BootY
        Put #F, , Map(mapNum).MaxX
        Put #F, , Map(mapNum).MaxY
    
        For x = 0 To Map(mapNum).MaxX
            For y = 0 To Map(mapNum).MaxY
                Put #F, , Map(mapNum).Tile(x, y)
            Next
        Next
    
        For x = 1 To MAX_MAP_NPCS
            Put #F, , Map(mapNum).Npc(x)
        Next
        Close #F
        
        DoEvents
    End Sub
    
    Sub SaveMaps()
        Dim i As Long
    
        For i = 1 To MAX_MAPS
            Call SaveMap(i)
        Next
    
    End Sub
    isn't it just possible to convert this code to vb 2010? This code isn't hard at all. Is this possible or not?

  9. #9
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Save and load a class

    Yeah, VB6 had a means to insert things into binary files. There have been a few threads on here talking about that. I think one of them, about a year ago, found a way to do something like that in .NET. However, what they were trying to do was to edit a single item in a binary file that contained many such items. In other words, they wanted to be able to access random items in the file. For a map editor, that's almost certainly a bad idea. It may seem to have some appeal, since you would want to be able to edit points in the map, but it will always be easier to do so to a map in memory rather than a map in a file, so the editor should load the map and edit the map in memory, then write the map back out again. Therefore, editing a single element in the file isn't necessary at all, so the solution from that thread, if there even was a solution (I may be remembering it wrong) doesn't really apply to your situation.

    Still, the bottom line is that .NET and VB6 handle binary files in a different fashion, so it may not be possible. I've written a couple different map editors, and since binary serialization does the job so simply, I just use that. I agree that the code you have posted looks pretty simple, but the code I posted was six lines for saving and another six for loading, regardless of the size of the object. What that code you just posted did is impressive when you think about it. What they are doing is taking objects and writing out every single property one after the other. They could just as easily have written to a text file using that technique, as the organization in the file would be simple indeed. If you consider what little you have shown of your maps, you'd have to write a vastly more complex routine to achieve the same end using that code. After all, from what little you posted, consider what you would have to do to save the Tile array alone:

    For each tile in the 50x50 array, write out each member. However, since each member is itself an object, you'd have to write out not just the members, but all the members of each member. To read it back in you'd have to create the LayerRec items, then load the values from the file back into them. By my calculation, that's 15 writes for each tile, though the tiles can be written sequentially in a loop, as noted.

    If you are willing to do that, why not write to a text file? They wouldn't rely on old VB6 methods that may or may not work quite the same, and the only difference would be that you would be able to edit the textfile in any text editor, such as notepad.
    My usual boring signature: Nothing

  10. #10

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Posts
    118

    Re: Save and load a class

    Quote Originally Posted by Shaggy Hiker View Post
    Yeah, VB6 had a means to insert things into binary files. There have been a few threads on here talking about that. I think one of them, about a year ago, found a way to do something like that in .NET. However, what they were trying to do was to edit a single item in a binary file that contained many such items. In other words, they wanted to be able to access random items in the file. For a map editor, that's almost certainly a bad idea. It may seem to have some appeal, since you would want to be able to edit points in the map, but it will always be easier to do so to a map in memory rather than a map in a file, so the editor should load the map and edit the map in memory, then write the map back out again. Therefore, editing a single element in the file isn't necessary at all, so the solution from that thread, if there even was a solution (I may be remembering it wrong) doesn't really apply to your situation.

    Still, the bottom line is that .NET and VB6 handle binary files in a different fashion, so it may not be possible. I've written a couple different map editors, and since binary serialization does the job so simply, I just use that. I agree that the code you have posted looks pretty simple, but the code I posted was six lines for saving and another six for loading, regardless of the size of the object. What that code you just posted did is impressive when you think about it. What they are doing is taking objects and writing out every single property one after the other. They could just as easily have written to a text file using that technique, as the organization in the file would be simple indeed. If you consider what little you have shown of your maps, you'd have to write a vastly more complex routine to achieve the same end using that code. After all, from what little you posted, consider what you would have to do to save the Tile array alone:

    For each tile in the 50x50 array, write out each member. However, since each member is itself an object, you'd have to write out not just the members, but all the members of each member. To read it back in you'd have to create the LayerRec items, then load the values from the file back into them. By my calculation, that's 15 writes for each tile, though the tiles can be written sequentially in a loop, as noted.

    If you are willing to do that, why not write to a text file? They wouldn't rely on old VB6 methods that may or may not work quite the same, and the only difference would be that you would be able to edit the textfile in any text editor, such as notepad.
    Oh really.. Thats dumb.. I tough the code to save a map would be easy. I've finished my game editors with save functions except the map editor. This because I can't get it saved as you understand.

    my teleport editor, Npc editor, Item Editor, Skill Editor, Shop editor works perfectly with XML-serialization because there are no initial arrays.

    Code:
    Imports System.IO
    Imports System.Xml.Serialization
    
    Public Class Teleport
    
        Public Name As String
        Public Map As Integer
        Public X As Integer
        Public Y As Integer
    
    End Class
    
    Public Class TeleportSL
    
        Public Shared Function LoadTeleport(ByVal fileName As String) As Teleport
    
            Dim ser As New XmlSerializer(GetType(Teleport))
            Dim fs As New FileStream(fileName, FileMode.Open)
            Dim ret As Teleport
    
            ret = DirectCast(ser.Deserialize(fs), Teleport)
    
            fs.Close()
            fs.Dispose()
    
            Return ret
    
        End Function
    
        Public Shared Sub SaveTeleport(ByVal teleport As Teleport, ByVal fileName As String)
    
            Dim ser As New XmlSerializer(GetType(Teleport))
            Dim fs As New FileStream(fileName, FileMode.Create)
    
            ser.Serialize(fs, teleport)
    
            fs.Close()
            fs.Dispose()
    
        End Sub
    
    End Class
    What you say is right, because with the code below (I made before your last post) this saving the map correctly - but it won't load it back. the map name will be "" when I load the file.
    Code:
    Public Module Map
    
        Public Const MAX_MAPS = 10
    
        Public xMap(0 To MAX_MAPS) As MapRec
    
        Public Structure MapRec
    
            Public Name As String
            Public Tile(,) As TileRec
    
            Public MaxX As Integer
            Public MaxY As Integer
    
        End Structure
    
        Public Structure TileRec
    
            Public Layer() As TileDataRec
            Public Attribute As Integer
    
        End Structure
    
        Public Structure TileDataRec
    
            Public X As Integer
            Public Y As Integer
            Public Tileset As Integer
    
        End Structure
    
    End Module
    
    Public Class LoadMap
    
        Public Shared Sub LoadMaps()
    
            Dim filename As String
            Dim F As Integer = FreeFile()
    
            filename = Application.StartupPath & "/" & 1 & ".dat"
    
            FileOpen(F, filename, OpenMode.Binary, OpenAccess.Read)
            FileGet(F, xMap(1).Name)
    
            FileClose(F)
    
        End Sub
    
    End Class
    
    Public Class SaveMap
    
        Public Shared Sub SaveMap(ByVal MapNum As Long)
    
            Dim FileName As String
            Dim F As Integer
    
            F = FreeFile()
            FileName = Application.StartupPath & "/" & MapNum & ".dat"
    
            FileOpen(F, FileName, OpenMode.Binary, OpenAccess.Write)
            FilePut(F, xMap(MapNum).Name)
            FileClose(F)
    
            Application.DoEvents()
    
        End Sub
    
    End Class
    Can you make me a working save function for my 2D-Map Arrays?

  11. #11
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Save and load a class

    You're a whole lot closer than you give yourself credit for. There are some limitations to XML serialization, and this may be one of them, but check that first. An XML serialized file would work a bit more easily than a binary serialized file for what you are trying to do. The nice thing about an XML serialized file is that you can look to see whether it worked, and how it worked, and do so easily enough. Use either Wordpad or Notepad (one works well for this type of file, the other really does not, but I forget which it is) to open the file. XML has plenty of oddities in it, but even if you are not familiar with XML, it should look VERY familiar. In fact, it should show all of your data. However, it may not, because I seem to remember reading that XML serialization didn't work on arrays. I haven't used it, so I have no experience with it, but by opening the file you will probably be able to see whether or not all your data is there. Of course, if it IS all there, it would be very tedious to read, so you won't want to check everything. Basically, I would expect that either you would have barely anything, only one tile, or all of them. If you have all of them, then the problem lies with reading them back in. If you have one of the first two options, then XML serialization failed. You could start a different thread on that if you still wanted to pursue it. You are very close, as it stands, the only real question I have is whether or not XML serialization even works on arrays.

    In any case, if you look at the binary serialization and compare it to what you already have, you will see that the two are quite similar. I wrapped things in an exception handler because you can never really trust files, but aside from that, the lines are really quite similar. You have an XMLSerializer, I have a BinaryFormatter. I used a memorystream, you used a file stream, but a stream is a stream, and a filestream is the one you want to be using. I then added in a bit about taking the stream and converting the bytes to a string, but that was just so I could put the data into a My.Settings property. Since you aren't doing that, you don't need any such thing.

    Unfortunately, that does leave a couple complications. The first one is utterly trivial, as you need to decorate all structures that you want to serialize with the <Serializable()> attribute. You'd just put that before Public. You can do some goofy stuff with that, but you don't need to. I'm not quite sure what that attribute does, but I suspect it may have to do with how the structure is arranged in memory. In any case, you can't serialize anything that lacks the attribute.

    The other complication is as I noted: Binary serialization includes the application that serialized it, and you can't deserialize it with a different application. XMLSerialization, and that binary file thing from VB6 rather finessed the problem because there isn't any type information included in any of that. XMLSerialization is just plain text with a minimal amount of structuring, whereas the VB6 routine was just writing some bytes. An integer probably took four bytes in such a file, and there was no problem with your reading back those four, or reading back only two of them, or reading back the wrong four. If you didn't do the reading exactly the way the data was organized in the file, you'd get something back, but it would be junk. What this meant was that using either of those two types of files, your map editor and your main program didn't have to have the same types at all. Most likely, you would copy the types from one to the other, so they both would have the same, but there would be nothing enforcing that other than your own whim (XML serialization would enforce it to some extent, but only very lightly, and you could circumvent that easily). In the map editor, you could name the structures something different, or the properties, or have fewer properties, or have them be different types (with some limitations). They would be the same only by chance.

    Binary serialization doesn't allow that. If you serialize an array of MapRec, then any program that deserializes it has to have access to the MapRec type. It's not enough to just have a type called MapRec in the application, nor is it enough to have the right properties in that type. Instead, the program that deserializes the object must have the same object that was serialized, and therefore it must be the same Assembly. That means that you can't have one program serialize and a different program be able to do anything with that file. I haven't found a way around this, but then again, I haven't really bothered trying. In one case, I was serializing structures and sending them to various programs on various computers using UDP. The solution is really simple, but does take some organization. What I did was to create a dll (which is laughably simple in .NET), put the Serialize and Deserialize methods into that dll as public functions in a module, then I also added the types that would be shared between the programs (all the message structures, but you could do the same with the structures in your map). This isn't just necessary for the binary serialization, you would find it to be kind of convenient for what you are doing even if you weren't doing any serialization. After all, by creating such a dll and referencing the dll from both the program and the map editor, you have the same objects available in each. Otherwise, if you change the design of the object in one, you had better remember to change it in the other. By putting the common structures and classes into a dll, a change to the dll is seen by both projects. And then the problem with binary serialization goes away and the actual code is virtually what you already wrote for XMLSerialization except that it uses a binaryformatter instead of an XMLSerializer.

    Of course, it also means that nobody can really write such a thing for you, though they might give you an example, but you barely need an example as you are so close already. Since the dll would be yours, you'd need to write it. If you haven't created one before, it might seem daunting, but you're already way beyond that point, since a dll would just be a new project of type Class Library, but is otherwise just like the other projects you've created.
    My usual boring signature: Nothing

  12. #12

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Posts
    118

    Re: Save and load a class

    Quote Originally Posted by Shaggy Hiker View Post
    You're a whole lot closer than you give yourself credit for. There are some limitations to XML serialization, and this may be one of them, but check that first. An XML serialized file would work a bit more easily than a binary serialized file for what you are trying to do. The nice thing about an XML serialized file is that you can look to see whether it worked, and how it worked, and do so easily enough. Use either Wordpad or Notepad (one works well for this type of file, the other really does not, but I forget which it is) to open the file. XML has plenty of oddities in it, but even if you are not familiar with XML, it should look VERY familiar. In fact, it should show all of your data. However, it may not, because I seem to remember reading that XML serialization didn't work on arrays. I haven't used it, so I have no experience with it, but by opening the file you will probably be able to see whether or not all your data is there. Of course, if it IS all there, it would be very tedious to read, so you won't want to check everything. Basically, I would expect that either you would have barely anything, only one tile, or all of them. If you have all of them, then the problem lies with reading them back in. If you have one of the first two options, then XML serialization failed. You could start a different thread on that if you still wanted to pursue it. You are very close, as it stands, the only real question I have is whether or not XML serialization even works on arrays.

    In any case, if you look at the binary serialization and compare it to what you already have, you will see that the two are quite similar. I wrapped things in an exception handler because you can never really trust files, but aside from that, the lines are really quite similar. You have an XMLSerializer, I have a BinaryFormatter. I used a memorystream, you used a file stream, but a stream is a stream, and a filestream is the one you want to be using. I then added in a bit about taking the stream and converting the bytes to a string, but that was just so I could put the data into a My.Settings property. Since you aren't doing that, you don't need any such thing.

    Unfortunately, that does leave a couple complications. The first one is utterly trivial, as you need to decorate all structures that you want to serialize with the <Serializable()> attribute. You'd just put that before Public. You can do some goofy stuff with that, but you don't need to. I'm not quite sure what that attribute does, but I suspect it may have to do with how the structure is arranged in memory. In any case, you can't serialize anything that lacks the attribute.

    The other complication is as I noted: Binary serialization includes the application that serialized it, and you can't deserialize it with a different application. XMLSerialization, and that binary file thing from VB6 rather finessed the problem because there isn't any type information included in any of that. XMLSerialization is just plain text with a minimal amount of structuring, whereas the VB6 routine was just writing some bytes. An integer probably took four bytes in such a file, and there was no problem with your reading back those four, or reading back only two of them, or reading back the wrong four. If you didn't do the reading exactly the way the data was organized in the file, you'd get something back, but it would be junk. What this meant was that using either of those two types of files, your map editor and your main program didn't have to have the same types at all. Most likely, you would copy the types from one to the other, so they both would have the same, but there would be nothing enforcing that other than your own whim (XML serialization would enforce it to some extent, but only very lightly, and you could circumvent that easily). In the map editor, you could name the structures something different, or the properties, or have fewer properties, or have them be different types (with some limitations). They would be the same only by chance.

    Binary serialization doesn't allow that. If you serialize an array of MapRec, then any program that deserializes it has to have access to the MapRec type. It's not enough to just have a type called MapRec in the application, nor is it enough to have the right properties in that type. Instead, the program that deserializes the object must have the same object that was serialized, and therefore it must be the same Assembly. That means that you can't have one program serialize and a different program be able to do anything with that file. I haven't found a way around this, but then again, I haven't really bothered trying. In one case, I was serializing structures and sending them to various programs on various computers using UDP. The solution is really simple, but does take some organization. What I did was to create a dll (which is laughably simple in .NET), put the Serialize and Deserialize methods into that dll as public functions in a module, then I also added the types that would be shared between the programs (all the message structures, but you could do the same with the structures in your map). This isn't just necessary for the binary serialization, you would find it to be kind of convenient for what you are doing even if you weren't doing any serialization. After all, by creating such a dll and referencing the dll from both the program and the map editor, you have the same objects available in each. Otherwise, if you change the design of the object in one, you had better remember to change it in the other. By putting the common structures and classes into a dll, a change to the dll is seen by both projects. And then the problem with binary serialization goes away and the actual code is virtually what you already wrote for XMLSerialization except that it uses a binaryformatter instead of an XMLSerializer.

    Of course, it also means that nobody can really write such a thing for you, though they might give you an example, but you barely need an example as you are so close already. Since the dll would be yours, you'd need to write it. If you haven't created one before, it might seem daunting, but you're already way beyond that point, since a dll would just be a new project of type Class Library, but is otherwise just like the other projects you've created.

    But I wonder, how do everyone make a map editor then? I mean, each map editor should use 2D-arrays because you have a X and a Y

  13. #13
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Save and load a class

    My map editor uses the technique I described: The map elements and the serialization routines are all found in a class library project that is referenced by the map editor and the main program.

    Oddly, I didn't use a 2D array, either, though I agree with you that most would. For a reason that I have now forgotten, I used a 1D array. All 2D arrays are really 1D arrays in memory, anyways. You first have all the elements of row 0, then all the elements of row 1, and so forth. In memory, they are just laid out in sequence like a 1D array. To access element (x,y), you get element ((y * rowsize) + x). The compiler does all that for you in a 2D array.

    I have the code for the serializer I used on a different computer, but I'm not sure that it would help anyways. After all, the serialization code would be the same, but the map elements certainly wouldn't be.
    My usual boring signature: Nothing

  14. #14

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Posts
    118

    Re: Save and load a class

    hmm.. interesting.. Indeed it is possible to use 1D arrays and just count the total tiles of the map by MaxX * MaxY. So it could be easily saved in an xml file

  15. #15
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Save and load a class

    Yeah, it is possible....but having done it, I'm not so sure that it's a good idea. Referencing a single element in a 2D array is pretty simple: X and Y. Referencing a single element in a 2D array mapped to a 1D array takes an equation: (Y * width) + X. Even though I created it in a class where I could write the method once and it would work, I found that I was always doing some odd things. For instance, I might shift some elements up and left, at which point I'd be trying to figure out how that changed everything. It worked, but I'm not sure it was in any way easier than just using a 2D array.
    My usual boring signature: Nothing

  16. #16

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Posts
    118

    Re: Save and load a class

    Quote Originally Posted by Shaggy Hiker View Post
    Yeah, it is possible....but having done it, I'm not so sure that it's a good idea. Referencing a single element in a 2D array is pretty simple: X and Y. Referencing a single element in a 2D array mapped to a 1D array takes an equation: (Y * width) + X. Even though I created it in a class where I could write the method once and it would work, I found that I was always doing some odd things. For instance, I might shift some elements up and left, at which point I'd be trying to figure out how that changed everything. It worked, but I'm not sure it was in any way easier than just using a 2D array.
    well it could be easy if you use some functions for it. I might give this a try

    Code:
    Public Function GetTile(Byval MaxMapX as integer, Byval X as integer, Byval Y as integer) As Integer
    
    Return Math.Floor(width * y + x)
    
    End function
    the only problem will be how to get the specific X and Y back what the tile is - I cant figure out what the calculation will be

    Code:
    Public Function GetX(Byval Tile as integer) As Integer
    
    Return 
    
    End Function

    Code:
    Public Function GetY(Byval Tile as integer) As Integer
    
    Return
    
    End Function

  17. #17
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    40,104

    Re: Save and load a class

    I would suggest that it be one method:

    Code:
    Public Function GetPoint(Tile As integer) As Point 'Found in System.Drawing if this is not defined
     Return New Point(Tile Mod width, Tile \ width)
    End Function
    My usual boring signature: Nothing

  18. #18

    Thread Starter
    Lively Member
    Join Date
    Jan 2011
    Posts
    118

    Re: Save and load a class

    Quote Originally Posted by Shaggy Hiker View Post
    I would suggest that it be one method:

    Code:
    Public Function GetPoint(Tile As integer) As Point 'Found in System.Drawing if this is not defined
     Return New Point(Tile Mod width, Tile \ width)
    End Function
    thanks, amazing! I'll look what I can do with my map editor now

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width