Novità

Ho cambiato i server su cui mi appoggio, mi scuso per eventuali inconvenienti ;)

[CODE] XNA 3.1 Content Manger in VB .NET

Ottenere il meglio dalle tue risorse artistiche.

[CODE] XNA 3.1 Content Manger in VB .NET

Messaggiodi Predator » 11/12/2009, 14:37

Update:
ho aggiornato il codice, ora supporta anche i file .X

Original:

Ciao ragazzi,
XNA usarlo in C# o in VB.Net è la stessa cosa, non cambia nulla. Ma come tutti sanno problema vero è proprio sono le risorse.
in C# vengono convertite in .xnb automaticamente dal Content Manager, mentre in VB no. E per caricarle occorrono altre strategie (per esempio utilizzare il LoadFromFile)
Ed è qui che vi offro la soluzione al problema :D
Ho cercato taaaaaaantissimo in internet ma non ho trovato soluzioni decenti, se non una vecchia per la versione 2.0 beta di xna.
Ho rivisitato il codice, l'ho testato e funziona tutto perfettamente. Ed è con piacere che lo pubblico in primis qui su xnaitalia :)
REQUISITI:
FrameWork 3.5 (sp1)
XNA 3.1

PROCEDURA:
al vostro progetto aggiungete una nuova classe e chiamatela VBContentManager.vb
incollate questo codice
Codice: Seleziona tutto
'Content Manager for XNA Studio 3.1 and FrameWork 3.5 (sp1)
'Class recoded by Predator

'The original class came from www.xnamachine.com

Imports Microsoft.Xna.Framework.Content
Imports Microsoft.Xna.Framework.Graphics
Imports Microsoft.Xna.Framework.Audio
Imports Microsoft.Xna.Framework

Public Class VBContentManager
    Inherits ContentManager

    Public Fonts As Hashtable(Of SpriteFont)
    Public Textures As Hashtable(Of Texture2D)
    Public SubTextures As Hashtable(Of Hashtable(Of Rectangle))
    Public Sounds As Hashtable(Of SoundBank)
    Public Effects As Hashtable(Of Effect)

    Private strContentprojFile, strProjectFolder, strExecutingFolder, strContentFolder As String
    Private objContent As List(Of ContentFile)
    Private intDupeSound, intDupeTexture, intDupeFont, intDupeEffect, intDupeModel As Integer

    Public Enum Platform
        Windows
        XBox360
    End Enum

    Public Enum ContentTypes
        Textures = 0
        Fonts = 1
        Sounds = 2
        Effects = 3
        Model = 4
    End Enum

    Private Enum ImporterName
        TextureImporter = 0
        FontDescriptionImporter = 1
        XactImporter = 2
        EffectImporter = 3
        XImporter = 4
    End Enum

    Private Enum ProcessorName
        TextureProcessor = 0
        FontDescriptionProcessor = 1
        XactProcessor = 2
        EffectProcessor = 3
        ModelProcessor = 4
    End Enum

    Public Structure ContentFile

        Public ContentType As ContentTypes
        Public File As System.IO.FileInfo
        Public Name As String

        Public Sub New(ByVal ContentType As ContentTypes, ByVal ContentFile As System.IO.FileInfo, ByVal Name As String)
            Me.ContentType = ContentType
            Me.File = ContentFile
            Me.Name = Name
        End Sub

    End Structure

    ''' <summary>
    ''' Creates a new ContentManager which has been extended with functionality to support a Visual Basic (or other non-C#) project
    ''' </summary>
    ''' <param name="ServiceProvider">Your game has a .Services property; send that in here.</param>
    ''' <param name="ContentFolder">Your content folder (a relative path, from your game's Project node as it appears in the Solution Explorer)</param>
    ''' <remarks></remarks>
    Public Sub New(ByVal ServiceProvider As IServiceProvider, ByVal ContentFolder As String)

        MyBase.New(ServiceProvider)

        With System.Reflection.Assembly.GetEntryAssembly.Location
            Me.strExecutingFolder = .Substring(0, .LastIndexOf("\"))
        End With

        With Me.strExecutingFolder
            With .Substring(0, .LastIndexOf("\") - 1)
                Me.strProjectFolder = .Substring(0, .LastIndexOf("\"))
            End With
        End With

        Me.strContentFolder = Me.strProjectFolder & "\" & ContentFolder

        Me.Fonts = New Hashtable(Of SpriteFont)
        Me.Textures = New Hashtable(Of Texture2D)
        Me.SubTextures = New Hashtable(Of Hashtable(Of Rectangle))
        Me.Sounds = New Hashtable(Of SoundBank)
        Me.Effects = New Hashtable(Of Effect)

    End Sub

    ''' <summary>
    ''' Attempts to load all assets which have been compiled by the Content Pipeline. Assets are placed into the respective Hash table (Fonts, Textures, et al)
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub LoadAllContent()

        Dim objCompiledContent As New List(Of IO.FileInfo)
        Dim strUnknownFiles As String = ""

        For Each file As IO.FileInfo In New IO.DirectoryInfo(Me.strExecutingFolder).GetFiles("*.xnb", IO.SearchOption.AllDirectories)

            Try

                'Font?

                With file.FullName.ToLower
                    Me.Fonts.Add(file.Name.Replace(file.Extension, ""), Me.Load(Of SpriteFont)(.Replace(Me.strExecutingFolder & "\", "").Replace(file.Extension, "")))
                End With

            Catch notAFont As Exception

                Try

                    'Texture2D?

                    With file.FullName
                        Me.Textures.Add(file.Name.Replace(file.Extension, ""), Me.Load(Of Texture2D)(.Replace(Me.strExecutingFolder & "\", "").Replace(file.Extension, "")))
                    End With

                    'Is this a sheet w/ a rectangle map?  If so, load the rectangle map

                    If IO.File.Exists(file.FullName.Replace(file.Extension, ".map")) Then
                        Me.LoadMap(file.Name.Replace(file.Extension, ""), file.FullName.Replace(file.Extension, ".map"))
                    End If

                Catch notATexture2D As Exception

                    Try

                        'Sound?

                        With file.FullName.ToLower
                            Me.Sounds.Add(file.Name.Replace(file.Extension, ""), Me.Load(Of SoundBank)(.Replace(Me.strExecutingFolder & "\", "").Replace(file.Extension, "")))
                        End With

                    Catch notASoundBank As Exception

                        Try

                            'Effect?

                            With file.FullName.ToLower
                                Me.Effects.Add(file.Name.Replace(file.Extension, ""), Me.Load(Of Effect)(.Replace(Me.strExecutingFolder & "\", "").Replace(file.Extension, "")))
                            End With

                        Catch unknown As Exception

                            strUnknownFiles &= vbCrLf & file.FullName

                        End Try

                    End Try

                End Try

            End Try

        Next

        If strUnknownFiles <> "" Then

            MsgBox("The VBContentManager was unable to determine the correct loader for:" & vbCrLf & _
            strUnknownFiles & vbCrLf & vbCrLf & _
            "Unless loaded by something else, the above content won't be available at runtime." & vbCrLf & vbCrLf & _
            "This application may become unstable as a result.")

        End If

    End Sub

    Private Sub LoadMap(ByVal strTextureNameName As String, ByVal strMapFile As String)

        Dim objReader As IO.StreamReader
        Dim strMapData As String
        Dim strLine() As String
        Dim strItem() As String

        objReader = New IO.StreamReader(strMapFile)

        Me.SubTextures.Add(strTextureNameName, New Hashtable(Of Rectangle))

        strMapData = objReader.ReadToEnd

        objReader.Close()

        objReader.Dispose()

        strLine = strMapData.Split(vbCrLf.ToCharArray, System.StringSplitOptions.RemoveEmptyEntries)

        For Each strMapItem As String In strLine

            strItem = strMapItem.Split(",".ToCharArray, System.StringSplitOptions.RemoveEmptyEntries)

            Me.SubTextures(strTextureNameName).Add(strItem(0), New Rectangle(CInt(strItem(1)), CInt(strItem(2)), CInt(strItem(3)), CInt(strItem(4))))

        Next

    End Sub

    ''' <summary>
    ''' Compiles the VB Content Pipeline
    ''' </summary>
    ''' <param name="stealth">Hide/Show the MSBuild window during the compile process</param>
    ''' <param name="platform">If there's a way the Xbox360 will work with VB, you could pass in the Xbox parameter as a target platform to MSBuild.  But it's Windows by default.</param>
    ''' <remarks></remarks>
    Public Sub CompileContent(ByVal stealth As Boolean, Optional ByVal platform As Platform = VBContentManager.Platform.Windows)

        Dim objProcess As Process
        Dim objPSI As New Diagnostics.ProcessStartInfo

        Me.objContent = New List(Of ContentFile)

        Me.HarvestContent()

        If Me.objContent.Count > 0 Then

            Me.BuildContentProj(platform)

            Try 'to write the content project file to disk

                Using TempStreamWriter As System.IO.StreamWriter = New System.IO.StreamWriter(Me.strProjectFolder & "\Content.contentproj", False)

                    With TempStreamWriter

                        .Write(Me.strContentprojFile)
                        .Close()

                    End With

                End Using

                Try

                    With objPSI
                        .FileName = Environment.GetEnvironmentVariable("Windir") & "\Microsoft.NET\Framework\v3.5\MSBuild.exe"
                        .Arguments = """" & Me.strProjectFolder & "\Content.contentproj""" & _
                        " /verbosity:normal" & _
                        " /l:FileLogger,Microsoft.Build.Engine;logfile=""" & Me.strProjectFolder & "\Content.log"""
                        If stealth Then
                            .Arguments &= " /noconsolelogger"
                            .WindowStyle = ProcessWindowStyle.Hidden
                        End If
                    End With

                    'give the .contentproj file to MSBuild

                    objProcess = System.Diagnostics.Process.Start(objPSI)

                    While Not objProcess.HasExited
                        Threading.Thread.Sleep(100)
                    End While

                Catch ex As Exception

                    MsgBox("When building the pipeline, trying to run MSBuild.exe resulted in: " & ex.Message)

                End Try

            Catch ex As Exception

                MsgBox("When building the pipeline, trying to create the Content.contentproj file """ & Me.strProjectFolder & "\Content.contentproj"" resulted in: " & ex.Message)

            End Try

        End If

    End Sub

    Private Sub HarvestContent()

        Dim objRoot As System.IO.DirectoryInfo = New System.IO.DirectoryInfo(Me.strContentFolder)

        For Each sound As System.IO.FileInfo In objRoot.GetFiles("*.xab", IO.SearchOption.AllDirectories)
            If Me.objContent.Contains(New ContentFile(ContentTypes.Sounds, sound, sound.Name.Replace(sound.Extension, ""))) Then
                Me.intDupeSound += 1
                Me.objContent.Add(New ContentFile(ContentTypes.Sounds, sound, sound.Name.Replace(sound.Extension, "") & Me.intDupeSound.ToString))
            Else
                Me.objContent.Add(New ContentFile(ContentTypes.Sounds, sound, sound.Name.Replace(sound.Extension, "")))
            End If
        Next

        For Each texture As System.IO.FileInfo In objRoot.GetFiles("*.png", IO.SearchOption.AllDirectories)
            If Me.objContent.Contains(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, ""))) Then
                Me.intDupeTexture += 1
                Me.objContent.Add(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, "") & Me.intDupeTexture.ToString))
            Else
                Me.objContent.Add(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, "")))
            End If
        Next

        For Each texture As System.IO.FileInfo In objRoot.GetFiles("*.jpg", IO.SearchOption.AllDirectories)
            If Me.objContent.Contains(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, ""))) Then
                Me.intDupeTexture += 1
                Me.objContent.Add(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, "") & Me.intDupeTexture.ToString))
            Else
                Me.objContent.Add(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, "")))
            End If
        Next

        For Each texture As System.IO.FileInfo In objRoot.GetFiles("*.gif", IO.SearchOption.AllDirectories)
            If Me.objContent.Contains(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, ""))) Then
                Me.intDupeTexture += 1
                Me.objContent.Add(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, "") & Me.intDupeTexture.ToString))
            Else
                Me.objContent.Add(New ContentFile(ContentTypes.Textures, texture, texture.Name.Replace(texture.Extension, "")))
            End If
        Next

        For Each font As System.IO.FileInfo In objRoot.GetFiles("*.spritefont", IO.SearchOption.AllDirectories)
            If Me.objContent.Contains(New ContentFile(ContentTypes.Fonts, font, font.Name.Replace(font.Extension, ""))) Then
                Me.intDupeFont += 1
                Me.objContent.Add(New ContentFile(ContentTypes.Fonts, font, font.Name.Replace(font.Extension, "") & Me.intDupeFont.ToString))
            Else
                Me.objContent.Add(New ContentFile(ContentTypes.Fonts, font, font.Name.Replace(font.Extension, "")))
            End If
        Next

        For Each effect As System.IO.FileInfo In objRoot.GetFiles("*.fx", IO.SearchOption.AllDirectories)
            If Me.objContent.Contains(New ContentFile(ContentTypes.Effects, effect, effect.Name.Replace(effect.Extension, ""))) Then
                Me.intDupeEffect += 1
                Me.objContent.Add(New ContentFile(ContentTypes.Effects, effect, effect.Name.Replace(effect.Extension, "") & Me.intDupeEffect.ToString))
            Else
                Me.objContent.Add(New ContentFile(ContentTypes.Effects, effect, effect.Name.Replace(effect.Extension, "")))
            End If
        Next
        For Each effect As System.IO.FileInfo In objRoot.GetFiles("*.x", IO.SearchOption.AllDirectories)
            If Me.objContent.Contains(New ContentFile(ContentTypes.Model, effect, effect.Name.Replace(effect.Extension, ""))) Then
                Me.intDupeModel += 1
                Me.objContent.Add(New ContentFile(ContentTypes.Model, effect, effect.Name.Replace(effect.Extension, "") & Me.intDupeModel.ToString))
            Else
                Me.objContent.Add(New ContentFile(ContentTypes.Model, effect, effect.Name.Replace(effect.Extension, "")))
            End If
        Next

    End Sub

    Private Sub BuildContentProj(ByVal platform As Platform)

        Dim strPlatform As String

        Select Case platform
            Case VBContentManager.Platform.XBox360
                strPlatform = "Xbox 360"
            Case Else
                strPlatform = "Windows"
        End Select

        Me.strContentprojFile = _
        "<Project xmlns=""http://schemas.microsoft.com/developer/msbuild/2003"">" & vbCrLf & _
        vbTab & "<Import Project=""$(MSBuildExtensionsPath)\Microsoft\XNA Game Studio\v3.1\Microsoft.Xna.GameStudio.ContentPipeline.targets"" />" & vbCrLf & _
        vbTab & "<PropertyGroup>" & vbCrLf & _
        vbTab & vbTab & "<OutputType>Library</OutputType>" & vbCrLf & _
        vbTab & vbTab & "<XnaFrameworkVersion>v3.1</XnaFrameworkVersion>" & vbCrLf & _
        vbTab & vbTab & "<ProjectDir>" & Me.strProjectFolder & "\</ProjectDir>" & vbCrLf & _
        vbTab & vbTab & "<ParentOutputDir>" & Me.strExecutingFolder & "</ParentOutputDir>" & vbCrLf & _
        vbTab & vbTab & "<ContentRootDirectory>\</ContentRootDirectory>" & vbCrLf & _
        vbTab & vbTab & "<XNAContentPipelineTargetPlatform>" & strPlatform & "</XNAContentPipelineTargetPlatform>" & vbCrLf & _
        vbTab & vbTab & "<OutputPath>" & Me.strExecutingFolder & "\</OutputPath>" & vbCrLf & _
        vbTab & vbTab & "<OutputDirectory>" & Me.strExecutingFolder & "\</OutputDirectory>" & vbCrLf & _
        vbTab & "</PropertyGroup>" & vbCrLf & _
        vbTab & "<ItemGroup>" & vbCrLf & _
        vbTab & vbTab & "<Reference Include=""Microsoft.Xna.Framework.Content.Pipeline.EffectImporter, Version=3.1.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d, processorArchitecture=MSIL"" />" & vbCrLf & _
        vbTab & vbTab & "<Reference Include=""Microsoft.Xna.Framework.Content.Pipeline.FBXImporter, Version=3.1.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d, processorArchitecture=MSIL"" />" & vbCrLf & _
        vbTab & vbTab & "<Reference Include=""Microsoft.Xna.Framework.Content.Pipeline.TextureImporter, Version=3.1.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d, processorArchitecture=MSIL"" />" & vbCrLf & _
        vbTab & vbTab & "<Reference Include=""Microsoft.Xna.Framework.Content.Pipeline.XImporter, Version=3.1.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d, processorArchitecture=MSIL"" />" & vbCrLf & _
        vbTab & "</ItemGroup>"

        For Each content As ContentFile In Me.objContent

            Me.strContentprojFile &= vbCrLf & _
            vbTab & "<ItemGroup>" & vbCrLf & _
            vbTab & vbTab & "<Compile Include=""" & content.File.FullName & """>" & vbCrLf & _
            vbTab & vbTab & vbTab & "<Name>" & content.Name & "</Name>" & vbCrLf & _
            vbTab & vbTab & vbTab & "<Importer>" & CType(content.ContentType, ImporterName).ToString & "</Importer>" & vbCrLf & _
            vbTab & vbTab & vbTab & "<Processor>" & CType(content.ContentType, ProcessorName).ToString & "</Processor>" & vbCrLf & _
            vbTab & vbTab & "</Compile>" & vbCrLf & _
            vbTab & "</ItemGroup>"

            If content.ContentType = ContentTypes.Textures Then

                'If this texture is a sheet w/ a map, copy it's map out in the executable area
                'along side the existing or eventual compiled texture

                If IO.File.Exists(content.File.FullName.Replace(content.File.Extension, ".map")) Then

                    Try
                        IO.File.Copy(content.File.FullName.Replace(content.File.Extension, ".map"), _
                        Me.strExecutingFolder & content.File.FullName.Replace(Me.strProjectFolder, "").Replace(content.File.Extension, ".map"), True)
                    Catch ex As Exception
                        'I'm going to be optimistic and assume that if I can't copy
                        'it's because the file is already there, and life is just fine
                    End Try

                End If

            End If

        Next

        Me.strContentprojFile &= vbCrLf & vbTab & "<!-- To modify your build process, add your task inside one of the targets below and uncomment it. " & vbCrLf & _
        vbTab & "     Other similar extension points exist, see Microsoft.Common.targets." & vbCrLf & _
        vbTab & "<Target Name=""BeforeBuild"">" & vbCrLf & _
        vbTab & "</Target>" & vbCrLf & _
        vbTab & "<Target Name=""AfterBuild"">" & vbCrLf & _
        vbTab & "</Target>" & vbCrLf & _
        vbTab & "-->" & vbCrLf & _
        "</Project>"

    End Sub

End Class
Public Class Hashtable(Of Type)
    Inherits DictionaryBase

    Public ReadOnly Property Keys() As ICollection
        Get
            Return MyBase.Dictionary.Keys
        End Get
    End Property

    Default Public Property Item(ByVal key As String) As Type
        Get
            Return CType(MyBase.Dictionary(key), Type)
        End Get
        Set(ByVal value As Type)
            MyBase.Dictionary(key) = value
        End Set
    End Property

    Public Overloads Sub Add(ByVal key As String, ByVal obj As Type)
        MyBase.Dictionary.Add(key, obj)
    End Sub

    Public ReadOnly Property Values() As ICollection
        Get
            Return Dictionary.Values
        End Get
    End Property

    Public Function Contains(ByVal key As String) As Boolean
        Return Dictionary.Contains(key)
    End Function

    Public Sub Remove(ByVal key As String)
        Dictionary.Remove(key)
    End Sub

End Class


UTILIZZO:
semplicissimo, nella vostra classe principale (di solito Game.vb) aggiungete la seguente riga tra i riferimenti globali,
cioè subito dopo Public Class Game
Protected objCM As VBContentManager

sotto New aggiungete questo per inizializzare il percorso:
Sub New()
Me.objCM = New VBContentManager(Me.Services, "Content")

per usarla basta aggiungere la seguente riga nel LoadContent
Protected Overrides Sub LoadContent()
objCM.CompileContent(True, VBContentManager.Platform.Windows)

finito :)
ovviamente potete scegliere tra windows o xbox.
Se non aggiungete nuove risorse basta commetare la riga. E comunque se le risorse sono state modificate, i file xnb verranno ricreati altrimenti verranno creati una sola volta 8-)

COME FUNZIONA:
Create una cartella Content dentro il percorso del vostro progetto (per capirci nella stessa cartella dove c'è il file NomeGioco.vbproj)
tutto cio' che mettete il dentro (comprese sottocartelle) verrà automaticamente processato, convertito in .xnb e messo nell'apposito percorso bin :D
Bhe dopo tutte le ricerche e richieste che ho letto in internet spero sia utile a molti.
se qualcuno vuole anche tradurre/sistemare quanto ho scritto tanto meglio
Ciauz

Predator
Ultima modifica di Predator il 21/12/2009, 1:19, modificato 2 volte in totale.
Avatar utente

Predator
Matricola
Matricola
 
Messaggi: 23
Iscritto il: 09/12/2009, 14:06

Re: [CODE] XNA 3.1 Content Manger in VB .NET

Messaggiodi Ocsecnarf » 11/12/2009, 18:05

Cavolo, ma sei bravissimo, quanti linguaggi sai?
Avatar utente

Ocsecnarf
Sta ingranando :)
Sta ingranando :)
 
Messaggi: 220
Iscritto il: 29/09/2009, 13:25
Località: Mondo Che Non Esiste

Re: [CODE] XNA 3.1 Content Manger in VB .NET

Messaggiodi Predator » 11/12/2009, 18:41

grazie:)
Essenzialmente vado bene su Asm, Vb.Net, C#, VB6, Asp.
Avatar utente

Predator
Matricola
Matricola
 
Messaggi: 23
Iscritto il: 09/12/2009, 14:06

Re: [CODE] XNA 3.1 Content Manger in VB .NET

Messaggiodi Serenissima » 12/12/2009, 12:36

Tanto di cappello. :)

Complimenti.

Serenissima
Matricola
Matricola
 
Messaggi: 56
Iscritto il: 21/11/2009, 12:56
Località: Alessandria

Re: [CODE] XNA 3.1 Content Manger in VB .NET

Messaggiodi Pino » 14/12/2009, 4:45

ATTENZIONE!!!

Il codice proposto funziona SOLO su PC, non può essere portato su Xbox 360 poiché è in VB, quindi pensateci bene prima di far tentativi: il linguaggio da usare per portabilità tra le piattaforme è solo C#.
Hai trovato un articolo su XNA in Inglese che vorresti fosse discusso ed approfondito qui? Mandami un MP (Messaggio Privato) segnalandomi l'articolo e farò il possibile per accontentarti :)
Avatar utente

Pino
Amministratore
Amministratore
 
Messaggi: 147
Iscritto il: 16/09/2009, 23:18
Località: Irlanda

Re: [CODE] XNA 3.1 Content Manger in VB .NET

Messaggiodi Predator » 20/12/2009, 22:47

Pino hai fatto benissimo a specificarlo! :applauso:
Avatar utente

Predator
Matricola
Matricola
 
Messaggi: 23
Iscritto il: 09/12/2009, 14:06

Re: [CODE] XNA 3.1 Content Manger in VB .NET

Messaggiodi Predator » 21/12/2009, 1:17

Ho aggioranto il codice, ora importa e processa anche le mesh, nel formato file .X :mrgreen:
Avatar utente

Predator
Matricola
Matricola
 
Messaggi: 23
Iscritto il: 09/12/2009, 14:06


Torna a Il "Content Pipeline"... questo sconosciuto

Chi c’è in linea

Visitano il forum: Nessuno e 1 ospite