Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
259 changes: 259 additions & 0 deletions DawnLib/src/API/Terminal/ModifyDisplayText.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
using System.Collections.Generic;
using System.Linq;
using Dawn.Internal;
using Dawn.Utils;

namespace Dawn;
public class ModifyDisplayText
{
private static List<ModifyDisplayText> DawnDisplayTextInserts = [];

public string Word = string.Empty;
public string TextToLookFor = string.Empty;
private string _textActuallyAdded = string.Empty;
internal TerminalNode ResultNode = null!;
public TerminalNode OriginalNode { get; private set; }
public IProvider<string> AddedText;

public Style ModifyStyle = Style.InsertLast;

/// <summary>This determines your text modification style. (see remarks for more information)</summary>
/// <remarks>
/// InsertAll - This will INSERT your AddedText at all locations that match your TextToLookFor property.
/// InsertFirst - This will INSERT your AddedText at the FIRST location that matches your TextToLookFor property.
/// InsertLast - This will INSERT your AddedText at the LAST location that matches your TextToLookFor property.
/// ReplaceAll - This will REPLACE all matching instances of your TextToLookFor property with your AddedText property.
/// ReplaceFirst - This will REPLACE the FIRST matching instance of your TextToLookFor property with your AddedText property.
/// ReplaceAll - This will REPLACE the LAST matching instance of your TextToLookFor property with your AddedText property.
/// </remarks>
public enum Style
{
InsertAll,
InsertFirst,
InsertLast,
ReplaceAll,
ReplaceFirst,
ReplaceLast,
}

/// <summary>Primary constructor for ModifyDisplayText. Takes a given keyword and modifies the resulting node's displaytext</summary>
/// <param name="keyword">This is the keyword a user enters to display the TerminalNode</param>
/// <param name="textToAdd">This is the text you plan to add to the resulting TerminalNode. Can be any type of IProvider<string></param>
/// <param name="textToLookFor">(Optional) This is the text you are wishing to insert after OR replace, depending on the next parameter</param>
/// <param name="replaceStyle">(Optional) This determines your modification style. Options are defined under ModifyDisplayText.Style</param>
/// <remarks>Text modification is done one time at Terminal Start. This does not replace or add to the Terminal.TextPostProcess method</remarks>
public ModifyDisplayText(string keyword, IProvider<string> textToAdd, string textToLookFor = "", Style replaceStyle = Style.InsertLast)
{
Word = keyword;
AddedText = textToAdd;
TextToLookFor = textToLookFor;
ModifyStyle = replaceStyle;

DawnDisplayTextInserts.Add(this);
}

/// <summary>Secondary constructor for ModifyDisplayText. Takes a given TerminalNode and modifies the resulting node's displaytext</summary>
/// <param name="terminalNode">This is the TerminalNode you wish to modify.</param>
/// <param name="textToAdd">This is the text you plan to add to the resulting TerminalNode. Can be any type of IProvider<string></param>
/// <param name="textToLookFor">(Optional) This is the text you are wishing to insert after OR replace, depending on the next parameter</param>
/// <param name="replaceStyle">(Optional) This determines your modification style. Options are defined under ModifyDisplayText.Style</param>
/// <remarks>
/// Text modification is done one time at Terminal Start. This does not replace or add to the Terminal.TextPostProcess method.
/// When utilizing this secondary constructor, if the TerminalNode is deleted and then re-created your text modifications will not take place.
/// You may utilize ManualResultNode(TerminalNode terminalNode) to manually update your resulting terminal node if you do not wish to use the primary constructor.
/// </remarks>
public ModifyDisplayText(TerminalNode terminalNode, IProvider<string> textToAdd, string textToLookFor = "", Style replaceStyle = Style.InsertLast)
{
ResultNode = terminalNode;
Word = string.Empty;
AddedText = textToAdd;
TextToLookFor = textToLookFor;
ModifyStyle = replaceStyle;

DawnDisplayTextInserts.Add(this);
}

/// <summary>This allows you to disable or re-enable your text modification</summary>
/// <remarks>
/// If the text has already been modified this will not remove your modifications at runtime.
/// This simply removes your text modification from the list of modifications to run at Terminal Start.
/// </remarks>
public void ToggleTextInsert(bool value)
{
if (value)
{
if (!DawnDisplayTextInserts.Contains(this))
DawnDisplayTextInserts.Add(this);
}
else
{
DawnDisplayTextInserts.Remove(this);
}
}

/// <summary>This allows you to manually set your Result TerminalNode</summary>
/// <remarks>
/// Setting this manually to a non-null result will disable keyword to result node matching.
/// NOTE: Changing this after Terminal Start has no affect on the result node.
/// </remarks>
public void ManualResultNode(TerminalNode terminalNode)
{
ResultNode = terminalNode;
}

/// <summary>This allows you to manually remove your added text during runtime</summary>
/// <remarks>
/// Running this method is not necessary unless there is a desire to remove the modifications before lobby reset.
/// Text modifications are automatically removed at lobby reset by default.
/// </remarks>
public void RemoveAddedTextNow()
{
ResetNodeText();
}

/// <summary>This allows you to manually refresh your added text during runtime</summary>
/// <remarks>
/// Running this method is not necessary unless there is a desire to refresh the text modifications before lobby reset.
/// Text modifications are automatically removed at lobby reset by default and refreshed at lobby load.
/// </remarks>
public void RefreshAddedTextNow()
{
ResetNodeText();
AddText();
}

internal static void AddAllTextInserts()
{
//remove any duplicates from list
DawnDisplayTextInserts = [.. DawnDisplayTextInserts.Distinct()];

foreach(ModifyDisplayText insert in DawnDisplayTextInserts)
{
insert.AddText();
}
}

//reset terminal nodes to original status
internal static void RemoveAllTextInserts()
{
foreach (ModifyDisplayText insert in DawnDisplayTextInserts)
{
insert.ResetNodeText();
}
}

private void AddText()
{
if (ResultNode == null)
{
if (!TryGetResultNode(out ResultNode))
return;
}

if (CheckForChanges())
return;

_textActuallyAdded = AddedText.Provide();

if (string.IsNullOrWhiteSpace(TextToLookFor))
{
//make sure we're at least adding the new line if someone forgot it
if (!_textActuallyAdded.EndsWith('\n'))
_textActuallyAdded += "\n";

DawnPlugin.Logger.LogMessage($"Appending text to end of {ResultNode.name} - {_textActuallyAdded}");
ResultNode.displayText += AddedText;
}
else
{
if (ResultNode.displayText.Contains(TextToLookFor))
{
//insert text based on style defined
InsertTextWithStyle();
}
else
{
//result displayText does not contain our expected text
DawnPlugin.Logger.LogWarning($"Unable to insert text after {TextToLookFor} for {ResultNode.name}, provided TextToLookFor does not exist!");
}

}
}

private void InsertTextWithStyle()
{
switch (ModifyStyle)
{
case Style.InsertAll:
ResultNode.displayText = ResultNode.displayText.Replace(TextToLookFor, TextToLookFor + _textActuallyAdded);
DawnPlugin.Logger.LogMessage($"{ResultNode.name} has successfully replaced all instances of {TextToLookFor} with [{TextToLookFor + _textActuallyAdded}]");
break;

case Style.InsertFirst:
ResultNode.displayText = ResultNode.displayText.ReplaceAtFirstIndexOf(TextToLookFor, TextToLookFor + _textActuallyAdded);
DawnPlugin.Logger.LogMessage($"{ResultNode.name} has successfully replaced the FIRST instance of {TextToLookFor} with [{TextToLookFor + _textActuallyAdded}]");
break;

case Style.InsertLast:
ResultNode.displayText = ResultNode.displayText.ReplaceAtLastIndexOf(TextToLookFor, TextToLookFor + _textActuallyAdded);
DawnPlugin.Logger.LogMessage($"{ResultNode.name} has successfully replaced the LAST instance of {TextToLookFor} with [{TextToLookFor + _textActuallyAdded}]");
break;

case Style.ReplaceAll:
ResultNode.displayText = ResultNode.displayText.Replace(TextToLookFor, _textActuallyAdded);
DawnPlugin.Logger.LogMessage($"{ResultNode.name} has successfully replaced all instances of {TextToLookFor} with [{_textActuallyAdded}]");
break;

case Style.ReplaceFirst:
ResultNode.displayText = ResultNode.displayText.ReplaceAtFirstIndexOf(TextToLookFor, _textActuallyAdded);
DawnPlugin.Logger.LogMessage($"{ResultNode.name} has successfully replaced the FIRST instance of {TextToLookFor} with [{TextToLookFor + _textActuallyAdded}]");
break;

case Style.ReplaceLast:
ResultNode.displayText = ResultNode.displayText.ReplaceAtLastIndexOf(TextToLookFor, _textActuallyAdded);
DawnPlugin.Logger.LogMessage($"{ResultNode.name} has successfully replaced the LAST instance of {TextToLookFor} with [{TextToLookFor + _textActuallyAdded}]");
break;
}
}

private void ResetNodeText()
{
// result doesn't exist anymore, no need to reset anything
// OR no text has been added
if (ResultNode == null || string.IsNullOrEmpty(_textActuallyAdded))
return;

DawnPlugin.Logger.LogMessage($"Removing inserted text [{_textActuallyAdded}] from node - {ResultNode.name}");
ResultNode.displayText = ResultNode.displayText.Replace(_textActuallyAdded, string.Empty);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn't this just not work if it's a Replace style? it'll run but it won't properly bring the result node back to how it original was

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah you're right. Replace style was added after I realized there'd be a use case for completely replacing text and this is def an oversight of mine.

Probably need to cache any text that's removed as well as the style that was used at modification and change this to a switch based on the cached style.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if that sounds like a headache to you I can go about fixing it before you get deep into this stuff

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

go for it, im going to head to class soon anyway so take your time

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prob won't get to it any time soon but yeah I don't think this PR needs to be rushed at all. Marking the PR as draft to not confuse ourselves

}

private bool CheckForChanges()
{
if (string.IsNullOrWhiteSpace(_textActuallyAdded))
return false;

return ResultNode.displayText.Contains(_textActuallyAdded);
}

private bool TryGetResultNode(out TerminalNode result)
{
result = null!;
if (TerminalRefs.Instance.TryGetKeyword(Word, out TerminalKeyword terminalKeyword))
{
if (terminalKeyword.specialKeywordResult == null)
{
CompatibleNoun compatibleNoun = terminalKeyword.defaultVerb.compatibleNouns.FirstOrDefault(k => k.noun == terminalKeyword);
if (compatibleNoun == null)
return false;

result = compatibleNoun.result;
}
else
{
result = terminalKeyword.specialKeywordResult;
}
}

return result != null;
}
}
25 changes: 23 additions & 2 deletions DawnLib/src/DawnTesting.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@ internal static void TestCommands()
builder.SetClearTextFlags(TerminalCommandRegistration.ClearText.Result | TerminalCommandRegistration.ClearText.Query);
});

ModifyDisplayText versionAdd = new("help", new SimpleProvider<string>("\n\n>VERSION\nDisplay Dawnlib's current version"), "record.", ModifyDisplayText.Style.InsertFirst);

UnityEvent test = new();
DawnLib.DefineTerminalCommand(NamespacedKey<DawnTerminalCommandInfo>.From("dawn_lib", "lights_command"), "DawnLibLights", builder =>
DawnTerminalCommandInfo lightsCommand = DawnLib.DefineTerminalCommand(NamespacedKey<DawnTerminalCommandInfo>.From("dawn_lib", "lights_command"), "DawnLibLights", builder =>
{
builder.SetEnabled(new SimpleProvider<bool>(true));
builder.SetMainText(BasicLightsCommand);
Expand All @@ -37,6 +39,8 @@ internal static void TestCommands()
test.Invoke();
};

ModifyDisplayText lightsAdd = new("other", new FuncProvider<string>(() => $"\n\n>{ListToString(LightsKeywords(), ", ").ToUpperInvariant()}\nToggle ship interior lights"), "planet.");

DawnLib.DefineTerminalCommand(NamespacedKey<DawnTerminalCommandInfo>.From("dawn_lib", "test_input_command"), "DawnLibInputs", builder =>
{
builder.SetEnabled(new SimpleProvider<bool>(true));
Expand All @@ -47,6 +51,8 @@ internal static void TestCommands()
builder.SetDescription("Takes the player's input and uses it on the next screen.");
});

ModifyDisplayText inputCommand = new("store", new SimpleProvider<string>($"\nThis is a hint to input\n\n"));

DawnLib.DefineTerminalCommand(NamespacedKey<DawnTerminalCommandInfo>.From("dawn_lib", "test_query_command"), "DawnLibQuery", builder =>
{
builder.SetEnabled(new SimpleProvider<bool>(true));
Expand All @@ -63,6 +69,21 @@ internal static void TestCommands()
queryCommandBuilder.SetCancelWord("no");
});
});

ModifyDisplayText ReplaceAllTest = new("help", new SimpleProvider<string>("///"), ">", ModifyDisplayText.Style.ReplaceAll);
ModifyDisplayText ReplaceLastTest = new("help", new SimpleProvider<string>("da"), "the", ModifyDisplayText.Style.ReplaceLast);
}

private static string ListToString(List<string> list, string separator)
{
string result = string.Empty;

foreach(string item in list)
{
result += item + separator;
}

return result.RemoveEnd(separator);
}

private static string BasicLightsCommand()
Expand Down Expand Up @@ -99,6 +120,6 @@ private static bool ShouldAddVersion()

private static List<string> LightsKeywords()
{
return ["lights", "dark", "vow", "help"];
return ["lights", "dark"];
}
}
6 changes: 6 additions & 0 deletions DawnLib/src/Internal/Patches/TerminalPatches.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,18 @@ private static void TerminalDisableHook(On.Terminal.orig_OnDisable orig, Termina

//still need to run the method
orig(self);

//Remove all InsertToDisplayText changes and return nodes to original values
ModifyDisplayText.RemoveAllTextInserts();
}

private static void TerminalStartHook(On.Terminal.orig_Start orig, Terminal self)
{
orig(self);

//Run all InsertToDisplayText changes
ModifyDisplayText.AddAllTextInserts();

//assign priorities to any remaining keywords that have not received a value yet
//also assign descriptions/category if unassigned
//doing this in start to give time after Terminal.Awake where commands are created
Expand Down
26 changes: 26 additions & 0 deletions DawnLib/src/Utils/Extensions/StringExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,32 @@ public static string RemoveEnd(this string input, string end)
return input;
}

public static string ReplaceAtFirstIndexOf(this string value, string expectedText, string replacement)
{
int index = value.IndexOf(expectedText);
if(index < 0)
{
DawnPlugin.Logger.LogWarning($"InsertAtFirstIndexOf: Unable to find expected text - {expectedText} in string - {value}. Text is unchanged");
return value;
}

return value.Remove(index, expectedText.Length).Insert(index, replacement);

}

public static string ReplaceAtLastIndexOf(this string value, string expectedText, string replacement)
{
int index = value.LastIndexOf(expectedText);
if (index < 0)
{
DawnPlugin.Logger.LogWarning($"InsertAtLastIndexOf: Unable to find expected text - {expectedText} in string - {value}. Text is unchanged");
return value;
}

return value.Remove(index, expectedText.Length).Insert(index, replacement);

}

public static string StripSpecialCharacters(this string input)
{
string returnString = string.Empty;
Expand Down
1 change: 0 additions & 1 deletion DawnLib/src/Utils/Extensions/TerminalExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ public static bool TryGetKeyword(this Terminal terminal, string keyWord, out Ter
{
if (keyWord.CompareStringsInvariant(keyword.word))
{
//Loggers.LogDebug($"Keyword: [{keyWord}] found!");
terminalKeyword = keyword;
return true;
}
Expand Down