public override async Task <AssetViewModel> PickupObject(AssetViewModel objectToFix, object referencedMember) { var assetPicker = ServiceProvider.Get <IEditorDialogService>().CreateAssetPickerDialog(objectToFix.Session); assetPicker.Message = "Select an asset to replace the deleted asset"; assetPicker.Filter = x => !IsInObjectsToFixList(x); assetPicker.InitialLocation = objectToFix.Directory; assetPicker.AllowMultiSelection = false; Type assetType = objectToFix.AssetType; var contentType = AssetRegistry.GetContentType(objectToFix.AssetType); if (contentType != null) { var assetTypes = AssetRegistry.GetAssetTypes(contentType); assetPicker.AcceptedTypes.AddRange(assetTypes); } else { assetPicker.AcceptedTypes.Add(assetType); } var result = await assetPicker.ShowModal(); return(result == DialogResult.Ok ? assetPicker.SelectedAssets.First() : null); }
public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { var url = (string)value; var asset = SessionViewModel.Instance.AllAssets.FirstOrDefault(x => x.Url == url); if (asset == null) { return(null); } var contentType = AssetRegistry.GetContentType(asset.AssetType); return(AttachedReferenceManager.CreateProxyObject(contentType, asset.Id, asset.Url)); }
/// <summary> /// Creates a reference to the given asset that matches the given reference type. /// </summary> /// <param name="asset">The target asset of the reference to create.</param> /// <param name="referenceType">The type of reference to create.</param> /// <returns>A reference to the given asset if it's not null and <paramref name="referenceType"/> is a valid reference type, null otherwise.</returns> /// <remarks>A reference type is either an <see cref="AssetReference"/> or a content type registered in the <see cref="AssetRegistry"/>.</remarks> public static object CreateReference(AssetViewModel asset, Type referenceType) { if (asset != null) { if (AssetRegistry.IsContentType(referenceType)) { var assetType = asset.AssetItem.Asset.GetType(); var contentType = AssetRegistry.GetContentType(assetType); return(referenceType.IsAssignableFrom(contentType) ? AttachedReferenceManager.CreateProxyObject(contentType, asset.Id, asset.Url) : null); } if (typeof(AssetReference).IsAssignableFrom(referenceType)) { return(new AssetReference(asset.AssetItem.Id, asset.AssetItem.Location)); } } return(null); }
private Task CheckAssetsToReload() { return(GameDispatcher.InvokeTask(async() => { List <ReloadingAsset> assets; // Get assets to reload from queue lock (assetsToReloadLock) { // Nothing left, early exit if (assetsToReloadQueue.Count == 0) { return; } // Copy locally and clear queue assets = assetsToReloadQueue.ToList(); assetsToReloadQueue.Clear(); assetsToReloadMapping.Clear(); } // Update the colorspace Game.UpdateColorSpace(currentColorSpace); var objToFastReload = new Dictionary <string, object>(); using (await database.MountInCurrentMicroThread()) { // First, unload assets foreach (var assetToUnload in assets) { if (FastReloadTypes.Contains(assetToUnload.AssetItem.Asset.GetType()) && IsCurrentlyLoaded(assetToUnload.AssetItem.Asset.Id)) { // If this type supports fast reload, retrieve the current (old) value via a load var type = AssetRegistry.GetContentType(assetToUnload.AssetItem.Asset.GetType()); string url = GetLoadingTimeUrl(assetToUnload.AssetItem); var oldValue = Game.Content.Get(type, url); if (oldValue != null) { logger?.Debug($"Preparing fast-reload of {assetToUnload.AssetItem.Location}"); objToFastReload.Add(url, oldValue); } } else if (IsCurrentlyLoaded(assetToUnload.AssetItem.Asset.Id, true)) { // Unload this object if it has already been loaded. logger?.Debug($"Unloading {assetToUnload.AssetItem.Location}"); await UnloadAsset(assetToUnload.AssetItem.Asset.Id); } } // Process fast-reload objects var nonFastReloadAssets = new List <ReloadingAsset>(); foreach (var assetToLoad in assets) { object oldValue; string url = GetLoadingTimeUrl(assetToLoad.AssetItem); if (FastReloadTypes.Contains(assetToLoad.AssetItem.Asset.GetType()) && objToFastReload.TryGetValue(url, out oldValue)) { // Fill oldValue with the values from the database without reloading the object. // As a result, no reference needs to be updated. logger?.Debug($"Fast-reloading {assetToLoad.AssetItem.Location}"); ReloadContent(oldValue, assetToLoad.AssetItem); var loadedObject = oldValue; // This fast-reloaded content might have been already loaded through private reference, but if we're reloading it here, // it means that we expect a public reference (eg. it has just been referenced publicly). Reload() won't increase public reference count // so we have to do it manually. if (!IsCurrentlyLoaded(assetToLoad.AssetItem.Id, true)) { var type = AssetRegistry.GetContentType(assetToLoad.AssetItem.Asset.GetType()); LoadContent(type, url); } await Manager.ReplaceContent(assetToLoad.AssetItem.Asset.Id, loadedObject); assetToLoad.Result.SetResult(loadedObject); } else { nonFastReloadAssets.Add(assetToLoad); } } // Load all async object in a separate task // We avoid Game.Content.LoadAsync, which would wait next frame between every loaded asset var microThread = Scheduler.CurrentMicroThread; var bufferBlock = new BufferBlock <KeyValuePair <ReloadingAsset, object> >(); var task = Task.Run(() => { var initialContext = SynchronizationContext.Current; // This synchronization context gives access to any MicroThreadLocal values. The database to use might actually be micro thread local. SynchronizationContext.SetSynchronizationContext(new MicrothreadProxySynchronizationContext(microThread)); foreach (var assetToLoad in nonFastReloadAssets) { var type = AssetRegistry.GetContentType(assetToLoad.AssetItem.Asset.GetType()); string url = GetLoadingTimeUrl(assetToLoad.AssetItem); object loadedObject = null; try { loadedObject = LoadContent(type, url); } catch (Exception e) { logger?.Error($"Unable to load asset [{assetToLoad.AssetItem.Location}].", e); } // Post it in BufferBlock so that the game-side loop can process results incrementally bufferBlock.Post(new KeyValuePair <ReloadingAsset, object>(assetToLoad, loadedObject)); } bufferBlock.Complete(); SynchronizationContext.SetSynchronizationContext(initialContext); }); while (await bufferBlock.OutputAvailableAsync()) { var item = await bufferBlock.ReceiveAsync(); var assetToLoad = item.Key; var loadedObject = item.Value; if (loadedObject != null) { // If it's the first load of this asset, keep its loading url if (!AssetLoadingTimeUrls.ContainsKey(assetToLoad.AssetItem.Asset.Id)) { AssetLoadingTimeUrls.Add(assetToLoad.AssetItem.Asset.Id, assetToLoad.AssetItem.Location); } // Add assets that were not previously loaded to the assetLoadingTimeUrls map. var dependencyManager = Asset.AssetItem.Package.Session.DependencyManager; var dependencies = dependencyManager.ComputeDependencies(Asset.AssetItem.Id, AssetDependencySearchOptions.Out | AssetDependencySearchOptions.Recursive, ContentLinkType.Reference); if (dependencies != null) { foreach (var dependency in dependencies.LinksOut) { if (!AssetLoadingTimeUrls.ContainsKey(dependency.Item.Id)) { AssetLoadingTimeUrls.Add(dependency.Item.Id, dependency.Item.Location); } } } // Remove assets that were previously loaded but are not anymore from the assetLoadingTimeUrls map. foreach (var loadedUrls in AssetLoadingTimeUrls.Where(x => !Game.Content.IsLoaded(x.Value)).ToList()) { AssetLoadingTimeUrls.Remove(loadedUrls.Key); } } await Manager.ReplaceContent(assetToLoad.AssetItem.Asset.Id, loadedObject); assetToLoad.Result.SetResult(loadedObject); } // Make sure everything is complete before we return await task; } })); }