Skip to content

Commit

Permalink
Fixed core update check (only works for cores initially downloaded fr…
Browse files Browse the repository at this point in the history
…om the menu)

Applied DRY-ish principle for DllModule base class and derivatives (osx and linux had the exact same code, minus the extension property).
  • Loading branch information
Skurdt committed Sep 16, 2020
1 parent 05c8981 commit 40f263a
Show file tree
Hide file tree
Showing 12 changed files with 320 additions and 285 deletions.
158 changes: 90 additions & 68 deletions Assets/Example/Scripts/Editor/LibretroManagerWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ public sealed class LibretroManagerWindow : EditorWindow
[Serializable]
public sealed class Core
{
public string FullName;
public string DisplayName;
public string LastModified;
public bool Available;
public bool Latest;
public string FullName = string.Empty;
public string DisplayName = string.Empty;
public string CurrentDate = string.Empty;
public string LatestDate = string.Empty;
public bool Available = false;

public bool Latest => CurrentDate.Equals(LatestDate, StringComparison.OrdinalIgnoreCase);
}

[Serializable]
Expand All @@ -53,26 +55,17 @@ public sealed class CoreList

public void Add(Core core) => Cores.Add(core);
}
static string CurrentPlatform()
{
switch (Application.platform)
{
case RuntimePlatform.LinuxEditor:
return "linux";
default:
return "windows";
}
}

private static string _buildBotUrl = $"https://buildbot.libretro.com/nightly/{CurrentPlatform()}/x86_64/latest/";
private static readonly string _buildbotUrl = $"https://buildbot.libretro.com/nightly/{CurrentPlatform()}/x86_64/latest/";
private static readonly string _libretroDirectory = Path.Combine(Application.streamingAssetsPath, "libretro~");
private static readonly string _coresDirectory = Path.Combine(_libretroDirectory, "cores");
private static readonly string _coresStatusFile = Path.Combine(_libretroDirectory, "cores.json");
private static readonly Color _orangeColor = new Color(0.6f, 0.6f, 0f, 1f);
private static readonly Color _greenColor = Color.green;
private static readonly Color _orangeColor = new Color(1.0f, 0.5f, 0f, 1f);
private static readonly Color _redColor = Color.red;

private static CoreList _coreList;
private static Color _defaultBgColor;
private Vector2 _scrollPos;
private static Vector2 _scrollPos;

[MenuItem("Libretro/Manage Cores"), SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "Unity Editor")]
private static void ShowWindow()
Expand All @@ -87,28 +80,26 @@ private static void ShowWindow()
_ = Directory.CreateDirectory(_coresDirectory);
}

_defaultBgColor = GUI.backgroundColor;

_coreList = FileSystem.DeserializeFromJson<CoreList>(_coresStatusFile);
if (_coreList == null)
{
_coreList = new CoreList();
}

Refresh();

GetWindow<LibretroManagerWindow>("Core Manager").minSize = new Vector2(286f, 120f);
}

private void OnGUI()
{
GUILayout.Space(16f);

if (GUILayout.Button("Check for updates", GUILayout.Height(EditorGUIUtility.singleLineHeight * 2f)))
if (GUILayout.Button("Refresh", GUILayout.Height(EditorGUIUtility.singleLineHeight * 2f)))
{
CheckForUpdates();
Refresh();
}

GUILayout.Space(16f);

GUILayout.Space(8f);
_scrollPos = GUILayout.BeginScrollView(_scrollPos);
{
foreach (Core core in _coreList.Cores)
Expand All @@ -120,82 +111,113 @@ private void OnGUI()
string buttonText;
if (core.Available && core.Latest)
{
GUI.backgroundColor = Color.green;
buttonText = "OK";
GUI.backgroundColor = _greenColor;
buttonText = "OK";
}
else if (core.Available && !core.Latest)
{
GUI.backgroundColor = _orangeColor;
buttonText = "Update";
buttonText = "Update";
}
else
{
GUI.backgroundColor = Color.red;
buttonText = "Download";
GUI.backgroundColor = _redColor;
buttonText = "Download";
}

if (GUILayout.Button(new GUIContent(buttonText, null, core.DisplayName), GUILayout.Width(80f), GUILayout.Height(EditorGUIUtility.singleLineHeight)))
if (GUILayout.Button(new GUIContent(buttonText, null, core.DisplayName), GUILayout.Width(80f), GUILayout.Height(EditorGUIUtility.singleLineHeight)) && !core.Latest)
{
if (!core.Available || !core.Latest)
try
{
string url = $"{_buildBotUrl}{core.FullName}";
string zipPath = DownloadFile(url);
string zipPath = DownloadFile($"{_buildbotUrl}{core.FullName}");
ExtractFile(zipPath);
CheckForUpdates();

core.CurrentDate = core.LatestDate;
core.Available = true;

_coreList.Cores = _coreList.Cores.OrderBy(x => x.DisplayName).ToList();
_ = FileSystem.SerializeToJson(_coreList, _coresStatusFile);
}
catch (Exception e)
{
Debug.LogException(e);
}
}

GUI.backgroundColor = _defaultBgColor;
}
}
GUILayout.EndHorizontal();
}
}
GUILayout.EndScrollView();
}

private static void CheckForUpdates()
private static string CurrentPlatform()
{
switch (Application.platform)
{
case RuntimePlatform.LinuxEditor:
{
return "linux";
}
default:
{
return "windows";
}
}
}

private static void Refresh()
{
foreach (Core core in _coreList.Cores)
{
bool fileExists = File.Exists(Path.GetFullPath(Path.Combine(_coresDirectory, core.FullName.Replace(".zip", string.Empty))));
if (!fileExists)
{
core.CurrentDate = string.Empty;
core.LatestDate = string.Empty;
core.Available = false;
}
}

HtmlWeb hw = new HtmlWeb();
HtmlDocument doc = hw.Load(new Uri(_buildBotUrl));
HtmlDocument doc = hw.Load(new Uri(_buildbotUrl));
HtmlNodeCollection trNodes = doc.DocumentNode.SelectNodes("//body/div/table/tr");

foreach (HtmlNode trNode in trNodes)
{
HtmlNodeCollection tdNodes = trNode.ChildNodes;
foreach (HtmlNode node in tdNodes)
if (tdNodes.Count < 3)
{
string fileName = tdNodes[1].InnerText;
if (!fileName.Contains("_libretro"))
{
continue;
}
continue;
}

string lastModified = tdNodes[2].InnerText;
bool available = File.Exists(Path.GetFullPath(Path.Combine(_coresDirectory, fileName.Replace(".zip", string.Empty))));
Core found = _coreList.Cores.Find(x => x.FullName.Equals(fileName, StringComparison.OrdinalIgnoreCase));
if (found != null)
{
found.LastModified = lastModified;
found.Available = available;
found.Latest = found.LastModified.Equals(lastModified, StringComparison.OrdinalIgnoreCase);
}
else
{
string fileName = tdNodes[1].InnerText;
if (!fileName.Contains("_libretro"))
{
continue;
}

_coreList.Add(new Core
{
FullName = fileName,
DisplayName = fileName.Substring(0,fileName.IndexOf('.')),
LastModified = lastModified,
Available = available,
Latest = true
});
}
string lastModified = tdNodes[2].InnerText;
bool available = File.Exists(Path.GetFullPath(Path.Combine(_coresDirectory, fileName.Replace(".zip", string.Empty))));
Core found = _coreList.Cores.Find(x => x.FullName.Equals(fileName, StringComparison.OrdinalIgnoreCase));
if (found != null)
{
found.LatestDate = lastModified;
found.Available = available;
}
else
{
_coreList.Add(new Core
{
FullName = fileName,
DisplayName = fileName.Substring(0, fileName.IndexOf('.')),
LatestDate = lastModified,
Available = available
});
}
}

_coreList.Cores = _coreList.Cores.OrderBy(x => x.DisplayName).ToList();
_ = FileSystem.SerializeToJson(_coreList, _coresStatusFile);
_coreList.Cores = _coreList.Cores.OrderBy(x => x.Available).ThenBy(x => x.Latest).ThenBy(x => x.DisplayName).ToList();
}

private static string DownloadFile(string url)
Expand Down
105 changes: 105 additions & 0 deletions Assets/SK.Plugins/SK.Libretro/Scripts/Utilities/DllModule/DllModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/* MIT License
* Copyright (c) 2020 Skurdt
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE. */

using System;
using System.Runtime.InteropServices;

namespace SK.Libretro.Utilities
{
public abstract class DllModule
{
public string Path { get; private set; }
public string Name { get; private set; }
public string Extension { get; private set; }

protected IntPtr _nativeHandle;

protected DllModule(string extension) => Extension = extension;

public void Load(string path)
{
if (string.IsNullOrEmpty(path))
{
throw new Exception("Library path is null or empty.");
}

Path = System.IO.Path.GetFullPath(path);
Name = System.IO.Path.GetFileNameWithoutExtension(path);

try
{
LoadLibrary();
}
catch (Exception)
{
throw;
}
}

[return: MarshalAs(UnmanagedType.FunctionPtr)]
public T GetFunction<T>(string functionName) where T : Delegate
{
if (_nativeHandle == IntPtr.Zero)
{
throw new Exception($"Library '{Name}' not loaded, cannot get function '{functionName}'");
}

try
{
IntPtr procAddress = GetProcAddress(functionName);
if (procAddress == IntPtr.Zero)
{
throw new Exception($"Function '{functionName}' not found in library '{Name}' at path '{Path}'");
}

return Marshal.GetDelegateForFunctionPointer<T>(procAddress);
}
catch (Exception)
{
throw;
}
}

public void Free()
{
if (_nativeHandle == IntPtr.Zero)
{
return;
}

try
{
FreeLibrary();
}
catch (Exception)
{
throw;
}
}

protected abstract void LoadLibrary();

protected abstract IntPtr GetProcAddress(string functionName);

protected abstract void FreeLibrary();
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 40f263a

Please sign in to comment.