Skip to content

Commit

Permalink
Added support for per coordinate skin overlays in kk; Dedupe skin ove…
Browse files Browse the repository at this point in the history
…rlay textures
  • Loading branch information
ManlyMarco committed Mar 11, 2021
1 parent d72bf20 commit 9b191d4
Show file tree
Hide file tree
Showing 7 changed files with 430 additions and 119 deletions.
3 changes: 2 additions & 1 deletion Core_OverlayMods/Core_OverlayMods.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)AssemblyInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)OverlayStorage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)TextureStorage.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Clothes\ClothesTexData.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Clothes\KoiClothesOverlayController.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Clothes\KoiClothesOverlayGui.cs" />
Expand All @@ -19,7 +21,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Skin\KoiSkinOverlayController.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Skin\KoiSkinOverlayGui.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Skin\KoiSkinOverlayMgr.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Skin\OverlayTexture.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Skin\TexType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Skin\Util.cs" />
</ItemGroup>
Expand Down
178 changes: 178 additions & 0 deletions Core_OverlayMods/OverlayStorage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ExtensibleSaveFormat;
using KKAPI.Chara;
using KKAPI.Maker;
using KoiClothesOverlayX;
using MessagePack;
using UnityEngine;
#if KK
using CoordinateType = ChaFileDefine.CoordinateType;
#elif EC
using CoordinateType = KoikatsuCharaFile.ChaFileDefine.CoordinateType;
#elif AI || HS2
using AIChara;
#endif

namespace KoiSkinOverlayX
{
#if AI || HS2
public enum CoordinateType
{
Unknown = 0
}
#endif

public class OverlayStorage
{
private const string OverlayDataKey = "Lookup";

private readonly TextureStorage _textureStorage;
private readonly ChaControl _chaControl;
private Dictionary<CoordinateType, Dictionary<TexType, int>> _allOverlayTextures;

public OverlayStorage(CharaCustomFunctionController controller)
{
_chaControl = controller.ChaControl;
_textureStorage = new TextureStorage();
_allOverlayTextures = new Dictionary<CoordinateType, Dictionary<TexType, int>>();
}

private Dictionary<TexType, int> GetCurrentOverlayTextures()
{
#if KK
// Need to do this instead of polling the CurrentCoordinate prop because it's updated too late
var coordinateType = (CoordinateType)_chaControl.fileStatus.coordinateType;
#elif EC
var coordinateType = CoordinateType.School01;
#else
var coordinateType = CoordinateType.Unknown;
#endif
return GetOverlayTextures(coordinateType);
}

private Dictionary<TexType, int> GetOverlayTextures(CoordinateType coordinateType)
{
_allOverlayTextures.TryGetValue(coordinateType, out var dict);

if (dict == null)
{
dict = new Dictionary<TexType, int>();
_allOverlayTextures.Add(coordinateType, dict);
}

return dict;
}

//CoordinateType coordinateType
public Texture2D GetTexture(TexType type)
{
var texs = GetCurrentOverlayTextures();
if (texs.TryGetValue(type, out var id))
return _textureStorage.GetSharedTexture(id);

return null;
}

public void SetTexture(TexType type, byte[] pngData)
{
var texs = GetCurrentOverlayTextures();
if (pngData == null)
{
texs.Remove(type);
}
else
{
var id = _textureStorage.StoreTexture(pngData);
texs[type] = id;
}
}

public int GetCount(bool onlyCurrentCoord = true)
{
return onlyCurrentCoord ? GetCurrentOverlayTextures().Count : _allOverlayTextures.Sum(x => x.Value.Count);
}

public void Clear()
{
// Less garbage generated than clearing the whole dict?
foreach (var dic in _allOverlayTextures) dic.Value.Clear();
_textureStorage.Clear();
}

public void Load(PluginData data)
{
data.data.TryGetValue(OverlayDataKey, out var lookup);
if (lookup is byte[] lookuparr)
{
try
{
_allOverlayTextures = MessagePackSerializer.Deserialize<Dictionary<CoordinateType, Dictionary<TexType, int>>>(lookuparr);
_textureStorage.Load(data);
}
catch (Exception ex)
{
if (MakerAPI.InsideMaker)
KoiSkinOverlayMgr.Logger.LogMessage("WARNING: Failed to load embedded overlay data for " + (_chaControl.chaFile?.charaFileName ?? "?"));
else
KoiSkinOverlayMgr.Logger.LogDebug("WARNING: Failed to load embedded overlay data for " + (_chaControl.chaFile?.charaFileName ?? "?"));
KoiSkinOverlayMgr.Logger.LogError(ex);

Clear();
}
}
}

public void Save(PluginData data)
{
PurgeUnused();
if (GetCount(false) > 0)
{
_textureStorage.Save(data);
data.data[OverlayDataKey] = MessagePackSerializer.Serialize(_allOverlayTextures);
}
}

private void PurgeUnused()
{
//foreach (var dic in _allOverlayTextures.ToList())
//{
// if (dic.Value.Count == 0)
// _allOverlayTextures.Remove(dic.Key);
//}
_textureStorage.PurgeUnused(_allOverlayTextures.SelectMany(x => x.Value.Values));
}

#if KK
public bool IsPerCoord()
{
Dictionary<TexType, int> first = null;
foreach (var dic in _allOverlayTextures)
{
if (first == null)
first = dic.Value;
else if (!dic.Value.SequenceEqual(first))
return true;
}

return false;
}

public void CopyToOtherCoords()
{
var cur = GetCurrentOverlayTextures();

foreach (CoordinateType ctype in Enum.GetValues(typeof(CoordinateType)))
{
var other = GetOverlayTextures(ctype);
if (cur == other) continue;

other.Clear();
foreach (var curval in cur)
other.Add(curval.Key, curval.Value);
}
}
#endif
}
}
80 changes: 28 additions & 52 deletions Core_OverlayMods/Skin/KoiSkinOverlayController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using ExtensibleSaveFormat;
using KKAPI;
using KKAPI.Chara;
using UniRx;
using UnityEngine;
#if AI || HS2
using AIChara;
Expand All @@ -19,28 +20,31 @@ public class KoiSkinOverlayController : CharaCustomFunctionController
/// </summary>
public List<AdditionalTexture> AdditionalTextures { get; } = new List<AdditionalTexture>();

private readonly Dictionary<TexType, OverlayTexture> _overlays = new Dictionary<TexType, OverlayTexture>();
public OverlayStorage OverlayStorage { get; private set; }

public IEnumerable<KeyValuePair<TexType, OverlayTexture>> Overlays => _overlays.AsEnumerable();
protected override void Awake()
{
base.Awake();
OverlayStorage = new OverlayStorage(this);
#if KK
CurrentCoordinate.Subscribe(v => UpdateTexture(0));
#endif
}

protected override void OnCardBeingSaved(GameMode currentGameMode)
{
var pd = new PluginData { version = 1 };
var pd = new PluginData { version = 2 };

foreach (var overlay in Overlays)
{
if (overlay.Value != null)
pd.data.Add(overlay.Key.ToString(), overlay.Value.Data);
}
OverlayStorage.Save(pd);

SetExtendedData(pd);
SetExtendedData(pd.data.Count > 0 ? pd : null);
}

protected override void OnReload(GameMode currentGameMode, bool maintainState)
{
if (maintainState) return;

var needsUpdate = _overlays.Any();
var needsUpdate = OverlayStorage.GetCount() > 0;
RemoveAllOverlays(false);

var data = GetExtendedData();
Expand All @@ -49,18 +53,13 @@ protected override void OnReload(GameMode currentGameMode, bool maintainState)
if (data.version <= 1)
ReadLegacyData(data);
else
ReadData(data);
OverlayStorage.Load(data);
}

if (needsUpdate || _overlays.Any())
if (needsUpdate || OverlayStorage.GetCount() > 0)
UpdateTexture(TexType.Unknown);
}

private void ReadData(PluginData data)
{
throw new NotImplementedException();
}

private void ReadLegacyData(PluginData data)
{
foreach (TexType texType in Enum.GetValues(typeof(TexType)))
Expand All @@ -73,17 +72,17 @@ private void ReadLegacyData(PluginData data)
{
if (texType == TexType.EyeOver)
{
_overlays.Add(TexType.EyeOverL, new OverlayTexture(bytes));
_overlays.Add(TexType.EyeOverR, new OverlayTexture(bytes));
OverlayStorage.SetTexture(TexType.EyeOverL, bytes);
OverlayStorage.SetTexture(TexType.EyeOverR, bytes);
}
else if (texType == TexType.EyeUnder)
{
_overlays.Add(TexType.EyeUnderL, new OverlayTexture(bytes));
_overlays.Add(TexType.EyeUnderR, new OverlayTexture(bytes));
OverlayStorage.SetTexture(TexType.EyeUnderL, bytes);
OverlayStorage.SetTexture(TexType.EyeUnderR, bytes);
}
else
{
_overlays.Add(texType, new OverlayTexture(bytes));
OverlayStorage.SetTexture(texType, bytes);
}
}
}
Expand All @@ -97,8 +96,8 @@ public void ApplyOverlayToRT(RenderTexture bodyTexture, TexType overlayType)

internal IEnumerable<Texture2D> GetOverlayTextures(TexType overlayType)
{
if (_overlays.TryGetValue(overlayType, out var tex))
yield return tex.Texture;
var tex = OverlayStorage.GetTexture(overlayType);
if (tex) yield return tex;

foreach (var additionalTexture in AdditionalTextures.Where(x => x.OverlayType == overlayType && x.Texture != null).OrderBy(x => x.ApplyOrder))
yield return additionalTexture.Texture;
Expand All @@ -110,40 +109,19 @@ internal static void ApplyOverlays(RenderTexture targetTexture, IEnumerable<Text
ApplyOverlay(targetTexture, overlay);
}

public OverlayTexture SetOverlayTex(byte[] overlayTex, TexType overlayType)
public Texture2D SetOverlayTex(byte[] overlayTex, TexType overlayType)
{
if (overlayType == TexType.EyeOver || overlayType == TexType.EyeUnder)
{
SetOverlayTex(overlayTex, overlayType + 2);
return SetOverlayTex(overlayTex, overlayType + 4); //todo return the correct thing
return SetOverlayTex(overlayTex, overlayType + 4);
}

_overlays.TryGetValue(overlayType, out var existing);

if (overlayTex == null)
{
// Remove the overlay
existing?.Dispose();
_overlays.Remove(overlayType);
existing = null;
}
else
{
// Update or add
if (existing == null)
{
existing = new OverlayTexture(overlayTex);
_overlays.Add(overlayType, existing);
}
else
{
existing.Data = overlayTex;
}
}
OverlayStorage.SetTexture(overlayType, overlayTex);

UpdateTexture(overlayType);

return existing;
return OverlayStorage.GetTexture(overlayType);
}

public void UpdateTexture(TexType type)
Expand All @@ -160,9 +138,7 @@ protected override void OnDestroy()

private void RemoveAllOverlays(bool removeAdditional)
{
foreach (var kvp in _overlays)
kvp.Value.Dispose();
_overlays.Clear();
OverlayStorage.Clear();

if (removeAdditional)
AdditionalTextures.Clear();
Expand Down

0 comments on commit 9b191d4

Please sign in to comment.