Skip to content

Commit

Permalink
internal refactoring and better DTR bar
Browse files Browse the repository at this point in the history
  • Loading branch information
PrincessRTFM committed Oct 17, 2023
1 parent d132fa3 commit 136af1e
Show file tree
Hide file tree
Showing 15 changed files with 204 additions and 89 deletions.
35 changes: 23 additions & 12 deletions WoLua/Constants/StatusText.cs
Original file line number Diff line number Diff line change
@@ -1,36 +1,47 @@
namespace PrincessRTFM.WoLua.Constants;

using System.Collections.Generic;
using System.Linq;

using Dalamud.Game.Text;
using Dalamud.Game.Text.SeStringHandling;

using PrincessRTFM.WoLua.Lua;

public static class StatusText {
public static string IconPlugin { get; } = SeIconChar.CrossWorld.ToIconString();
public static string IconScripts { get; } = SeIconChar.CrossWorld.ToIconString();
public static string IconInitialising { get; } = SeIconChar.Experience.ToIconString();
public static string IconLoadingScripts { get; } = SeIconChar.Clock.ToIconString();
public static string IconErrored { get; } = SeIconChar.Cross.ToIconString();
public static string IconDisposing { get; } = SeIconChar.ExperienceFilled.ToIconString();

public static SeString Initialising { get; } = $"{IconPlugin} {IconInitialising}";
public static SeString LoadingScripts { get; } = $"{IconPlugin} {IconLoadingScripts}";
public static SeString Initialising { get; } = $"{IconScripts} {IconInitialising}";
public static SeString LoadingScripts { get; } = $"{IconScripts} {IconLoadingScripts}";
public static SeString Scripts {
get {
IEnumerable<ScriptContainer> scripts = Service.Scripts.Values;
int total = Service.Scripts.Count;
int loaded = scripts.Where(c => c.Active).Count();
int loaded = Service.Scripts.Values.Where(c => c.Active).Count();
int failed = total - loaded;
#if DEBUG
return $"{IconPlugin}{loaded}/{total} {IconErrored}{failed}";
return $"{IconScripts}{loaded}/{total} {IconErrored}{failed}";
#else
return loaded == total
? $"{IconPlugin}{loaded}"
: $"{IconPlugin}{loaded}/{total} {IconErrored}{failed}";
? $"{IconScripts}{loaded}"
: $"{IconScripts}{loaded}/{total} {IconErrored}{failed}";
#endif
}
}
public static SeString Disposing { get; } = $"{IconPlugin} {IconDisposing}";
public static SeString Disposing { get; } = $"{IconScripts} {IconDisposing}";

public static SeString TooltipInitialising { get; } = $"{Plugin.Name} initialising, please wait...";
public static SeString TooltipLoadingScripts { get; } = "Loading scripts...";
public static SeString TooltipLoaded {
get {
int totalCount = Service.Scripts.Count;
string totalNoun = totalCount == 1 ? "script" : "scripts";
int loadedCount = Service.Scripts.Values.Where(c => c.Active).Count();
string loadedNoun = loadedCount == 1 ? "script" : "scripts";
int failedCount = totalCount - loadedCount;
string failedNoun = failedCount == 1 ? "script" : "scripts";
return $"{totalCount} {totalNoun} found.\n{loadedCount} {loadedNoun} loaded successfully.\n{failedCount} {failedNoun} failed to load.\nClick to reload all scripts.";
}
}
public static SeString TooltipDisposing { get; } = "Shutting down...";
}
4 changes: 4 additions & 0 deletions WoLua/Lua/Api/ApiBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ public abstract class ApiBase: IDisposable {

public bool Disposed { get; protected set; } = false;

protected internal virtual void PreInit() { }
protected internal virtual void Init() { }
protected internal virtual void PostInit() { }

[MoonSharpHidden]
public ScriptContainer Owner { get; private set; }

Expand Down
3 changes: 3 additions & 0 deletions WoLua/Lua/Api/Game/EntityWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ namespace PrincessRTFM.WoLua.Lua.Api.Game;

[MoonSharpUserData]
[MoonSharpHideMember(nameof(Entity))]
[MoonSharpHideMember(nameof(Equals))]
[MoonSharpHideMember("<Clone>$")]
[MoonSharpHideMember(nameof(Deconstruct))]
public sealed record class EntityWrapper(GameObject? Entity): IEquatable<EntityWrapper> {
#region Conversions
private unsafe NativeGameObject* go => this ? (NativeGameObject*)this.Entity!.Address : null;
Expand Down
3 changes: 3 additions & 0 deletions WoLua/Lua/Api/Game/JobData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ namespace PrincessRTFM.WoLua.Lua.Api.Game;
using PrincessRTFM.WoLua.Constants;

[MoonSharpUserData]
[MoonSharpHideMember(nameof(Equals))]
[MoonSharpHideMember("<Clone>$")]
[MoonSharpHideMember(nameof(Deconstruct))]
public sealed record class JobData(uint Id, string? Name, string? Abbreviation): IEquatable<JobData> {
public const string
InvalidJobName = "adventurer",
Expand Down
2 changes: 2 additions & 0 deletions WoLua/Lua/Api/Game/MountData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ namespace PrincessRTFM.WoLua.Lua.Api.Game;
using PrincessRTFM.WoLua.Constants;

[MoonSharpUserData]
[MoonSharpHideMember("<Clone>$")]
[MoonSharpHideMember(nameof(Equals))]
public sealed record class MountData: IEquatable<MountData> {
public bool Active { get; }
public ushort Id { get; }
Expand Down
11 changes: 5 additions & 6 deletions WoLua/Lua/Api/Game/PlayerApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -259,8 +259,7 @@ public EntityWrapper MouseOverTarget {
private static bool emotesLoaded = false;
private static readonly Dictionary<string, uint> emoteUnlocks = new();

[MoonSharpHidden]
public static void InitialiseEmotes() {
internal static void initialiseEmotes() {
if (emotesLoaded)
return;
emotesLoaded = true;
Expand Down Expand Up @@ -297,13 +296,13 @@ public static void InitialiseEmotes() {

}

public unsafe bool? HasEmote(string name) {
public unsafe bool? HasEmote(string emote) {
if (!this.Loaded)
return null;

string emote = name.StartsWith('/') ? name[1..] : name;
this.Log($"Checking whether '{emote}' is unlocked", LogTag.Emotes);
if (!emoteUnlocks.TryGetValue(emote, out uint unlockLink)) {
string internalName = emote.TrimStart('/');
this.Log($"Checking whether '{internalName}' is unlocked", LogTag.Emotes);
if (!emoteUnlocks.TryGetValue(internalName, out uint unlockLink)) {
this.Log("Can't find unlock link in cached map", LogTag.Emotes);
return null;
}
Expand Down
2 changes: 2 additions & 0 deletions WoLua/Lua/Api/GameApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ internal GameApi(ScriptContainer source) : base(source) { }
public void PrintMessage(params DynValue[] messages) {
if (this.Disposed)
return;
if (messages.Length == 0)
return;

string message = string.Join(
" ",
Expand Down
40 changes: 23 additions & 17 deletions WoLua/Lua/Api/ScriptApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ protected override void Dispose(bool disposing) {
this.Storage = null!;
}

protected internal override void PreInit() {
this.ReloadStorage();
this.Owner.Engine.Options.DebugPrint = this.Debug.PrintString;
this.Owner.Engine.Options.DebugInput = this.Debug.Input;
}

#endregion

#region Sub-API access
Expand Down Expand Up @@ -113,14 +119,14 @@ public bool SaveStorage() {
}
}

public void SetStorage(Table update) {
public void SetStorage(Table replacement) {
if (this.Disposed)
return;

this.Log("Replacing script storage", LogTag.ScriptStorage);
Table store = new(this.Owner.Engine);
this.Owner.cleanTable(update);
foreach (TablePair item in update.Pairs) {
this.Owner.cleanTable(replacement);
foreach (TablePair item in replacement.Pairs) {
store[item.Key] = item.Value;
}
this.Storage = store;
Expand All @@ -130,7 +136,7 @@ public void SetStorage(Table update) {

#region Common strings

public static string PluginCommand => Service.Plugin.Command;
public static string PluginCommand => Plugin.Command;

public string Name => this.Owner.InternalName;

Expand All @@ -144,11 +150,9 @@ public void SetStorage(Table update) {

public int QueueSize => this.Owner.ActionQueue.Count;

public void ClearQueue()
=> this.Owner.ActionQueue.clear();
public void ClearQueue() => this.Owner.ActionQueue.clear();

public void QueueDelay(uint ms)
=> this.Owner.ActionQueue.add(new PauseAction(ms));
public void QueueDelay(uint milliseconds) => this.Owner.ActionQueue.add(new PauseAction(milliseconds));

public void QueueAction(Closure func, params DynValue[] arguments)
=> this.Owner.ActionQueue.add(new CallbackAction(DynValue.NewClosure(func), arguments));
Expand All @@ -169,26 +173,27 @@ public static string Clipboard {

#region JSON

public DynValue ParseJson(string content) {
this.Log(content, LogTag.JsonParse);
public Table? ParseJson(string jsonObject) {
this.Log(jsonObject, LogTag.JsonParse);
try {
Table table = JsonTableConverter.JsonToTable(content, this.Owner.Engine);
Table table = JsonTableConverter.JsonToTable(jsonObject, this.Owner.Engine);
this.Owner.cleanTable(table);
return DynValue.NewTable(table);
return table;
}
catch (SyntaxErrorException e) {
this.Log(e.ToString(), LogTag.JsonParse);
return DynValue.Nil;
return null;
}
}

public string SerialiseJson(Table content) {
this.Owner.cleanTable(content);
string json = JsonTableConverter.TableToJson(content);
this.Log(json, LogTag.JsonDump);
return json;
}
public string SerializeJson(Table content) // american spelling
=> this.SerialiseJson(content);

public string SerializeJson(Table content) => this.SerialiseJson(content); // american spelling

#endregion

Expand All @@ -207,7 +212,7 @@ private void showNotification(string content, NotificationType type, double dura
initialDuration += 10 * content.Count(char.IsPunctuation);
uint duration = (uint)Math.Abs(Math.Ceiling(initialDuration * durationModifier));
this.Log($"Displaying notification (type {type}) of {content.Length:N} chars for {duration:N}ms ({initialDuration:D}ms x {durationModifier:F2})", LogTag.DebugMessage);
Service.Interface.UiBuilder.AddNotification(content, $"{Service.Plugin.Name}: {this.Title}", type, duration);
Service.Interface.UiBuilder.AddNotification(content, $"{Plugin.Name}: {this.Title}", type, duration);
}
public void NotifyDebug(string content) {
if (this.Debug.Enabled)
Expand All @@ -225,11 +230,12 @@ public void NotifyDebug(string content) {
[MoonSharpUserDataMetamethod(Metamethod.Stringify)]
public override string ToString() => $"Script[{this.Owner.PrettyName}]";

[MoonSharpHidden]
[MoonSharpUserDataMetamethod(Metamethod.FunctionCall)]
[SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Lua __call invocations pass target object as first parameter")]
public void RegisterCallbackFunction(DynValue self, DynValue func) {
if (this.Owner.SetCallback(func)) {
this.Log($"Registered on-execute function [{ApiBase.ToUsefulString(func, true)}]", LogTag.CallbackRegistration);
this.Log($"Registered on-execute function [{ToUsefulString(func, true)}]", LogTag.CallbackRegistration);
}
else {
string descriptor = func.Type.ToString() + (func.Type is DataType.UserData ? ("(" + (func.UserData.Object is null ? "static unknown" : func.UserData.Object.GetType().FullName) + ")") : "");
Expand Down
11 changes: 11 additions & 0 deletions WoLua/Lua/LuaGlobalAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace PrincessRTFM.WoLua.Lua;

using System;

[AttributeUsage(AttributeTargets.Property)]
internal class LuaGlobalAttribute: Attribute {
public readonly string Name;
public LuaGlobalAttribute(string name) {
this.Name = name;
}
}
48 changes: 34 additions & 14 deletions WoLua/Lua/ScriptContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace PrincessRTFM.WoLua.Lua;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;

using MoonSharp.Interpreter;
Expand Down Expand Up @@ -34,13 +35,14 @@ public sealed partial class ScriptContainer: IDisposable {
public const string FatalErrorMessage = "The lua engine has encountered a fatal error. Please send your dalamud.log file to the developer and restart your game.";

#region Path normalisation

private static string aggregator(string accumulated, Regex pattern) => pattern.Replace(accumulated, string.Empty);

[GeneratedRegex(@"\s+", RegexOptions.Compiled)]
public static partial Regex AllWhitespace();

public static readonly Regex PluginNamePrefix = new("^" + Regex.Escape($"{Service.Plugin.Name}."), RegexOptions.IgnoreCase | RegexOptions.Compiled);
public static readonly Regex PluginNameSuffix = new(Regex.Escape($".{Service.Plugin.Name}") + "$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
public static readonly Regex PluginNamePrefix = new("^" + Regex.Escape($"{Plugin.Name}."), RegexOptions.IgnoreCase | RegexOptions.Compiled);
public static readonly Regex PluginNameSuffix = new(Regex.Escape($".{Plugin.Name}") + "$", RegexOptions.IgnoreCase | RegexOptions.Compiled);

internal static readonly Regex[] standardRemovals = new Regex[] {
AllWhitespace(),
Expand All @@ -56,12 +58,15 @@ public static string NameToSlug(in string name, in bool forceNormalisation = fal
regexen = regexen.Concat(experimentalRemovals);
return regexen.Aggregate(name, aggregator);
}

#endregion

public string InternalName { get; }
public string PrettyName { get; }
public string SourcePath { get; }

#region Direct invocation command

public bool CommandRegistered { get; private set; } = false;
private void redirectCommandInvocation(string command, string argline) => Service.Plugin.Invoke(this.InternalName, argline);
public bool RegisterCommand() {
Expand All @@ -72,7 +77,7 @@ public bool RegisterCommand() {

string shortform = $"/{Service.Configuration.DirectInvocationCommandPrefix}{this.InternalName}".ToLower();
this.CommandRegistered = Service.CommandManager.AddHandler(shortform, new(this.redirectCommandInvocation) {
HelpMessage = $"Run the {this.InternalName} script from {Service.Plugin.Name}",
HelpMessage = $"Run the {this.InternalName} script from {Plugin.Name}",
ShowInHelp = false,
});
if (this.CommandRegistered)
Expand All @@ -87,12 +92,16 @@ public void UnregisterCommand() {
this.CommandRegistered = false;
}

#endregion

public Script Engine { get; private set; } = new(ScriptModules);

public ActionQueue ActionQueue { get; private set; }

public ScriptApi ScriptApi { get; private set; }
public GameApi GameApi { get; private set; }
[LuaGlobal("Script")]
public ScriptApi ScriptApi { get; private set; } = null!;
[LuaGlobal("Game")]
public GameApi GameApi { get; private set; } = null!;

public string SourceDir => Path.GetDirectoryName(this.SourcePath)!;
public string SourceFile => Path.GetFileName(this.SourcePath);
Expand All @@ -114,15 +123,26 @@ public ScriptContainer(string file, string name, string slug) {

this.ActionQueue = new(this);

this.ScriptApi = new(this);
this.ScriptApi.ReloadStorage();

this.GameApi = new(this);

this.Engine.Options.DebugPrint = this.ScriptApi.Debug.PrintString;
this.Engine.Options.DebugInput = this.ScriptApi.Debug.Input;
this.Engine.Globals["Script"] = this.ScriptApi;
this.Engine.Globals["Game"] = this.GameApi;
Type apiBase = typeof(ApiBase);
Type self = this.GetType();
PropertyInfo[] scriptGlobals = self
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.PropertyType.IsAssignableTo(apiBase) && !p.PropertyType.IsAbstract && p.GetCustomAttribute<LuaGlobalAttribute>() is not null)
.ToArray();

foreach (PropertyInfo p in scriptGlobals) {
LuaGlobalAttribute g = p.GetCustomAttribute<LuaGlobalAttribute>()!;
ConstructorInfo ci = p.PropertyType.GetConstructor(new Type[] { self })!;
ApiBase o = (ApiBase)ci.Invoke(new object?[] { this });
o.PreInit();
p.SetValue(this, o);
this.Engine.Globals[g.Name] = o;
o.Init();
}
foreach (PropertyInfo p in scriptGlobals) {
ApiBase o = (ApiBase)p.GetValue(this)!;
o.PostInit();
}

try {
this.Engine.DoFile(this.SourceFile);
Expand Down
Loading

0 comments on commit 136af1e

Please sign in to comment.