Esempio n. 1
0
        protected T ReadAsset <T>(string assetName, Action <IDisposable> recordDisposableObject)
        {
            if (string.IsNullOrEmpty(assetName))
            {
                throw new ArgumentNullException("assetName");
            }
            if (disposed)
            {
                throw new ObjectDisposedException("ContentManager");
            }

            object result = null;

            // FIXME: Should this block be here? -flibit
            if (graphicsDeviceService == null)
            {
                graphicsDeviceService = ServiceProvider.GetService(typeof(IGraphicsDeviceService)) as IGraphicsDeviceService;
                if (graphicsDeviceService == null)
                {
                    throw new InvalidOperationException("No Graphics Device Service");
                }
            }

            Stream stream            = null;
            string modifiedAssetName = String.Empty;             // Will be used if we have to guess a filename

            try
            {
                stream = OpenStream(assetName);
            }
            catch (Exception e)
            {
                // Okay, so we couldn't open it. Maybe it needs a different extension?
                // FIXME: This only works for files on the disk, what about custom streams? -flibit
                modifiedAssetName = FileHelpers.NormalizeFilePathSeparators(
                    Path.Combine(RootDirectoryFullPath, assetName)
                    );
                if (typeof(T) == typeof(Texture2D) || typeof(T) == typeof(Texture))
                {
                    modifiedAssetName = Texture2DReader.Normalize(modifiedAssetName);
                }
                else if ((typeof(T) == typeof(SoundEffect)))
                {
                    modifiedAssetName = SoundEffectReader.Normalize(modifiedAssetName);
                }
                else if ((typeof(T) == typeof(Effect)))
                {
                    modifiedAssetName = EffectReader.Normalize(modifiedAssetName);
                }
                else if ((typeof(T) == typeof(Song)))
                {
                    modifiedAssetName = SongReader.Normalize(modifiedAssetName);
                }
                else if ((typeof(T) == typeof(Video)))
                {
                    modifiedAssetName = VideoReader.Normalize(modifiedAssetName);
                }

                // Did we get anything...?
                if (String.IsNullOrEmpty(modifiedAssetName))
                {
                    // Nope, nothing we're aware of!
                    throw new ContentLoadException(
                              "Could not load asset " + assetName + "! Error: " + e.Message,
                              e
                              );
                }

                stream = TitleContainer.OpenStream(modifiedAssetName);
            }

            // Check for XNB header
            stream.Read(xnbHeader, 0, xnbHeader.Length);
            if (xnbHeader[0] == 'X' &&
                xnbHeader[1] == 'N' &&
                xnbHeader[2] == 'B' &&
                targetPlatformIdentifiers.Contains((char)xnbHeader[3]))
            {
                using (BinaryReader xnbReader = new BinaryReader(stream))
                    using (ContentReader reader = GetContentReaderFromXnb(assetName, ref stream, xnbReader, recordDisposableObject))
                    {
                        result = reader.ReadAsset <T>();
                        GraphicsResource resource = result as GraphicsResource;
                        if (resource != null)
                        {
                            resource.Name = assetName;
                        }
                    }
            }
            else
            {
                // It's not an XNB file. Try to load as a raw asset instead.

                // FIXME: Assuming seekable streams! -flibit
                stream.Seek(0, SeekOrigin.Begin);

                if (typeof(T) == typeof(Texture2D) || typeof(T) == typeof(Texture))
                {
                    Texture2D texture = Texture2D.FromStream(
                        graphicsDeviceService.GraphicsDevice,
                        stream
                        );
                    texture.Name = assetName;
                    result       = texture;
                }
                else if ((typeof(T) == typeof(SoundEffect)))
                {
                    result = SoundEffect.FromStream(stream);
                }
                else if ((typeof(T) == typeof(Effect)))
                {
                    byte[] data = new byte[stream.Length];
                    stream.Read(data, 0, (int)stream.Length);
                    result = new Effect(graphicsDeviceService.GraphicsDevice, data);
                }
                else if ((typeof(T) == typeof(Song)))
                {
                    // FIXME: Not using the stream! -flibit
                    result = new Song(modifiedAssetName);
                }
                else if ((typeof(T) == typeof(Video)))
                {
                    // FIXME: Not using the stream! -flibit
                    result = new Video(modifiedAssetName, graphicsDeviceService.GraphicsDevice);
                }
                else
                {
                    stream.Close();
                    throw new ContentLoadException("Could not load " + assetName + " asset!");
                }

                /* Because Raw Assets skip the ContentReader step, they need to have their
                 * disposables recorded here. Doing it outside of this catch will
                 * result in disposables being logged twice.
                 */
                IDisposable disposableResult = result as IDisposable;
                if (disposableResult != null)
                {
                    if (recordDisposableObject != null)
                    {
                        recordDisposableObject(disposableResult);
                    }
                    else
                    {
                        disposableAssets.Add(disposableResult);
                    }
                }

                /* Because we're not using a BinaryReader for raw assets, we
                 * need to close the stream ourselves.
                 * -flibit
                 */
                stream.Close();
            }

            return((T)result);
        }
        internal ContentTypeReader[] LoadAssetReaders(ContentReader reader)
        {
#pragma warning disable 0219, 0649
            // Trick to prevent the linker removing the code, but not actually execute the code
            if (falseflag)
            {
                // Dummy variables required for it to work on iDevices ** DO NOT DELETE **
                // This forces the classes not to be optimized out when deploying to iDevices
                var hByteReader              = new ByteReader();
                var hSByteReader             = new SByteReader();
                var hDateTimeReader          = new DateTimeReader();
                var hDecimalReader           = new DecimalReader();
                var hBoundingSphereReader    = new BoundingSphereReader();
                var hBoundingFrustumReader   = new BoundingFrustumReader();
                var hRayReader               = new RayReader();
                var hCharListReader          = new ListReader <Char>();
                var hRectangleListReader     = new ListReader <Rectangle>();
                var hRectangleArrayReader    = new ArrayReader <Rectangle>();
                var hVector3ListReader       = new ListReader <Vector3>();
                var hStringListReader        = new ListReader <StringReader>();
                var hIntListReader           = new ListReader <Int32>();
                var hSpriteFontReader        = new SpriteFontReader();
                var hTexture2DReader         = new Texture2DReader();
                var hCharReader              = new CharReader();
                var hRectangleReader         = new RectangleReader();
                var hStringReader            = new StringReader();
                var hVector2Reader           = new Vector2Reader();
                var hVector3Reader           = new Vector3Reader();
                var hVector4Reader           = new Vector4Reader();
                var hCurveReader             = new CurveReader();
                var hIndexBufferReader       = new IndexBufferReader();
                var hBoundingBoxReader       = new BoundingBoxReader();
                var hMatrixReader            = new MatrixReader();
                var hBasicEffectReader       = new BasicEffectReader();
                var hVertexBufferReader      = new VertexBufferReader();
                var hAlphaTestEffectReader   = new AlphaTestEffectReader();
                var hEnumSpriteEffectsReader = new EnumReader <Graphics.SpriteEffects>();
                var hArrayFloatReader        = new ArrayReader <float>();
                var hArrayVector2Reader      = new ArrayReader <Vector2>();
                var hListVector2Reader       = new ListReader <Vector2>();
                var hArrayMatrixReader       = new ArrayReader <Matrix>();
                var hEnumBlendReader         = new EnumReader <Graphics.Blend>();
                var hNullableRectReader      = new NullableReader <Rectangle>();
                var hEffectMaterialReader    = new EffectMaterialReader();
                var hExternalReferenceReader = new ExternalReferenceReader();
                var hSoundEffectReader       = new SoundEffectReader();
                var hSongReader              = new SongReader();
                var hModelReader             = new ModelReader();
                var hInt32Reader             = new Int32Reader();
                var hEffectReader            = new EffectReader();
                var hSingleReader            = new SingleReader();

                // At the moment the Video class doesn't exist
                // on all platforms... Allow it to compile anyway.
#if ANDROID || (IOS && !TVOS) || MONOMAC || (WINDOWS && !OPENGL) || WINDOWS_UAP
                var hVideoReader = new VideoReader();
#endif
            }
#pragma warning restore 0219, 0649

            // The first content byte i read tells me the number of content readers in this XNB file
            var numberOfReaders = reader.Read7BitEncodedInt();
            var contentReaders  = new ContentTypeReader[numberOfReaders];
            var needsInitialize = new BitArray(numberOfReaders);
            _contentReaders = new Dictionary <Type, ContentTypeReader>(numberOfReaders);

            // Lock until we're done allocating and initializing any new
            // content type readers...  this ensures we can load content
            // from multiple threads and still cache the readers.
            lock (_locker)
            {
                // For each reader in the file, we read out the length of the string which contains the type of the reader,
                // then we read out the string. Finally we instantiate an instance of that reader using reflection
                for (var i = 0; i < numberOfReaders; i++)
                {
                    // This string tells us what reader we need to decode the following data
                    // string readerTypeString = reader.ReadString();
                    string originalReaderTypeString = reader.ReadString();

                    Func <ContentTypeReader> readerFunc;
                    if (typeCreators.TryGetValue(originalReaderTypeString, out readerFunc))
                    {
                        contentReaders[i]  = readerFunc();
                        needsInitialize[i] = true;
                    }
                    else
                    {
                        //System.Diagnostics.Debug.WriteLine(originalReaderTypeString);

                        // Need to resolve namespace differences
                        string readerTypeString = originalReaderTypeString;

                        readerTypeString = PrepareType(readerTypeString);

                        var l_readerType = Type.GetType(readerTypeString);
                        if (l_readerType != null)
                        {
                            ContentTypeReader typeReader;
                            if (!_contentReadersCache.TryGetValue(l_readerType, out typeReader))
                            {
                                try
                                {
                                    typeReader = l_readerType.GetDefaultConstructor().Invoke(null) as ContentTypeReader;
                                }
                                catch (TargetInvocationException ex)
                                {
                                    // If you are getting here, the Mono runtime is most likely not able to JIT the type.
                                    // In particular, MonoTouch needs help instantiating types that are only defined in strings in Xnb files.
                                    throw new InvalidOperationException(
                                              "Failed to get default constructor for ContentTypeReader. To work around, add a creation function to ContentTypeReaderManager.AddTypeCreator() " +
                                              "with the following failed type string: " + originalReaderTypeString, ex);
                                }

                                needsInitialize[i] = true;

                                _contentReadersCache.Add(l_readerType, typeReader);
                            }

                            contentReaders[i] = typeReader;
                        }
                        else
                        {
                            throw new ContentLoadException(
                                      "Could not find ContentTypeReader Type. Please ensure the name of the Assembly that contains the Type matches the assembly in the full type name: " +
                                      originalReaderTypeString + " (" + readerTypeString + ")");
                        }
                    }

                    var targetType = contentReaders[i].TargetType;
                    if (targetType != null)
                    {
                        if (!_contentReaders.ContainsKey(targetType))
                        {
                            _contentReaders.Add(targetType, contentReaders[i]);
                        }
                    }

                    // I think the next 4 bytes refer to the "Version" of the type reader,
                    // although it always seems to be zero
                    reader.ReadInt32();
                }

                // Initialize any new readers.
                for (var i = 0; i < contentReaders.Length; i++)
                {
                    if (needsInitialize.Get(i))
                    {
                        contentReaders[i].Initialize(this);
                    }
                }
            } // lock (_locker)

            return(contentReaders);
        }