add intro UI for first time registration, add FileCacheManager to scan and rescan for file changes, fix namings, polish UI for normal usage

This commit is contained in:
Stanley Dimant
2022-06-21 01:07:57 +02:00
parent b7b2005dcb
commit 4a12d667f1
11 changed files with 1074 additions and 534 deletions

View File

@@ -45,7 +45,7 @@ namespace MareSynchronos.Managers
private string _lastSentHash = string.Empty;
private Task? _playerChangedTask = null;
private HashSet<string> onlineWhitelistedUsers = new();
private HashSet<string> _onlineWhitelistedUsers = new();
public CharacterManager(ClientState clientState, Framework framework, ApiController apiController, ObjectTable objectTable, IpcManager ipcManager, FileReplacementFactory factory,
Configuration pluginConfiguration)
@@ -154,6 +154,11 @@ namespace MareSynchronos.Managers
_watcher.Disable();
_watcher.PlayerChanged -= Watcher_PlayerChanged;
_watcher?.Dispose();
foreach (var character in _onlineWhitelistedUsers)
{
RestoreCharacter(character);
}
}
public void StopWatchPlayer(string name)
@@ -164,7 +169,7 @@ namespace MareSynchronos.Managers
public async Task UpdatePlayersFromService(Dictionary<string, PlayerCharacter> currentLocalPlayers)
{
PluginLog.Debug("Updating local players from service");
currentLocalPlayers = currentLocalPlayers.Where(k => onlineWhitelistedUsers.Contains(k.Key))
currentLocalPlayers = currentLocalPlayers.Where(k => _onlineWhitelistedUsers.Contains(k.Key))
.ToDictionary(k => k.Key, k => k.Value);
await _apiController.GetCharacterData(currentLocalPlayers
.ToDictionary(
@@ -205,10 +210,10 @@ namespace MareSynchronos.Managers
Task.WaitAll(apiTask);
onlineWhitelistedUsers = new HashSet<string>(apiTask.Result);
_onlineWhitelistedUsers = new HashSet<string>(apiTask.Result);
var assignTask = AssignLocalPlayersData();
Task.WaitAll(assignTask);
PluginLog.Debug("Online and whitelisted users: " + string.Join(",", onlineWhitelistedUsers));
PluginLog.Debug("Online and whitelisted users: " + string.Join(",", _onlineWhitelistedUsers));
_framework.Update += Framework_Update;
_ipcManager.PenumbraRedrawEvent += IpcManager_PenumbraRedrawEvent;
@@ -221,6 +226,12 @@ namespace MareSynchronos.Managers
_framework.Update -= Framework_Update;
_ipcManager.PenumbraRedrawEvent -= IpcManager_PenumbraRedrawEvent;
_clientState.TerritoryChanged -= ClientState_TerritoryChanged;
foreach (var character in _onlineWhitelistedUsers)
{
RestoreCharacter(character);
}
_lastSentHash = string.Empty;
}
private void ApiControllerOnAddedToWhitelist(object? sender, EventArgs e)
@@ -230,7 +241,7 @@ namespace MareSynchronos.Managers
var players = GetLocalPlayers();
if (players.ContainsKey(characterHash))
{
PluginLog.Debug("You got added to a whitelist, restoring data for " + characterHash);
PluginLog.Debug("Removed from whitelist, restoring data for " + characterHash);
_ = _apiController.GetCharacterData(new Dictionary<string, int> { { characterHash, (int)players[characterHash].ClassJob.Id } });
}
}
@@ -287,8 +298,8 @@ namespace MareSynchronos.Managers
}
PluginLog.Debug("Assigned hash to visible player: " + otherPlayerName);
/*ipcManager.PenumbraRemoveTemporaryCollection(otherPlayerName);
ipcManager.PenumbraCreateTemporaryCollection(otherPlayerName);
_ipcManager.PenumbraRemoveTemporaryCollection(otherPlayerName);
_ipcManager.PenumbraCreateTemporaryCollection(otherPlayerName);
Dictionary<string, string> moddedPaths = new();
using (var db = new FileCacheContext())
{
@@ -306,41 +317,49 @@ namespace MareSynchronos.Managers
}
}
ipcManager.PenumbraSetTemporaryMods(otherPlayerName, moddedPaths);*/
_ipcManager.PenumbraSetTemporaryMods(otherPlayerName, moddedPaths);
_ipcManager.GlamourerApplyCharacterCustomization(e.CharacterData.GlamourerData, otherPlayerName);
//ipcManager.PenumbraRedraw(otherPlayerName);
_ipcManager.PenumbraRedraw(otherPlayerName);
}
private void ApiControllerOnRemovedFromWhitelist(object? sender, EventArgs e)
{
var characterHash = (string?)sender;
if (string.IsNullOrEmpty(characterHash)) return;
RestoreCharacter(characterHash);
}
private void RestoreCharacter(string characterHash)
{
var players = GetLocalPlayers();
foreach (var entry in _characterCache.Where(c => c.Key.Item1 == characterHash))
{
_characterCache.Remove(entry.Key);
}
var playerName = players.SingleOrDefault(p => p.Key == characterHash).Value.Name.ToString() ?? null;
if (playerName != null)
foreach (var player in players)
{
if (player.Key != characterHash) continue;
var playerName = player.Value.Name.ToString();
RestorePreviousCharacter(playerName);
PluginLog.Debug("Removed from whitelist, restoring glamourer state for " + playerName);
_ipcManager.PenumbraRemoveTemporaryCollection(playerName);
_ipcManager.GlamourerRevertCharacterCustomization(playerName);
break;
}
}
private void ApiControllerOnWhitelistedPlayerOffline(object? sender, EventArgs e)
{
PluginLog.Debug("Player offline: " + sender!);
onlineWhitelistedUsers.Remove((string)sender!);
_onlineWhitelistedUsers.Remove((string)sender!);
}
private void ApiControllerOnWhitelistedPlayerOnline(object? sender, EventArgs e)
{
PluginLog.Debug("Player online: " + sender!);
onlineWhitelistedUsers.Add((string)sender!);
_onlineWhitelistedUsers.Add((string)sender!);
}
private async Task AssignLocalPlayersData()
@@ -351,11 +370,7 @@ namespace MareSynchronos.Managers
{
if (currentLocalPlayers.ContainsKey(player.Key.Item1))
{
await Task.Run(() => ApiControllerOnCharacterReceived(null, new CharacterReceivedEventArgs
{
CharacterNameHash = player.Key.Item1,
CharacterData = player.Value
}));
await Task.Run(() => ApiControllerOnCharacterReceived(null, new CharacterReceivedEventArgs(player.Key.Item1, player.Value)));
}
}
@@ -413,7 +428,7 @@ namespace MareSynchronos.Managers
var pObj = (PlayerCharacter)obj;
var hashedName = Crypto.GetHash256(pObj.Name.ToString() + pObj.HomeWorld.Id.ToString());
if (!onlineWhitelistedUsers.Contains(hashedName)) continue;
if (!_onlineWhitelistedUsers.Contains(hashedName)) continue;
localPlayersList.Add(hashedName);
if (!_cachedLocalPlayers.ContainsKey(hashedName)) newPlayers[hashedName] = pObj;
@@ -455,7 +470,7 @@ namespace MareSynchronos.Managers
string playerName = obj.Name.ToString();
if (playerName == GetPlayerName()) continue;
var playerObject = (PlayerCharacter)obj;
allLocalPlayers.Add(Crypto.GetHash256(playerObject.Name.ToString() + playerObject.HomeWorld.Id.ToString()), playerObject);
allLocalPlayers[Crypto.GetHash256(playerObject.Name.ToString() + playerObject.HomeWorld.Id.ToString())] = playerObject;
}
return allLocalPlayers;
@@ -509,7 +524,7 @@ namespace MareSynchronos.Managers
var cacheDto = characterCacheTask.Result.ToCharacterCacheDto();
if (cacheDto.Hash == _lastSentHash)
{
PluginLog.Warning("Not sending data, already sent");
PluginLog.Debug("Not sending data, already sent");
return;
}
Task.WaitAll(_apiController.SendCharacterData(cacheDto, GetLocalPlayers().Select(d => d.Key).ToList()));

View File

@@ -0,0 +1,187 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Dalamud.Logging;
using MareSynchronos.Factories;
using MareSynchronos.FileCacheDB;
namespace MareSynchronos.Managers
{
internal class FileCacheManager : IDisposable
{
private const int MinutesForScan = 10;
private readonly FileCacheFactory _fileCacheFactory;
private readonly IpcManager _ipcManager;
private readonly Configuration _pluginConfiguration;
private CancellationTokenSource? _scanCancellationTokenSource;
private System.Timers.Timer? _scanScheduler;
private Task? _scanTask;
private Stopwatch? _timerStopWatch;
public FileCacheManager(FileCacheFactory fileCacheFactory, IpcManager ipcManager, Configuration pluginConfiguration)
{
_fileCacheFactory = fileCacheFactory;
_ipcManager = ipcManager;
_pluginConfiguration = pluginConfiguration;
if (_ipcManager.CheckPenumbraApi()
&& _pluginConfiguration.AcceptedAgreement
&& !string.IsNullOrEmpty(_pluginConfiguration.CacheFolder)
&& _pluginConfiguration.ClientSecret.ContainsKey(_pluginConfiguration.ApiUri)
&& !string.IsNullOrEmpty(_ipcManager.PenumbraModDirectory()))
{
StartInitialScan();
}
}
public long CurrentFileProgress { get; private set; }
public bool IsScanRunning => !_scanTask?.IsCompleted ?? false;
public TimeSpan TimeToNextScan => TimeSpan.FromMinutes(MinutesForScan).Subtract(_timerStopWatch?.Elapsed ?? TimeSpan.FromMinutes(MinutesForScan));
public long TotalFiles { get; private set; }
public void Dispose()
{
PluginLog.Debug("Disposing File Cache Manager");
_scanScheduler?.Stop();
_scanCancellationTokenSource?.Cancel();
}
public void StartInitialScan()
{
_scanCancellationTokenSource = new CancellationTokenSource();
_scanTask = StartFileScan(_scanCancellationTokenSource.Token);
}
private async Task StartFileScan(CancellationToken ct)
{
_scanCancellationTokenSource = new CancellationTokenSource();
var penumbraDir = _ipcManager.PenumbraModDirectory()!;
PluginLog.Debug("Getting files from " + penumbraDir);
var scannedFiles = new ConcurrentDictionary<string, bool>(
Directory.EnumerateFiles(penumbraDir, "*.*", SearchOption.AllDirectories)
.Select(s => s.ToLowerInvariant())
.Where(f => f.Contains(@"\chara\") && (f.EndsWith(".tex") || f.EndsWith(".mdl") || f.EndsWith(".mtrl")))
.Select(p => new KeyValuePair<string, bool>(p, false)));
List<FileCache> fileCaches;
await using (FileCacheContext db = new())
{
fileCaches = db.FileCaches.ToList();
}
TotalFiles = scannedFiles.Count;
var fileCachesToUpdate = new ConcurrentBag<FileCache>();
var fileCachesToDelete = new ConcurrentBag<FileCache>();
var fileCachesToAdd = new ConcurrentBag<FileCache>();
PluginLog.Debug("Getting file list from Database");
// scan files from database
Parallel.ForEach(fileCaches, new ParallelOptions()
{
MaxDegreeOfParallelism = _pluginConfiguration.MaxParallelScan,
CancellationToken = ct,
},
cache =>
{
if (ct.IsCancellationRequested) return;
if (!File.Exists(cache.Filepath))
{
fileCachesToDelete.Add(cache);
}
else
{
if (scannedFiles.ContainsKey(cache.Filepath))
{
scannedFiles[cache.Filepath] = true;
}
FileInfo fileInfo = new(cache.Filepath);
if (fileInfo.LastWriteTimeUtc.Ticks == long.Parse(cache.LastModifiedDate)) return;
_fileCacheFactory.UpdateFileCache(cache);
fileCachesToUpdate.Add(cache);
}
var files = CurrentFileProgress;
Interlocked.Increment(ref files);
CurrentFileProgress = files;
});
if (ct.IsCancellationRequested) return;
// scan new files
Parallel.ForEach(scannedFiles.Where(c => c.Value == false), new ParallelOptions()
{
MaxDegreeOfParallelism = _pluginConfiguration.MaxParallelScan,
CancellationToken = ct
},
file =>
{
fileCachesToAdd.Add(_fileCacheFactory.Create(file.Key));
var files = CurrentFileProgress;
Interlocked.Increment(ref files);
CurrentFileProgress = files;
});
await using (FileCacheContext db = new())
{
if (fileCachesToAdd.Any() || fileCachesToUpdate.Any() || fileCachesToDelete.Any())
{
db.FileCaches.AddRange(fileCachesToAdd);
db.FileCaches.UpdateRange(fileCachesToUpdate);
db.FileCaches.RemoveRange(fileCachesToDelete);
await db.SaveChangesAsync(ct);
}
}
PluginLog.Debug("Scan complete");
TotalFiles = 0;
CurrentFileProgress = 0;
if (!_pluginConfiguration.InitialScanComplete)
{
_pluginConfiguration.InitialScanComplete = true;
_pluginConfiguration.Save();
_timerStopWatch = Stopwatch.StartNew();
StartScheduler();
}
else if (_timerStopWatch == null)
{
StartScheduler();
_timerStopWatch = Stopwatch.StartNew();
}
}
private void StartScheduler()
{
PluginLog.Debug("Scheduling next scan for in " + MinutesForScan + " minutes");
_scanScheduler = new System.Timers.Timer(TimeSpan.FromMinutes(MinutesForScan).TotalMilliseconds)
{
AutoReset = false,
Enabled = false,
};
_scanScheduler.AutoReset = true;
_scanScheduler.Elapsed += (_, _) =>
{
_timerStopWatch?.Stop();
if (_scanTask?.IsCompleted ?? false)
{
PluginLog.Warning("Scanning task is still running, not reinitiating.");
return;
}
PluginLog.Debug("Initiating periodic scan for mod changes");
_scanTask = StartFileScan(_scanCancellationTokenSource!.Token);
_timerStopWatch = Stopwatch.StartNew();
};
_scanScheduler.Start();
}
}
}

View File

@@ -10,23 +10,23 @@ namespace MareSynchronos.Managers
{
public class IpcManager : IDisposable
{
private readonly DalamudPluginInterface pluginInterface;
private ICallGateSubscriber<object> penumbraInit;
private ICallGateSubscriber<string, string, string>? penumbraResolvePath;
private ICallGateSubscriber<string>? penumbraResolveModDir;
private ICallGateSubscriber<string>? glamourerGetCharacterCustomization;
private ICallGateSubscriber<string, string, object>? glamourerApplyCharacterCustomization;
private ICallGateSubscriber<int> penumbraApiVersion;
private ICallGateSubscriber<int> glamourerApiVersion;
private ICallGateSubscriber<IntPtr, int, object?> penumbraObjectIsRedrawn;
private ICallGateSubscriber<string, int, object>? penumbraRedraw;
private ICallGateSubscriber<string, string, string[]>? penumbraReverseResolvePath;
private ICallGateSubscriber<string, object> glamourerRevertCustomization;
private readonly DalamudPluginInterface _pluginInterface;
private readonly ICallGateSubscriber<object> _penumbraInit;
private readonly ICallGateSubscriber<string, string, string>? _penumbraResolvePath;
private readonly ICallGateSubscriber<string>? _penumbraResolveModDir;
private readonly ICallGateSubscriber<string>? _glamourerGetCharacterCustomization;
private readonly ICallGateSubscriber<string, string, object>? _glamourerApplyCharacterCustomization;
private readonly ICallGateSubscriber<int> _penumbraApiVersion;
private readonly ICallGateSubscriber<int> _glamourerApiVersion;
private readonly ICallGateSubscriber<IntPtr, int, object?> _penumbraObjectIsRedrawn;
private readonly ICallGateSubscriber<string, int, object>? _penumbraRedraw;
private readonly ICallGateSubscriber<string, string, string[]>? _penumbraReverseResolvePath;
private readonly ICallGateSubscriber<string, object> _glamourerRevertCustomization;
private ICallGateSubscriber<string, string, IReadOnlyDictionary<string, string>, List<string>, int, int>
penumbraSetTemporaryMod;
private ICallGateSubscriber<string, string, bool, (int, string)> penumbraCreateTemporaryCollection;
private ICallGateSubscriber<string, int> penumbraRemoveTemporaryCollection;
private readonly ICallGateSubscriber<string, string, IReadOnlyDictionary<string, string>, List<string>, int, int>
_penumbraSetTemporaryMod;
private readonly ICallGateSubscriber<string, string, bool, (int, string)> _penumbraCreateTemporaryCollection;
private readonly ICallGateSubscriber<string, int> _penumbraRemoveTemporaryCollection;
public bool Initialized { get; private set; } = false;
@@ -34,41 +34,41 @@ namespace MareSynchronos.Managers
public IpcManager(DalamudPluginInterface pi)
{
pluginInterface = pi;
_pluginInterface = pi;
penumbraInit = pluginInterface.GetIpcSubscriber<object>("Penumbra.Initialized");
penumbraResolvePath = pluginInterface.GetIpcSubscriber<string, string, string>("Penumbra.ResolveCharacterPath");
penumbraResolveModDir = pluginInterface.GetIpcSubscriber<string>("Penumbra.GetModDirectory");
penumbraRedraw = pluginInterface.GetIpcSubscriber<string, int, object>("Penumbra.RedrawObjectByName");
glamourerGetCharacterCustomization = pluginInterface.GetIpcSubscriber<string>("Glamourer.GetCharacterCustomization");
glamourerApplyCharacterCustomization = pluginInterface.GetIpcSubscriber<string, string, object>("Glamourer.ApplyCharacterCustomization");
penumbraReverseResolvePath = pluginInterface.GetIpcSubscriber<string, string, string[]>("Penumbra.ReverseResolvePath");
penumbraApiVersion = pluginInterface.GetIpcSubscriber<int>("Penumbra.ApiVersion");
glamourerApiVersion = pluginInterface.GetIpcSubscriber<int>("Glamourer.ApiVersion");
glamourerRevertCustomization = pluginInterface.GetIpcSubscriber<string, object>("Glamourer.RevertCharacterCustomization");
penumbraObjectIsRedrawn = pluginInterface.GetIpcSubscriber<IntPtr, int, object?>("Penumbra.GameObjectRedrawn");
_penumbraInit = _pluginInterface.GetIpcSubscriber<object>("Penumbra.Initialized");
_penumbraResolvePath = _pluginInterface.GetIpcSubscriber<string, string, string>("Penumbra.ResolveCharacterPath");
_penumbraResolveModDir = _pluginInterface.GetIpcSubscriber<string>("Penumbra.GetModDirectory");
_penumbraRedraw = _pluginInterface.GetIpcSubscriber<string, int, object>("Penumbra.RedrawObjectByName");
_glamourerGetCharacterCustomization = _pluginInterface.GetIpcSubscriber<string>("Glamourer.GetCharacterCustomization");
_glamourerApplyCharacterCustomization = _pluginInterface.GetIpcSubscriber<string, string, object>("Glamourer.ApplyCharacterCustomization");
_penumbraReverseResolvePath = _pluginInterface.GetIpcSubscriber<string, string, string[]>("Penumbra.ReverseResolvePath");
_penumbraApiVersion = _pluginInterface.GetIpcSubscriber<int>("Penumbra.ApiVersion");
_glamourerApiVersion = _pluginInterface.GetIpcSubscriber<int>("Glamourer.ApiVersion");
_glamourerRevertCustomization = _pluginInterface.GetIpcSubscriber<string, object>("Glamourer.RevertCharacterCustomization");
_penumbraObjectIsRedrawn = _pluginInterface.GetIpcSubscriber<IntPtr, int, object?>("Penumbra.GameObjectRedrawn");
penumbraObjectIsRedrawn.Subscribe(RedrawEvent);
penumbraInit.Subscribe(RedrawSelf);
_penumbraObjectIsRedrawn.Subscribe(RedrawEvent);
_penumbraInit.Subscribe(RedrawSelf);
penumbraSetTemporaryMod =
pluginInterface
_penumbraSetTemporaryMod =
_pluginInterface
.GetIpcSubscriber<string, string, IReadOnlyDictionary<string, string>, List<string>, int,
int>("Penumbra.AddTemporaryMod");
penumbraCreateTemporaryCollection =
pluginInterface.GetIpcSubscriber<string, string, bool, (int, string)>("Penumbra.CreateTemporaryCollection");
penumbraRemoveTemporaryCollection =
pluginInterface.GetIpcSubscriber<string, int>("Penumbra.RemoveTemporaryCollection");
_penumbraCreateTemporaryCollection =
_pluginInterface.GetIpcSubscriber<string, string, bool, (int, string)>("Penumbra.CreateTemporaryCollection");
_penumbraRemoveTemporaryCollection =
_pluginInterface.GetIpcSubscriber<string, int>("Penumbra.RemoveTemporaryCollection");
Initialized = true;
}
public bool CheckPenumbraAPI()
public bool CheckPenumbraApi()
{
try
{
return penumbraApiVersion.InvokeFunc() >= 4;
return _penumbraApiVersion.InvokeFunc() >= 4;
}
catch
{
@@ -76,11 +76,11 @@ namespace MareSynchronos.Managers
}
}
public bool CheckGlamourerAPI()
public bool CheckGlamourerApi()
{
try
{
return glamourerApiVersion.InvokeFunc() >= 0;
return _glamourerApiVersion.InvokeFunc() >= 0;
}
catch
{
@@ -95,91 +95,78 @@ namespace MareSynchronos.Managers
private void RedrawSelf()
{
penumbraRedraw!.InvokeAction("self", 0);
_penumbraRedraw!.InvokeAction("self", 0);
}
private void Uninitialize()
{
penumbraInit.Unsubscribe(RedrawSelf);
penumbraObjectIsRedrawn.Unsubscribe(RedrawEvent);
penumbraResolvePath = null;
penumbraResolveModDir = null;
glamourerGetCharacterCustomization = null;
glamourerApplyCharacterCustomization = null;
penumbraReverseResolvePath = null;
_penumbraInit.Unsubscribe(RedrawSelf);
_penumbraObjectIsRedrawn.Unsubscribe(RedrawEvent);
Initialized = false;
PluginLog.Debug("IPC Manager disposed");
}
public string[] PenumbraReverseResolvePath(string path, string characterName)
{
if (!CheckPenumbraAPI()) return new[] { path };
return penumbraReverseResolvePath!.InvokeFunc(path, characterName);
if (!CheckPenumbraApi()) return new[] { path };
return _penumbraReverseResolvePath!.InvokeFunc(path, characterName);
}
public string? PenumbraResolvePath(string path, string characterName)
{
if (!CheckPenumbraAPI()) return null;
return penumbraResolvePath!.InvokeFunc(path, characterName);
if (!CheckPenumbraApi()) return null;
return _penumbraResolvePath!.InvokeFunc(path, characterName);
}
public string? PenumbraModDirectory()
{
if (!CheckPenumbraAPI()) return null;
return penumbraResolveModDir!.InvokeFunc();
if (!CheckPenumbraApi()) return null;
return _penumbraResolveModDir!.InvokeFunc();
}
public string? GlamourerGetCharacterCustomization()
{
if (!CheckGlamourerAPI()) return null;
return glamourerGetCharacterCustomization!.InvokeFunc();
if (!CheckGlamourerApi()) return null;
return _glamourerGetCharacterCustomization!.InvokeFunc();
}
public void GlamourerApplyCharacterCustomization(string customization, string characterName)
{
if (!CheckGlamourerAPI()) return;
glamourerApplyCharacterCustomization!.InvokeAction(customization, characterName);
if (!CheckGlamourerApi()) return;
_glamourerApplyCharacterCustomization!.InvokeAction(customization, characterName);
}
public void GlamourerRevertCharacterCustomization(string characterName)
{
if (!CheckGlamourerAPI()) return;
glamourerRevertCustomization!.InvokeAction(characterName);
if (!CheckGlamourerApi()) return;
_glamourerRevertCustomization!.InvokeAction(characterName);
}
public void PenumbraRedraw(string actorName)
{
if (!CheckPenumbraAPI()) return;
penumbraRedraw!.InvokeAction(actorName, 0);
if (!CheckPenumbraApi()) return;
_penumbraRedraw!.InvokeAction(actorName, 0);
}
public void PenumbraCreateTemporaryCollection(string characterName)
{
if (!CheckPenumbraAPI()) return;
if (!CheckPenumbraApi()) return;
PluginLog.Debug("Creating temp collection for " + characterName);
//penumbraCreateTemporaryCollection.InvokeFunc("MareSynchronos", characterName, true);
}
public void PenumbraRemoveTemporaryCollection(string characterName)
{
if (!CheckPenumbraAPI()) return;
if (!CheckPenumbraApi()) return;
PluginLog.Debug("Removing temp collection for " + characterName);
//penumbraRemoveTemporaryCollection.InvokeFunc(characterName);
}
public void PenumbraSetTemporaryMods(string characterName, IReadOnlyDictionary<string, string> modPaths)
{
if (!CheckPenumbraAPI()) return;
if (!CheckPenumbraApi()) return;
PluginLog.Debug("Assigning temp mods for " + characterName);
try
{
//var result = penumbraSetTemporaryMod.InvokeFunc("MareSynchronos", characterName, modPaths, new List<string>(), 0);
//PluginLog.Debug("Success: " + result);
}
catch (Exception ex)
{
PluginLog.Error(ex, "Error during IPC call");
}
//penumbraSetTemporaryMod.InvokeFunc("MareSynchronos", characterName, modPaths, new List<string>(), 0);
}
public void Dispose()