#if USE_ARCWEAVE using System; using System.Collections.Generic; using UnityEngine; using Language.Lua; namespace PixelCrushers.DialogueSystem.ArcweaveSupport { /// /// Implements Arcscript built-in functions for the Dialogue System's Lua environment. /// Notes: /// - Uses LuaInterpreter. /// - Does not implement reset() or resetAll(). /// [AddComponentMenu("")] // Use wrapper. public class ArcweaveLua : Saver { [Tooltip("Typically leave unticked so temporary Dialogue Managers don't unregister your functions.")] public bool unregisterOnDisable = false; [Tooltip("Support multiplayer Lua functions. Currently: visits() incorporates Variable['ActorIndex'].")] public bool multiplayer = false; #region Unity Entrypoints public override void OnEnable() { base.OnEnable(); Lua.RegisterFunction(nameof(abs), null, SymbolExtensions.GetMethodInfo(() => abs(0))); Lua.RegisterFunction(nameof(sqr), null, SymbolExtensions.GetMethodInfo(() => sqr(0))); Lua.RegisterFunction(nameof(sqrt), null, SymbolExtensions.GetMethodInfo(() => sqrt(0))); Lua.RegisterFunction(nameof(random), null, SymbolExtensions.GetMethodInfo(() => random())); Lua.RegisterFunction(nameof(visits), this, SymbolExtensions.GetMethodInfo(() => visits(string.Empty))); Lua.environment.Register(nameof(roll), roll); Lua.environment.Register(nameof(show), show); } public override void OnDisable() { base.OnDisable(); if (unregisterOnDisable) { Lua.UnregisterFunction(nameof(abs)); Lua.UnregisterFunction(nameof(sqr)); Lua.UnregisterFunction(nameof(sqrt)); Lua.UnregisterFunction(nameof(random)); Lua.UnregisterFunction(nameof(roll)); Lua.UnregisterFunction(nameof(show)); } } #endregion #region Arcweave Functions public static double abs(double n) { return Mathf.Abs((float)n); } public static double sqr(double n) { return (n * n); } public static double sqrt(double n) { return Mathf.Sqrt((float)n); } public static double random() { return UnityEngine.Random.value; // Note: Returns 1 inclusive, but Arcscript random() is 1 exclusive. } public static LuaValue roll(LuaValue[] values) { int m = (int)(values[0] as LuaNumber).Number; int n = (values.Length > 1 && values[1] is LuaNumber) ? (int)(values[1] as LuaNumber).Number : 1; double result = 0; for (int i = 0; i < (int)n; i++) { result += UnityEngine.Random.Range(1, (int)m + 1); } return new LuaNumber(result); } public static LuaValue show(LuaValue[] values) { var s = string.Empty; foreach (var value in values) { s += value.ToString(); } return new LuaString(s); } #endregion #region visits() [Serializable] public class SaveData { public List guids = new List(); public List visits = new List(); public string lastTextGuid; public SaveData() { } public SaveData(Dictionary visitsDict, string lastTextGuid) { foreach (var kvp in visitsDict) { guids.Add(kvp.Key); visits.Add(kvp.Value); } this.lastTextGuid = lastTextGuid; } } [Serializable] public class MultiplayerSaveData { public List actorIndices = new List(); public List saveData = new List(); } protected Dictionary> visitsDicts = new Dictionary>(); protected Dictionary lastTextGuids = new Dictionary(); protected virtual string GetActorIndex() { return multiplayer ? DialogueLua.GetVariable("ActorIndex").asString : "Player"; } protected virtual string GetLastTextGuid(string actorIndex) { if (!lastTextGuids.ContainsKey(actorIndex)) { lastTextGuids.Add(actorIndex, string.Empty); } return lastTextGuids[actorIndex]; } protected virtual Dictionary GetVisitsDict(string actorIndex) { if (!visitsDicts.ContainsKey(actorIndex)) { visitsDicts.Add(actorIndex, new Dictionary()); } return visitsDicts[actorIndex]; } protected virtual void OnConversationLine(Subtitle subtitle) { if (string.IsNullOrEmpty(subtitle.formattedText.text)) return; var lastTextGuid = Field.LookupValue(subtitle.dialogueEntry.fields, "Guid"); if (string.IsNullOrEmpty(lastTextGuid)) return; var actorIndex = GetActorIndex(); lastTextGuids[actorIndex] = lastTextGuid; var visitsDict = GetVisitsDict(actorIndex); if (visitsDict.ContainsKey(lastTextGuid)) { visitsDict[lastTextGuid]++; } else { visitsDict.Add(lastTextGuid, 1); } } public double visits(string id) { int count; var actorIndex = GetActorIndex(); var guid = !string.IsNullOrEmpty(id) ? id : GetLastTextGuid(actorIndex); var visitsDict = GetVisitsDict(actorIndex); return visitsDict.TryGetValue(guid, out count) ? count : 0; } public override string RecordData() { if (!multiplayer) { var actorIndex = GetActorIndex(); var data = new SaveData(GetVisitsDict(actorIndex), GetLastTextGuid(actorIndex)); return SaveSystem.Serialize(data); } else { var multiplayerData = new MultiplayerSaveData(); foreach (var kvp in visitsDicts) { var actorIndex = kvp.Key; var visitsDict = kvp.Value; var data = new SaveData(visitsDict, GetLastTextGuid(actorIndex)); multiplayerData.actorIndices.Add(actorIndex); multiplayerData.saveData.Add(data); } return SaveSystem.Serialize(multiplayerData); } } public override void ApplyData(string s) { if (string.IsNullOrEmpty(s)) return; if (!multiplayer) { var data = SaveSystem.Deserialize(s); if (data == null) return; var actorIndex = GetActorIndex(); var visitsDict = GetVisitsDict(actorIndex); visitsDict.Clear(); for (int i = 0; i < Mathf.Min(data.guids.Count, data.visits.Count); i++) { visitsDict.Add(data.guids[i], data.visits[i]); } lastTextGuids[actorIndex] = data.lastTextGuid; } else { var multiplayerData = SaveSystem.Deserialize(s); if (multiplayerData == null) return; for (int i = 0; i < Mathf.Min(multiplayerData.actorIndices.Count, multiplayerData.saveData.Count); i++) { var actorIndex = multiplayerData.actorIndices[i]; var data = multiplayerData.saveData[i]; var visitsDict = GetVisitsDict(actorIndex); visitsDict.Clear(); for (int j = 0; j < Mathf.Min(data.guids.Count, data.visits.Count); j++) { visitsDict.Add(data.guids[j], data.visits[j]); } lastTextGuids[actorIndex] = data.lastTextGuid; } } } #endregion } } #endif