Midnight Conjurer

Greetings & Salutations:

I am trying to put together my own kind of "Content Manager" as the current one appears to only work with content that has been added to the project, and not with say, a file on a network drive somewhere.

I really like how the "XNA ContentManager" uses generics, and was trying to implement it myself, but encountered some errors. I looked on the net but couldn't find the answer I was looking for.

Basically, I would like to be able to fetch any kind of asset from my own content manager,
regardless of what it is .

The following function does not work as it is written.
Could someone point out the proper way something like this is supposed to be implemented

(PS. The content is stored in dictionaries (ie dict_textures, dict_cubemaps, dict_effects etc..) )

public virtual T Get<T>(string filePath)
{
T asset;

Type type = typeof(T);

switch (type.FullName)
{
case "Microsoft.Xna.Framework.Graphics.Texture2D":
{
asset = Find_Texture2D(filePath) as T; //Returns a Texture2D
} break;

case "Microsoft.Xna.Framework.Graphics.TextureCube": etc........
}

return default(asset);
}

It would be great If someone could help me out. Thanks.

-Midnight Conjurer


Re: XNA Framework Custom Content Manager - Generics Question

Fluxtah

Hi, I really cannot think of a nice way of doing that right now, but at least this compiles, I do not know if it works though it could throw a runtime error :)

        public A Find<A>(string assetName) where A : class
        {
            if(typeof(A) == typeof(Texture2D))
                return FindTexture2D(assetName) as A;

            return null;
        }

        private Texture2D FindTexture2D(string assetName)
        {
            return null;
        }

 





Re: XNA Framework Custom Content Manager - Generics Question

Leaf.

If you're not using switch you can use the is keyword.

if (asset is Texture2D)
{
    //....
}

You could also use a dictionary that is keyed by type to store your type "finders" and then look up a finder object. This helps because you don't have to change your source code every time you add a new asset type.

// new types
interface IAssetFinder {...};
interface IAssetFinder<T> : IAssetFinder {...};

// in setup
Dictionary<Type, IAssetFinder> _assetFinders;

_assetFinders[typeof(Texture2D)] = new Texture2DFinder();
// add other asset types...

// in Get<T>()
IAssetFinder<T> finder = _assetFinders[typeof(T)] as IAssetFinder<T>;
asset = finder.Find(filePath);


Also, assuming you don't mind using pre-built assets (.xnb), it's quite easy to derive a new content manager that loads files from other locations such as network shares, from web servers, inside zip files, etc. Just derive from ContentManager and override ContentManager.OpenStream().

Cheers,
Leaf.

 Edit: Removed switch suggestion as it was stupid.






Re: XNA Framework Custom Content Manager - Generics Question

Fluxtah

I dont think you can switch on a type.





Re: XNA Framework Custom Content Manager - Generics Question

Leaf.

Fluxtah, you're correct of course. I'll remove that bit from the post. You can still use the type as a key which is the way I would probably use anway.

Cheers,
Leaf.






Re: XNA Framework Custom Content Manager - Generics Question

Fluxtah

Yes, I would probably also use the Type as a key, its a good idea.





Re: XNA Framework Custom Content Manager - Generics Question

Midnight Conjurer

Hi there,

Thanks for responding to my question. All the answers I got were very good.

You mentioned :

"Also, assuming you don't mind using pre-built assets (.xnb),
it's quite easy to derive a new content manager that loads files
from other locations such as network shares, from web servers,
inside zip files, etc. Just derive from ContentManager
and override ContentManager.OpenStream()."

I dont suppose you could give me a quick example of how that would look
Been trying for a couple days, but no success. Would be great if I had an example to learn from.

Also, I have been looking into converting files to XNB at runtime. Basically, I am working on
a game dev tool and its easier on the artists etc if all they have to do is open up a jpg etc,
do something with it, then save it (again as jpg, or export it as something else).
I want to have all the xnb stuff done internally so that its transparent to the user.
The reason I want to use the content manager is becauase there are also model files
and it is so much easier than writing my own import/export functions.
Just have to figure out how to write up an xml file with the necessary info, then build it, it seems.

Keep up the good work,

-Midnight Conjurer





Re: XNA Framework Custom Content Manager - Generics Question

Leaf.

Overriding OpenStream() is very easy, you just need to use the string asset name to figure out what stream object to return. Here's a simple example that enables a "mod" directory option for your game. The new content manager will check the mod directory first so that default assets can be overriden by a mod.

public class ModContentManager : ContentManager
{
private string _modDirectory;

public ModContentManager(
IServiceProvider serviceProvider,
string rootDirectory, string modDirectory)
: base(serviceProvider, rootDirectory)
{
_modDirectory = modDirectory;
}

protected override Stream OpenStream(string assetName)
{
string assetPath = Path.Combine(_modDirectory, assetName + ".xnb");

if (File.Exists(assetPath))
{
return new FileStream(assetPath, FileMode.Open, FileAccess.Read, FileShare.Read);
}
else
{
return base.OpenStream(assetName);
}
}
}

This is untested code, its just to give you an idea. The stream you return could be for any file location, it could be a file inside a zip, a network stream from a web server, etc.

Regarding building content outside of the IDE, search these forums for "MSBuild" and you should find some threads on that topic. I posted a couple of notes on my site too.

Cheers,
Leaf.






Re: XNA Framework Custom Content Manager - Generics Question

Michael Hansen

what you need is this

http://www.3devolution.net/DevBlog/tabid/90/EntryID/5/Default.aspx

this setup a basic xna content manager and serviceprovider whith out the game.dll so you can control all bye you self

you can add more functions to the xna contentmanager






Re: XNA Framework Custom Content Manager - Generics Question

Midnight Conjurer

Excellent information. Thank you very much.

Had one final question about converting content to XNB at runtime.

I have been checking out MSBuild, but I also came across something in XNA:

Microsoft.Xna.Framework.Content.Pipeline.Tasks.BuildContent

Is there any way BuildContent can be used directly to convert the files

It looked like it might be easier than messing around with MSBuild, but I could be wrong.

If using it is a good idea, a small code sample will do wonders to help get me underway.

Thanks again,

- Midnight Conjurer






Re: XNA Framework Custom Content Manager - Generics Question

Shawn Hargreaves - MSFT

BuildContent is an MSBuild task, so the easiest way to run it is using MSBuild.

I guess it's possible you could host it yourself by emulating the various bits of MSBuild functionality it uses, but that would be tricky and I think much more work than just spinning up an MSBuild Engine object to do that for you!





Re: XNA Framework Custom Content Manager - Generics Question

Midnight Conjurer

Hi Shawn,

Thanks for the reply. Thats pretty much what I thought.
I managed to be able to properly write up the necessary xml data,
and get msbuild to generate xnb's for me at runtime now.

Heres what I ended up with in my designated "Temp" folder:
Bin \Windows\MyContent.xnb
Obj \Windows\ContentPipeline.xml

Do you happen to know:
1.How to have "MyContent.xnb" output to a specified folder instead of bin\windows
2.Why a 121 kb JPG got turned into a 3073 kb XNB Seems overweight.......
(The generated XNB loads just fine via the content manager by the way.)

If you or someone could answer this for me it would help alot.

Thanks,

- Midnight Conjurer




Re: XNA Framework Custom Content Manager - Generics Question

Leaf.

MSBuild project files are very flexible beasts so its difficult to be sure how your particular file is figuring out where to output the files. The simplest way that might work is to change the <OutputPath> property. For a little more information read on.

The BuildContent task has two parameters that control the output:

IntermediateDirectory="$(ProjectDir)$(IntermediateOutputPath)"
OutputDirectory="$(TargetDir)"

The default values above are set by the Microsoft.Xna.ContentPipeline.targets that a standard Xna project will import. The properties referenced in those values (ProjectDir, TargetDir, etc.) are set by the Microsoft.Common.targets file. And they are based on properties that you can set in your project file, like <OutputPath> and <IntermediateOutputPath>.

So from that you can see that changing <OutputPath> will change the OutputDirectory parameter on the BuildContent task. Alternatively if your project file is calling the BuildContent task directly then you can just change/add the OutputDirectory parameter.

Cheers,
Leaf.






Re: XNA Framework Custom Content Manager - Generics Question

ProfEclipse

Michael Hansen wrote:

what you need is this

http://www.3devolution.net/DevBlog/tabid/90/EntryID/5/Default.aspx

this setup a basic xna content manager and serviceprovider whith out the game.dll so you can control all bye you self

you can add more functions to the xna contentmanager

No. Actually, that's nothing like what he is trying to do.