[GS 2.0 Beta]
Moving forward, the tutorials on this website will be referencing XNA 2.0.
Here is an updated version of the VBContentManager class for use with XNA 2.0
- The class itself now inherits from the XNA 2.0 ContentManager
- The LoadPipeline() method has been replaced by the CompileContent & LoadAllContent methods. Call these methods as appropriate where LoadPipeline was used before.
- You can now specify a platform (Windows or Xbox360), although it's not exactly known whether or not you can run VB.NET on an Xbox360. This is there just in case/for the future. The target platform is Windows by default
- You can now specify whether or not the MSBuild window is visible, having the content compile in "stealth mode" (as a C# project does)
- The content folder is no longer supplied relative to the bin\Debug folder. You now supply it relative to the Project node in which the folder resides. For example, if you made a folder called "My Content" in your game's project in the Solution Explorer, you would simply supply "My Content" as the path to your content (rather than "../../My Content" like before)
- The 'fake' project file built for MSBuild is now a .contentproj file, rather than an actual .csproj file. Not that the extension matters much, this was simply for the sake of emulating the file created in XNA 2.0 (where, in C#, content is now a sub-project of the game and has it's own project file - the VBContentManager simply simulates this file). As an aside, the project file being generated is more well formed than before, so MSBuild should no longer throw warning messages as it compiles.
- In the previous version of the VBContentManager, choosing not to compile the content would result in a runtime error. You no longer have to compile the content; if you know it's already compiled (like say for instance, right before you are going to distribute the application to someone's PC) you can omit the call to CompileContent in your code and load the already-compiled content (skips the call to MSBuild completely).
Here is the code for the class:
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 As Integer
Public Enum Platform
Windows
XBox360
End Enum
Public Enum ContentTypes
Textures = 0
Fonts = 1
Sounds = 2
Effects = 3
End Enum
Private Enum ImporterName
TextureImporter = 0
FontDescriptionImporter = 1
XactImporter = 2
EffectImporter = 3
End Enum
Private Enum ProcessorName
TextureProcessor = 0
FontDescriptionProcessor = 1
XactProcessor = 2
EffectProcessor = 3
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
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
''' <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\v2.0.50727\MSBuild.exe"
.Arguments = """" & Me.strProjectFolder & "\Content.contentproj""" & _
" /verbosity:normal" & _
" /l:FileLogger,Microsoft.Build.Engine;logfile=""" & Me.strProjectFolder & "\Content.log"""
If stealth Then
.Arguments &= " /noconsolelogger"
End If
If stealth Then
.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.strContentFolder & "\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
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\v2.0\Microsoft.Xna.GameStudio.ContentPipeline.targets"" />" & vbCrLf & _
vbTab & "<PropertyGroup>" & vbCrLf & _
vbTab & vbTab & "<OutputType>Library</OutputType>" & vbCrLf & _
vbTab & vbTab & "<XnaFrameworkVersion>v2.0</XnaFrameworkVersion>" & vbCrLf & _
vbTab & vbTab & "<ProjectDir>" & Me.strProjectFolder & "\</ProjectDir>" & vbCrLf & _
vbTab & vbTab & "<XNAContentPipelineTargetPlatform>" & strPlatform & "</XNAContentPipelineTargetPlatform>" & vbCrLf & _
vbTab & vbTab & "<OutputPath>" & Me.strExecutingFolder & "\</OutputPath>" & vbCrLf & _
vbTab & "</PropertyGroup>" & vbCrLf & _
vbTab & "<ItemGroup>" & vbCrLf & _
vbTab & vbTab & "<Reference Include=""Microsoft.Xna.Framework.Content.Pipeline.EffectImporter, Version=2.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d, processorArchitecture=MSIL"" />" & vbCrLf & _
vbTab & vbTab & "<Reference Include=""Microsoft.Xna.Framework.Content.Pipeline.FBXImporter, Version=2.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d, processorArchitecture=MSIL"" />" & vbCrLf & _
vbTab & vbTab & "<Reference Include=""Microsoft.Xna.Framework.Content.Pipeline.TextureImporter, Version=2.0.0.0, Culture=neutral, PublicKeyToken=6d5c3888ef60e27d, processorArchitecture=MSIL"" />" & vbCrLf & _
vbTab & vbTab & "<Reference Include=""Microsoft.Xna.Framework.Content.Pipeline.XImporter, Version=2.0.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>"
Next
Me.strContentprojFile &= vbCrLf & "</Project>"
End Sub
End Class
To see how a Game can utilize the VBContentManager class, see
the previous tutorial on the subject, and then read the change log at the top of this post.
Some slight changes can be made to the MyBaseGame class as well. Now that a ContentManager is built into v2.0 of the XNA Game class, you can overload the Content property to return your VBContentManager.
0 comments:
Post a Comment