/// <summary>Apply any <see cref="Editors"/> to a loaded asset.</summary> /// <typeparam name="T">The asset type.</typeparam> /// <param name="info">The basic asset metadata.</param> /// <param name="asset">The loaded asset.</param> private IAssetData ApplyEditors <T>(IAssetInfo info, IAssetData asset) { IAssetData GetNewData(object data) => new AssetDataForObject(info, data, this.AssertAndNormaliseAssetName); // edit asset foreach (var entry in this.GetInterceptors(this.Editors)) { // check for match IModMetadata mod = entry.Key; IAssetEditor editor = entry.Value; try { if (!editor.CanEdit <T>(info)) { continue; } } catch (Exception ex) { mod.LogAsMod($"Mod crashed when checking whether it could edit asset '{info.AssetName}', and will be ignored. Error details:\n{ex.GetLogSummary()}", LogLevel.Error); continue; } // try edit object prevAsset = asset.Data; try { editor.Edit <T>(asset); this.Monitor.Log($"{mod.DisplayName} edited {info.AssetName}.", LogLevel.Trace); } catch (Exception ex) { mod.LogAsMod($"Mod crashed when editing asset '{info.AssetName}', which may cause errors in-game. Error details:\n{ex.GetLogSummary()}", LogLevel.Error); } // validate edit if (asset.Data == null) { mod.LogAsMod($"Mod incorrectly set asset '{info.AssetName}' to a null value; ignoring override.", LogLevel.Warn); asset = GetNewData(prevAsset); } else if (!(asset.Data is T)) { mod.LogAsMod($"Mod incorrectly set asset '{asset.AssetName}' to incompatible type '{asset.Data.GetType()}', expected '{typeof(T)}'; ignoring override.", LogLevel.Warn); asset = GetNewData(prevAsset); } } // return result return(asset); }
/// <summary>Apply any <see cref="Editors"/> to a loaded asset.</summary> /// <typeparam name="T">The asset type.</typeparam> /// <param name="info">The basic asset metadata.</param> /// <param name="asset">The loaded asset.</param> private IAssetData ApplyEditors <T>(IAssetInfo info, IAssetData asset) { IAssetData GetNewData(object data) => new AssetDataForObject(info, data, this.AssertAndNormalizeAssetName); // special case: if the asset was loaded with a more general type like 'object', call editors with the actual type instead. { Type actualType = asset.Data.GetType(); Type actualOpenType = actualType.IsGenericType ? actualType.GetGenericTypeDefinition() : null; if (typeof(T) != actualType && (actualOpenType == typeof(Dictionary <,>) || actualOpenType == typeof(List <>) || actualType == typeof(Texture2D) || actualType == typeof(Map))) { return((IAssetData)this.GetType() .GetMethod(nameof(this.ApplyEditors), BindingFlags.NonPublic | BindingFlags.Instance) .MakeGenericMethod(actualType) .Invoke(this, new object[] { info, asset })); } } // edit asset foreach (var entry in this.Editors) { // check for match IModMetadata mod = entry.Mod; IAssetEditor editor = entry.Data; try { if (!editor.CanEdit <T>(info)) { continue; } } catch (Exception ex) { mod.LogAsMod($"Mod crashed when checking whether it could edit asset '{info.AssetName}', and will be ignored. Error details:\n{ex.GetLogSummary()}", LogLevel.Error); continue; } // try edit object prevAsset = asset.Data; try { editor.Edit <T>(asset); this.Monitor.Log($"{mod.DisplayName} edited {info.AssetName}.", LogLevel.Trace); } catch (Exception ex) { mod.LogAsMod($"Mod crashed when editing asset '{info.AssetName}', which may cause errors in-game. Error details:\n{ex.GetLogSummary()}", LogLevel.Error); } // validate edit if (asset.Data == null) { mod.LogAsMod($"Mod incorrectly set asset '{info.AssetName}' to a null value; ignoring override.", LogLevel.Warn); asset = GetNewData(prevAsset); } else if (!(asset.Data is T)) { mod.LogAsMod($"Mod incorrectly set asset '{asset.AssetName}' to incompatible type '{asset.Data.GetType()}', expected '{typeof(T)}'; ignoring override.", LogLevel.Warn); asset = GetNewData(prevAsset); } } // return result return(asset); }