Refactored a bunch of things
Added Notes Module + Data Structure Added Config Module + Data Structure Added Role Buttons Module + Data Structure
This commit is contained in:
parent
aab1fad4e2
commit
7f08d72ef8
23 changed files with 638 additions and 83 deletions
31
SMSModLogOutputAnalyzer/Data/Config.cs
Normal file
31
SMSModLogOutputAnalyzer/Data/Config.cs
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
using Discord.Interactions;
|
||||||
|
using Discord;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using Orpticon.Wrappers;
|
||||||
|
using SMSModLogOutputAnalyzer.Modules;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Data
|
||||||
|
{
|
||||||
|
public partial class Config
|
||||||
|
{
|
||||||
|
public static ITextChannel NotesLogChannel { get => (ITextChannel)Program.Client.GetChannel(Instance.notesLogChannel); set => Instance.notesLogChannel = value.Id; }
|
||||||
|
[XmlAttribute] public ulong notesLogChannel { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static void Load()
|
||||||
|
{
|
||||||
|
Instance = SerializerXML.DeserializeFromFileOrDefault<Config>("Config.xml");
|
||||||
|
}
|
||||||
|
public static void Save()
|
||||||
|
{
|
||||||
|
SerializerXML.SerializeToFile(Instance, "Config.xml");
|
||||||
|
}
|
||||||
|
public static Config Instance { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
24
SMSModLogOutputAnalyzer/Data/NotesDataObject.Note.cs
Normal file
24
SMSModLogOutputAnalyzer/Data/NotesDataObject.Note.cs
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
using Discord;
|
||||||
|
using System.Reactive;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using static SMSModLogOutputAnalyzer.Data.NotesDataObject;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Data
|
||||||
|
{
|
||||||
|
public partial class NotesDataObject
|
||||||
|
{
|
||||||
|
public class Note
|
||||||
|
{
|
||||||
|
[XmlAttribute] public string Text { get; set; }
|
||||||
|
[XmlAttribute] public ulong CreatorID { get; set; }
|
||||||
|
[XmlAttribute] public DateTime CreationTime { get; set; }
|
||||||
|
[XmlAttribute] public int Id { get; set; }
|
||||||
|
public EmbedFieldBuilder ToField()
|
||||||
|
{
|
||||||
|
var unix = ((DateTimeOffset)CreationTime).ToUnixTimeSeconds();
|
||||||
|
// "Note " + Id, "`" + Text + "`\nCreated by <@" + CreatorID + "> at <t:" + unix + ":f>"
|
||||||
|
return new EmbedFieldBuilder().WithName(Text).WithValue("ID: `" + Id + "`\nCreated by <@" + CreatorID + "> at <t:" + unix + ":f>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
SMSModLogOutputAnalyzer/Data/NotesDataObject.UserNotes.cs
Normal file
14
SMSModLogOutputAnalyzer/Data/NotesDataObject.UserNotes.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Data
|
||||||
|
{
|
||||||
|
public partial class NotesDataObject
|
||||||
|
{
|
||||||
|
public class UserNotes
|
||||||
|
{
|
||||||
|
[XmlAttribute] public ulong Id { get; set; }
|
||||||
|
[XmlAttribute] public int Counter { get; set; } = 0;
|
||||||
|
[XmlElement("Note")] public List<Note> Notes { get; set; } = new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
42
SMSModLogOutputAnalyzer/Data/NotesDataObject.cs
Normal file
42
SMSModLogOutputAnalyzer/Data/NotesDataObject.cs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
using Discord;
|
||||||
|
using Orpticon.Custom;
|
||||||
|
using Orpticon.Wrappers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Data
|
||||||
|
{
|
||||||
|
public partial class NotesDataObject
|
||||||
|
{
|
||||||
|
[XmlElement("Notes")] public List<UserNotes> List { get; set; } = new();
|
||||||
|
[XmlIgnore] public UserNotes this[IUser user] => this[user.Id];
|
||||||
|
[XmlIgnore]
|
||||||
|
public UserNotes this[ulong id]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var notes = List.Find(x => x.Id == id);
|
||||||
|
if(notes == null)
|
||||||
|
{
|
||||||
|
notes = new() { Id = id };
|
||||||
|
List.Add(notes);
|
||||||
|
}
|
||||||
|
return notes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
SerializerXML.SerializeToFile(this, "NotesData.xml");
|
||||||
|
}
|
||||||
|
public static NotesDataObject Load()
|
||||||
|
{
|
||||||
|
var obj = SerializerXML.DeserializeFromFileOrDefault<NotesDataObject>("NotesData.xml");
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Data
|
||||||
|
{
|
||||||
|
public partial class RoleButtonsDataObject
|
||||||
|
{
|
||||||
|
public class RoleButton
|
||||||
|
{
|
||||||
|
[XmlAttribute] public int Id { get; set; }
|
||||||
|
[XmlAttribute] public ulong Role { get; set; }
|
||||||
|
[XmlAttribute] public ulong RequiredRole { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
27
SMSModLogOutputAnalyzer/Data/RoleButtonsDataObject.cs
Normal file
27
SMSModLogOutputAnalyzer/Data/RoleButtonsDataObject.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static SMSModLogOutputAnalyzer.Data.NotesDataObject;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using Orpticon.Wrappers;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Data
|
||||||
|
{
|
||||||
|
public partial class RoleButtonsDataObject
|
||||||
|
{
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
SerializerXML.SerializeToFile(this, "RoleButtons.xml");
|
||||||
|
}
|
||||||
|
public static RoleButtonsDataObject Load()
|
||||||
|
{
|
||||||
|
var obj = SerializerXML.DeserializeFromFileOrDefault<RoleButtonsDataObject>("RoleButtons.xml");
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
[XmlElement("Button")] public List<RoleButton> List { get; set; } = new();
|
||||||
|
[XmlAttribute] public int Counter { get; set; }
|
||||||
|
public RoleButton this[int id] => List.Find(x => x.Id == id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
using Discord;
|
||||||
|
using Discord.Interactions;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Modules
|
||||||
|
{
|
||||||
|
public class AskForLogFileModule : InteractionModuleBase
|
||||||
|
{
|
||||||
|
[MessageCommand("Ask for Log file")]
|
||||||
|
public async Task AskForLog(IMessage message)
|
||||||
|
{
|
||||||
|
string title = "Please submit Log File";
|
||||||
|
string descr = "In order to assist you further, we are going to need your `BepInEx/LogOutput.log` file.";
|
||||||
|
if (message.Channel.Id == 1220431757266915400)
|
||||||
|
{
|
||||||
|
title = "Merci d'envoyer le fichier journal";
|
||||||
|
descr = "Afin de t'aider davantage, nous allons avoir besoin de ton fichier `BepInEx/LogOutput.log`.";
|
||||||
|
}
|
||||||
|
if (message.Channel.Id == 1220476339883216977)
|
||||||
|
{
|
||||||
|
title = "Bitte schick uns deine Log-Datei.";
|
||||||
|
descr = "Um dir weiterhelfen zu können, benötigen wir deine `BepInEx/LogOutput.log` Datei.";
|
||||||
|
}
|
||||||
|
if (message.Channel.Id == 1220488093124005909)
|
||||||
|
{
|
||||||
|
title = "Envía el archivo de registro";
|
||||||
|
descr = "Para poder ayudarte mejor, vamos a necesitar tu archivo `BepInEx/LogOutput.log`.";
|
||||||
|
}
|
||||||
|
if (message.Channel.Id == 1221180784598188082)
|
||||||
|
{
|
||||||
|
title = "Prześlij plik dziennika";
|
||||||
|
descr = "Aby pomóc Ci dalej, będziemy potrzebować Twojego pliku `BepInEx/LogOutput.log`.";
|
||||||
|
}
|
||||||
|
if (message.Channel.Id == 1225150931306549330)
|
||||||
|
{
|
||||||
|
title = "Por favor, envia o ficheiro de registo";
|
||||||
|
descr = "Para te podermos ajudar mais, vamos precisar do teu ficheiro `BepInEx/LogOutput.log`.";
|
||||||
|
}
|
||||||
|
var stream = new MemoryStream(Properties.Resources.LogOutput);
|
||||||
|
await RespondWithFileAsync(new FileAttachment(stream, "LogOutput.jpg"), "<@" + message.Author.Id + ">", embed: new EmbedBuilder().WithTitle(title).WithDescription(descr).WithImageUrl("attachment://LogOutput.jpg").WithDefaults().Build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
using Discord;
|
||||||
|
using Discord.Interactions;
|
||||||
|
using SMSModLogOutputAnalyzer.Data;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Modules
|
||||||
|
{
|
||||||
|
public partial class ConfigModule
|
||||||
|
{
|
||||||
|
public partial class Commands
|
||||||
|
{
|
||||||
|
[Group("set", "Setter Commands")]
|
||||||
|
public class Setters : InteractionModuleBase
|
||||||
|
{
|
||||||
|
[SlashCommand("notes_log_channel", "What channel to log note creations into.")]
|
||||||
|
[RequireUserPermission(ChannelPermission.ManageChannels)]
|
||||||
|
public async Task NotesLogChannel(ITextChannel channel)
|
||||||
|
{
|
||||||
|
Config.NotesLogChannel = channel;
|
||||||
|
Config.Save();
|
||||||
|
await RespondAsync(embed: new EmbedBuilder().WithDescription("Config value `NotesLogChannel` set to `" + channel.Id + "`.").WithDefaults().Build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
using Discord.Interactions;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Modules
|
||||||
|
{
|
||||||
|
public partial class ConfigModule
|
||||||
|
{
|
||||||
|
[Group("config", "Config Commands")]
|
||||||
|
public partial class Commands : InteractionModuleBase
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
SMSModLogOutputAnalyzer/Modules/Config/ConfigModule.cs
Normal file
14
SMSModLogOutputAnalyzer/Modules/Config/ConfigModule.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
using Discord.Interactions;
|
||||||
|
using Orpticon.Wrappers;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Modules
|
||||||
|
{
|
||||||
|
public partial class ConfigModule : InteractionModuleBase
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
namespace SMSModLogOutputAnalyzer
|
namespace SMSModLogOutputAnalyzer.Modules
|
||||||
{
|
{
|
||||||
public partial class CommandModule
|
public partial class LogAnalyzeModule
|
||||||
{
|
{
|
||||||
public struct FoundLine
|
public struct FoundLine
|
||||||
{
|
{
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
using Discord.Interactions;
|
using Discord.Interactions;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace SMSModLogOutputAnalyzer
|
namespace SMSModLogOutputAnalyzer.Modules
|
||||||
{
|
{
|
||||||
public partial class CommandModule : InteractionModuleBase
|
public partial class LogAnalyzeModule : InteractionModuleBase
|
||||||
{
|
{
|
||||||
public static List<string> KnownMelonLoaderMods = new List<string>
|
public static List<string> KnownMelonLoaderMods = new List<string>
|
||||||
{
|
{
|
||||||
|
|
@ -35,39 +35,6 @@ namespace SMSModLogOutputAnalyzer
|
||||||
{
|
{
|
||||||
Console.WriteLine("Building module");
|
Console.WriteLine("Building module");
|
||||||
}
|
}
|
||||||
[MessageCommand("Ask for Log file")]
|
|
||||||
public async Task AskForLog(IMessage message)
|
|
||||||
{
|
|
||||||
string title = "Please submit Log File";
|
|
||||||
string descr = "In order to assist you further, we are going to need your `BepInEx/LogOutput.log` file.";
|
|
||||||
if(message.Channel.Id == 1220431757266915400)
|
|
||||||
{
|
|
||||||
title = "Merci d'envoyer le fichier journal";
|
|
||||||
descr = "Afin de t'aider davantage, nous allons avoir besoin de ton fichier `BepInEx/LogOutput.log`.";
|
|
||||||
}
|
|
||||||
if(message.Channel.Id == 1220476339883216977)
|
|
||||||
{
|
|
||||||
title = "Bitte schick uns deine Log-Datei.";
|
|
||||||
descr = "Um dir weiterhelfen zu können, benötigen wir deine `BepInEx/LogOutput.log` Datei.";
|
|
||||||
}
|
|
||||||
if (message.Channel.Id == 1220488093124005909)
|
|
||||||
{
|
|
||||||
title = "Envía el archivo de registro";
|
|
||||||
descr = "Para poder ayudarte mejor, vamos a necesitar tu archivo `BepInEx/LogOutput.log`.";
|
|
||||||
}
|
|
||||||
if (message.Channel.Id == 1221180784598188082)
|
|
||||||
{
|
|
||||||
title = "Prześlij plik dziennika";
|
|
||||||
descr = "Aby pomóc Ci dalej, będziemy potrzebować Twojego pliku `BepInEx/LogOutput.log`.";
|
|
||||||
}
|
|
||||||
if (message.Channel.Id == 1225150931306549330)
|
|
||||||
{
|
|
||||||
title = "Por favor, envia o ficheiro de registo";
|
|
||||||
descr = "Para te podermos ajudar mais, vamos precisar do teu ficheiro `BepInEx/LogOutput.log`.";
|
|
||||||
}
|
|
||||||
var stream = new MemoryStream(Properties.Resources.LogOutput);
|
|
||||||
await RespondWithFileAsync(new FileAttachment(stream, "LogOutput.jpg"), "<@" + message.Author.Id + ">", embed: new EmbedBuilder().WithTitle(title).WithDescription(descr).WithImageUrl("attachment://LogOutput.jpg").Build());
|
|
||||||
}
|
|
||||||
[MessageCommand("Analyze Log")]
|
[MessageCommand("Analyze Log")]
|
||||||
public async Task Analyze(IMessage message)
|
public async Task Analyze(IMessage message)
|
||||||
{
|
{
|
||||||
|
|
@ -76,7 +43,7 @@ namespace SMSModLogOutputAnalyzer
|
||||||
await Upload((Attachment)message.Attachments.First());
|
await Upload((Attachment)message.Attachments.First());
|
||||||
} else
|
} else
|
||||||
{
|
{
|
||||||
await RespondAsync("Message has no attachment.", ephemeral: true);
|
await RespondAsync(embed: new EmbedBuilder().WithDescription("Message has no attachment.").WithDefaults().Build(), ephemeral: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[SlashCommand("upload", "Upload a LogOutput.log file for analysis.")]
|
[SlashCommand("upload", "Upload a LogOutput.log file for analysis.")]
|
||||||
|
|
@ -89,7 +56,7 @@ namespace SMSModLogOutputAnalyzer
|
||||||
var text = await http.GetStringAsync(file.Url);
|
var text = await http.GetStringAsync(file.Url);
|
||||||
if(Program.AnalysisCache.ContainsKey(text))
|
if(Program.AnalysisCache.ContainsKey(text))
|
||||||
{
|
{
|
||||||
await RespondAsync(ephemeral: true, text: "This log file has already been analysed [here](" + Program.AnalysisCache[text].GetJumpUrl() + ").");
|
await RespondAsync(ephemeral: true, embed: new EmbedBuilder().WithDescription("This log file has already been analysed [here](" + Program.AnalysisCache[text].GetJumpUrl() + ").").WithDefaults().Build());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await DeferAsync();
|
await DeferAsync();
|
||||||
|
|
@ -97,7 +64,6 @@ namespace SMSModLogOutputAnalyzer
|
||||||
var textLines = text.Split('\n').Select(x => x.Trim()).ToArray();
|
var textLines = text.Split('\n').Select(x => x.Trim()).ToArray();
|
||||||
var embedBuilder = new EmbedBuilder();
|
var embedBuilder = new EmbedBuilder();
|
||||||
embedBuilder.WithAuthor(Context.User);
|
embedBuilder.WithAuthor(Context.User);
|
||||||
embedBuilder.WithFooter(Program.Footer);
|
|
||||||
|
|
||||||
Dictionary<string, List<string>> values = new();
|
Dictionary<string, List<string>> values = new();
|
||||||
var lines = FindLines(textLines,
|
var lines = FindLines(textLines,
|
||||||
|
|
@ -209,7 +175,7 @@ namespace SMSModLogOutputAnalyzer
|
||||||
foreach (var field in fields) Log(field.Name + ", " + field.Value);
|
foreach (var field in fields) Log(field.Name + ", " + field.Value);
|
||||||
embedBuilder.WithFields(fields);
|
embedBuilder.WithFields(fields);
|
||||||
|
|
||||||
embedBuilder.WithColor(Color.DarkBlue);
|
embedBuilder.WithDefaults();
|
||||||
var embed = embedBuilder.Build();
|
var embed = embedBuilder.Build();
|
||||||
var message = await ModifyOriginalResponseAsync(func => { func.Embeds = new[] { embed }; func.Components = downloadButton.Build(); });
|
var message = await ModifyOriginalResponseAsync(func => { func.Embeds = new[] { embed }; func.Components = downloadButton.Build(); });
|
||||||
Program.AnalysisCache.Add(text, message);
|
Program.AnalysisCache.Add(text, message);
|
||||||
|
|
@ -236,33 +202,5 @@ namespace SMSModLogOutputAnalyzer
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
[SlashCommand("troubleshoot", "Starts the troubleshooting assistant.")]
|
|
||||||
[RequireUserPermission(GuildPermission.ManageChannels)]
|
|
||||||
public async Task Troubleshoot()
|
|
||||||
{
|
|
||||||
await RespondAsync("Posting", ephemeral: true);
|
|
||||||
await Context.Channel.SendMessageAsync(embed: new EmbedBuilder()
|
|
||||||
.WithTitle("Troubleshooting Assistant")
|
|
||||||
.WithDescription("Press the button below to be guided through our troubleshooting assistant. Hopefully it can help you with getting mods working.")
|
|
||||||
.WithFooter(Program.Footer)
|
|
||||||
.Build(),
|
|
||||||
components: new ComponentBuilder()
|
|
||||||
.WithButton("Start", "troubleshoot:root", ButtonStyle.Success)
|
|
||||||
.Build());
|
|
||||||
}
|
|
||||||
[ComponentInteraction("troubleshoot:*")]
|
|
||||||
public async Task TroubleshootButton(string node)
|
|
||||||
{
|
|
||||||
Flowchart.FlowchartNode fcnode = Program.Troubleshooting.Nodes.Find(x => x.Name == node);
|
|
||||||
if (fcnode == null) return;
|
|
||||||
var connections = Program.Troubleshooting.Connections.Where(x => x.FromName == node);
|
|
||||||
var cmpb = new ComponentBuilder();
|
|
||||||
foreach (var conn in connections) cmpb.WithButton(conn.Text, "troubleshoot:" + conn.ToName, conn.Text == "Yes" ? ButtonStyle.Success : conn.Text == "No" ? ButtonStyle.Danger : ButtonStyle.Primary);
|
|
||||||
await RespondAsync(embed: new EmbedBuilder()
|
|
||||||
.WithTitle(fcnode.Text)
|
|
||||||
.WithDescription(fcnode.Description)
|
|
||||||
.WithFooter(Program.Footer)
|
|
||||||
.Build(), components: cmpb.Build(), ephemeral: true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
using Discord;
|
||||||
|
using Discord.Interactions;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Modules
|
||||||
|
{
|
||||||
|
public partial class NotesModule
|
||||||
|
{
|
||||||
|
public partial class Commands
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Currently unused because I can't figure out how to get modals to work
|
||||||
|
/// </summary>
|
||||||
|
public class AddNoteModal : IModal
|
||||||
|
{
|
||||||
|
public string Title => "Add Note";
|
||||||
|
[RequiredInput(true)]
|
||||||
|
[InputLabel("Note Text")]
|
||||||
|
[ModalTextInput("note_text", TextInputStyle.Paragraph, "stinky")]
|
||||||
|
public string Note { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
108
SMSModLogOutputAnalyzer/Modules/Notes/NotesModule.Commands.cs
Normal file
108
SMSModLogOutputAnalyzer/Modules/Notes/NotesModule.Commands.cs
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
using Discord;
|
||||||
|
using Discord.Interactions;
|
||||||
|
using SMSModLogOutputAnalyzer.Data;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Modules
|
||||||
|
{
|
||||||
|
public partial class NotesModule
|
||||||
|
{
|
||||||
|
[Group("notes", "Various commands related to notes.")]
|
||||||
|
public partial class Commands : InteractionModuleBase
|
||||||
|
{
|
||||||
|
[SlashCommand("view", "View notes that have been added to a user.")]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
|
public async Task View(IUser user, [Summary(description: "How many notes to skip (used for pagination)")] int offset = 0)
|
||||||
|
{
|
||||||
|
EmbedBuilder embedBuilder = new EmbedBuilder();
|
||||||
|
|
||||||
|
var notes = Data[user].Notes.Skip(offset).Take(25).ToArray();
|
||||||
|
bool addNextPageButton = Data[user].Notes.Count > offset + 25;
|
||||||
|
if (notes.Length == 0)
|
||||||
|
{
|
||||||
|
await RespondAsync(embed: new EmbedBuilder().WithDefaults().WithDescription("No " + (offset > 0 ? "more " : "") + "notes have been added to this user.").Build(), ephemeral: true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
embedBuilder.WithAuthor(user);
|
||||||
|
embedBuilder.WithDefaults();
|
||||||
|
|
||||||
|
foreach (var note in notes)
|
||||||
|
{
|
||||||
|
embedBuilder.AddField(note.ToField());
|
||||||
|
}
|
||||||
|
|
||||||
|
var embed = embedBuilder.Build();
|
||||||
|
var button = new ComponentBuilder().WithButton("Next Page", "view_notes:" + user.Id + ":" + (offset + 25)).Build();
|
||||||
|
|
||||||
|
if (addNextPageButton)
|
||||||
|
{
|
||||||
|
await RespondAsync(embed: embed, components: button, ephemeral: true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await RespondAsync(embed: embed, ephemeral: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
[SlashCommand("add", "Add a note to a user.")]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
|
public async Task Add(IUser user, [Summary("note")] string text)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text))
|
||||||
|
{
|
||||||
|
Console.WriteLine("Sending modal");
|
||||||
|
await Context.Interaction.RespondWithModalAsync<AddNoteModal>("add_note:" + user.Id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NotesDataObject.Note note = new();
|
||||||
|
|
||||||
|
note.Text = text;
|
||||||
|
note.CreatorID = Context.User.Id;
|
||||||
|
note.CreationTime = DateTime.Now;
|
||||||
|
note.Id = ++Data[user].Counter;
|
||||||
|
|
||||||
|
Data[user].Notes.Add(note);
|
||||||
|
Data.Save();
|
||||||
|
|
||||||
|
string error = "";
|
||||||
|
|
||||||
|
var field = note.ToField();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Config.NotesLogChannel.SendMessageAsync(embed: new EmbedBuilder().WithDefaults().WithAuthor(user.Username + " - New Note", user.GetDisplayAvatarUrl()).WithTitle(field.Name).WithDescription((string)field.Value).Build());
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
error = "\n\n:x: Logging failed";
|
||||||
|
}
|
||||||
|
|
||||||
|
await RespondAsync(embed: new EmbedBuilder().WithDescription("Note **" + note.Id + "** added." + error).WithDefaults().Build(), ephemeral: true);
|
||||||
|
}
|
||||||
|
[SlashCommand("remove", "Removes a note from a user.")]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
|
public async Task Remove(IUser user, int note_id)
|
||||||
|
{
|
||||||
|
int num = Data[user].Notes.RemoveAll(x => x.Id == note_id);
|
||||||
|
Data.Save();
|
||||||
|
if (num > 0) await RespondAsync(embed: new EmbedBuilder().WithDescription("Note **" + note_id + "** removed.").WithDefaults().Build(), ephemeral: true);
|
||||||
|
else await RespondAsync(embed: new EmbedBuilder().WithDescription("Note **" + note_id + "** was not found.").WithDefaults().Build(), ephemeral: true);
|
||||||
|
}
|
||||||
|
[SlashCommand("clear", "Removes all notes from a user.")]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
|
public async Task Clear(IUser user)
|
||||||
|
{
|
||||||
|
int num = Data[user].Notes.RemoveAll(x => true);
|
||||||
|
Data.Save();
|
||||||
|
await RespondAsync(embed: new EmbedBuilder().WithDescription("**" + num + "** notes were removed.").WithDefaults().Build(), ephemeral: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[ModalInteraction("add_note:*", true)]
|
||||||
|
[RequireUserPermission(ChannelPermission.ManageRoles)]
|
||||||
|
public async Task AddModal(AddNoteModal modal, string user) => await Add(await Context.Client.GetUserAsync(ulong.Parse(user)), modal.Note);
|
||||||
|
[ComponentInteraction("view_notes:*:*", true)]
|
||||||
|
[RequireUserPermission(ChannelPermission.ManageRoles)]
|
||||||
|
public async Task ViewButton(string user, string offset) => await View(await Context.Client.GetUserAsync(ulong.Parse(user)), int.Parse(offset));
|
||||||
|
[MessageCommand("View Notes")]
|
||||||
|
[RequireUserPermission(ChannelPermission.ManageRoles)]
|
||||||
|
public async Task UserView(IMessage message) => await View(message.Author);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
SMSModLogOutputAnalyzer/Modules/Notes/NotesModule.cs
Normal file
15
SMSModLogOutputAnalyzer/Modules/Notes/NotesModule.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
using Discord.Interactions;
|
||||||
|
using SMSModLogOutputAnalyzer.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Modules
|
||||||
|
{
|
||||||
|
public partial class NotesModule : InteractionModuleBase
|
||||||
|
{
|
||||||
|
public static NotesDataObject Data { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,131 @@
|
||||||
|
using Discord;
|
||||||
|
using Discord.Interactions;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Globalization;
|
||||||
|
using static SMSModLogOutputAnalyzer.Data.RoleButtonsDataObject;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Modules
|
||||||
|
{
|
||||||
|
public partial class RoleButtonModule
|
||||||
|
{
|
||||||
|
[Group("role", "Role Button Commands")]
|
||||||
|
public class Commands : InteractionModuleBase
|
||||||
|
{
|
||||||
|
[Group("button", "Role Button Commands")]
|
||||||
|
public class Subcommands : InteractionModuleBase
|
||||||
|
{
|
||||||
|
[SlashCommand("create", "Creates a new role button.")]
|
||||||
|
[RequireUserPermission(ChannelPermission.ManageRoles)]
|
||||||
|
public async Task Create([Summary(description: "What role the button should give")] IRole role,
|
||||||
|
[Summary(description: "What title the embed should have")] string title,
|
||||||
|
[Summary(description: "What description the embed should have")] string description,
|
||||||
|
[Summary(description: "What text the button should have")] string button_text,
|
||||||
|
[Summary(description: "What emote the button should have")] string button_emote = "",
|
||||||
|
[Summary(description: "What style the button should have")] ButtonStyle style = ButtonStyle.Primary,
|
||||||
|
[Summary(description: "What role should the user already need to have")] IRole required_role = null,
|
||||||
|
[Summary(description: "Embed color (hex code)")] string embed_color = "206694")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
RoleButton button = new RoleButton();
|
||||||
|
button.Id = Data.Counter++;
|
||||||
|
button.Role = role.Id;
|
||||||
|
if (required_role != null) button.RequiredRole = required_role.Id;
|
||||||
|
Data.List.Add(button);
|
||||||
|
Data.Save();
|
||||||
|
|
||||||
|
EmbedBuilder embedBuilder = new EmbedBuilder();
|
||||||
|
embedBuilder.WithTitle(title);
|
||||||
|
embedBuilder.WithDescription(description);
|
||||||
|
embedBuilder.WithColor(Program.ConvertColor(embed_color));
|
||||||
|
|
||||||
|
ComponentBuilder componentBuilder = new ComponentBuilder();
|
||||||
|
var buttonBuilder = new ButtonBuilder().WithLabel(button_text).WithStyle(style).WithCustomId("role_button:" + button.Id);
|
||||||
|
if (Emote.TryParse(button_emote, out Emote emote))
|
||||||
|
{
|
||||||
|
buttonBuilder.WithEmote(emote);
|
||||||
|
}
|
||||||
|
if (Emoji.TryParse(button_emote, out Emoji emote2))
|
||||||
|
{
|
||||||
|
buttonBuilder.WithEmote(emote2);
|
||||||
|
}
|
||||||
|
componentBuilder.WithButton(buttonBuilder);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await Context.Channel.SendMessageAsync(embed: embedBuilder.Build(), components: componentBuilder.Build());
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
await RespondAsync(embed: new EmbedBuilder().WithDefaults().WithDescription(":x: Message Sending failed. Ensure the bot has sufficient permissions to send in this channel.").Build(), ephemeral: true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await RespondAsync(embed: new EmbedBuilder().WithDefaults().WithDescription(":white_check_mark: Role Button Created").Build(), ephemeral: true);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ComponentInteraction("role_button:*", true)]
|
||||||
|
public async Task RoleButton(string id)
|
||||||
|
{
|
||||||
|
var button = Data[int.Parse(id)];
|
||||||
|
|
||||||
|
if (Context.User is SocketGuildUser user)
|
||||||
|
{
|
||||||
|
if (user.Roles.Any(x => x.Id == button.Role))
|
||||||
|
{
|
||||||
|
await RemoveRole(button.Role);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (button.RequiredRole == 0)
|
||||||
|
{
|
||||||
|
await AddRole(button.Role);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (user.Roles.Any(x => x.Id == button.RequiredRole))
|
||||||
|
{
|
||||||
|
await AddRole(button.Role);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await RespondAsync(embed: new EmbedBuilder().WithDefaults().WithDescription("You need the role <@&" + button.RequiredRole + "> to be allowed to get this role.").Build(), ephemeral: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task AddRole(ulong role)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Context.User is SocketGuildUser user)
|
||||||
|
{
|
||||||
|
await user.AddRoleAsync(role);
|
||||||
|
await RespondAsync(embed: new EmbedBuilder().WithDefaults().WithDescription(":white_check_mark: Role Added: <@&" + role + ">").Build(), ephemeral: true);
|
||||||
|
}
|
||||||
|
} catch (Exception e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RemoveRole(ulong role)
|
||||||
|
{
|
||||||
|
if (Context.User is SocketGuildUser user)
|
||||||
|
{
|
||||||
|
await user.RemoveRoleAsync(role);
|
||||||
|
await RespondAsync(embed: new EmbedBuilder().WithDefaults().WithDescription(":x: Role Removed: <@&" + role + ">").Build(), ephemeral: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
using Discord.Interactions;
|
||||||
|
using SMSModLogOutputAnalyzer.Data;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Modules
|
||||||
|
{
|
||||||
|
public partial class RoleButtonModule : InteractionModuleBase
|
||||||
|
{
|
||||||
|
public static RoleButtonsDataObject Data { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
using Discord;
|
||||||
|
using Discord.Interactions;
|
||||||
|
|
||||||
|
namespace SMSModLogOutputAnalyzer.Modules
|
||||||
|
{
|
||||||
|
public class TroubleshootingModule : InteractionModuleBase
|
||||||
|
{
|
||||||
|
[SlashCommand("troubleshoot", "Starts the troubleshooting assistant.")]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||||
|
public async Task Troubleshoot()
|
||||||
|
{
|
||||||
|
await RespondAsync("Posting", ephemeral: true);
|
||||||
|
await Context.Channel.SendMessageAsync(embed: new EmbedBuilder()
|
||||||
|
.WithTitle("Troubleshooting Assistant")
|
||||||
|
.WithDescription("Press the button below to be guided through our troubleshooting assistant. Hopefully it can help you with getting mods working.")
|
||||||
|
.WithFooter(Program.Footer)
|
||||||
|
.Build(),
|
||||||
|
components: new ComponentBuilder()
|
||||||
|
.WithButton("Start", "troubleshoot:root", ButtonStyle.Success)
|
||||||
|
.Build());
|
||||||
|
}
|
||||||
|
[ComponentInteraction("troubleshoot:*")]
|
||||||
|
public async Task TroubleshootButton(string node)
|
||||||
|
{
|
||||||
|
Flowchart.FlowchartNode fcnode = Program.Troubleshooting.Nodes.Find(x => x.Name == node);
|
||||||
|
if (fcnode == null) return;
|
||||||
|
var connections = Program.Troubleshooting.Connections.Where(x => x.FromName == node);
|
||||||
|
var cmpb = new ComponentBuilder();
|
||||||
|
foreach (var conn in connections) cmpb.WithButton(conn.Text, "troubleshoot:" + conn.ToName, conn.Text == "Yes" ? ButtonStyle.Success : conn.Text == "No" ? ButtonStyle.Danger : ButtonStyle.Primary);
|
||||||
|
await RespondAsync(embed: new EmbedBuilder()
|
||||||
|
.WithTitle(fcnode.Text)
|
||||||
|
.WithDescription(fcnode.Description)
|
||||||
|
.WithFooter(Program.Footer)
|
||||||
|
.Build(), components: cmpb.Build(), ephemeral: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,37 +1,60 @@
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Interactions;
|
using Discord.Interactions;
|
||||||
using System.Reflection;
|
using SMSModLogOutputAnalyzer.Modules;
|
||||||
using System;
|
using SMSModLogOutputAnalyzer.Data;
|
||||||
|
using SMSModLogOutputAnalyzer.Modules;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
namespace SMSModLogOutputAnalyzer
|
namespace SMSModLogOutputAnalyzer
|
||||||
{
|
{
|
||||||
internal static class Program
|
internal static class Program
|
||||||
{
|
{
|
||||||
private static DiscordSocketClient _client;
|
public static DiscordSocketClient Client;
|
||||||
public static Flowchart Troubleshooting;
|
public static Flowchart Troubleshooting;
|
||||||
public const string Footer = "SMS Mods Bot • Made by BratPfanneTV, for Modded Supermarket Simulator (Unofficial)";
|
public const string Footer = "SMS Mods Bot • Made by BratPfanneTV, for Modded Supermarket Simulator (Unofficial)";
|
||||||
|
public static Color Color = Color.DarkBlue;
|
||||||
public static Dictionary<string, IMessage> AnalysisCache = new();
|
public static Dictionary<string, IMessage> AnalysisCache = new();
|
||||||
|
public static EmbedBuilder WithDefaults(this EmbedBuilder builder)
|
||||||
|
{
|
||||||
|
return builder.WithFooter(Footer).WithColor(Color);
|
||||||
|
}
|
||||||
|
public static Color ConvertColor(string hex)
|
||||||
|
{
|
||||||
|
string colorcode = hex;
|
||||||
|
colorcode = colorcode.TrimStart('#');
|
||||||
|
return new Color(
|
||||||
|
int.Parse(colorcode.Substring(0, 2), NumberStyles.HexNumber),
|
||||||
|
int.Parse(colorcode.Substring(2, 2), NumberStyles.HexNumber),
|
||||||
|
int.Parse(colorcode.Substring(4, 2), NumberStyles.HexNumber));
|
||||||
|
}
|
||||||
|
public static bool TryParseEmote(string str, out IEmote iemote)
|
||||||
|
{
|
||||||
|
if (Emote.TryParse(str, out Emote emote)) iemote = emote;
|
||||||
|
else if (Emoji.TryParse(str, out Emoji emoji)) iemote = emoji;
|
||||||
|
else iemote = null;
|
||||||
|
return iemote != null;
|
||||||
|
}
|
||||||
public static async Task Main()
|
public static async Task Main()
|
||||||
{
|
{
|
||||||
Troubleshooting = Flowchart.Parse(Properties.Resources.Flowchart);
|
Troubleshooting = Flowchart.Parse(Properties.Resources.Flowchart);
|
||||||
|
|
||||||
_client = new DiscordSocketClient(new DiscordSocketConfig { LogLevel = LogSeverity.Debug });
|
Client = new DiscordSocketClient(new DiscordSocketConfig { LogLevel = LogSeverity.Debug });
|
||||||
|
|
||||||
_client.Log += Log;
|
Client.Log += Log;
|
||||||
|
|
||||||
// You can assign your bot token to a string, and pass that in to connect.
|
// You can assign your bot token to a string, and pass that in to connect.
|
||||||
// This is, however, insecure, particularly if you plan to have your code hosted in a public repository.
|
// This is, however, insecure, particularly if you plan to have your code hosted in a public repository.
|
||||||
var token = File.ReadAllText("token.txt");
|
var token = File.ReadAllText("token.txt");
|
||||||
_client.Ready += _client_Ready;
|
Client.Ready += _client_Ready;
|
||||||
|
|
||||||
// Some alternative options would be to keep your token in an Environment Variable or a standalone file.
|
// Some alternative options would be to keep your token in an Environment Variable or a standalone file.
|
||||||
// var token = Environment.GetEnvironmentVariable("NameOfYourEnvironmentVariable");
|
// var token = Environment.GetEnvironmentVariable("NameOfYourEnvironmentVariable");
|
||||||
// var token = File.ReadAllText("token.txt");
|
// var token = File.ReadAllText("token.txt");
|
||||||
// var token = JsonConvert.DeserializeObject<AConfigurationClass>(File.ReadAllText("config.json")).Token;
|
// var token = JsonConvert.DeserializeObject<AConfigurationClass>(File.ReadAllText("config.json")).Token;
|
||||||
|
|
||||||
await _client.LoginAsync(TokenType.Bot, token);
|
await Client.LoginAsync(TokenType.Bot, token);
|
||||||
await _client.StartAsync();
|
await Client.StartAsync();
|
||||||
|
|
||||||
// Block this task until the program is closed.
|
// Block this task until the program is closed.
|
||||||
await Task.Delay(-1);
|
await Task.Delay(-1);
|
||||||
|
|
@ -39,14 +62,22 @@ namespace SMSModLogOutputAnalyzer
|
||||||
|
|
||||||
private static async Task _client_Ready()
|
private static async Task _client_Ready()
|
||||||
{
|
{
|
||||||
var server = (ulong)652484929950842881;
|
NotesModule.Data = NotesDataObject.Load();
|
||||||
var _interactionService = new InteractionService(_client.Rest);
|
RoleButtonModule.Data = RoleButtonsDataObject.Load();
|
||||||
var module = await _interactionService.AddModuleAsync<CommandModule>(null);
|
Config.Load();
|
||||||
await _interactionService.AddModulesGloballyAsync(true, module);
|
|
||||||
|
|
||||||
_client.InteractionCreated += async (x) =>
|
var _interactionService = new InteractionService(Client.Rest);
|
||||||
|
await _interactionService.AddModulesGloballyAsync(true,
|
||||||
|
await _interactionService.AddModuleAsync<AskForLogFileModule>(null),
|
||||||
|
await _interactionService.AddModuleAsync<ConfigModule>(null),
|
||||||
|
await _interactionService.AddModuleAsync<RoleButtonModule>(null),
|
||||||
|
await _interactionService.AddModuleAsync<LogAnalyzeModule>(null),
|
||||||
|
await _interactionService.AddModuleAsync<NotesModule>(null),
|
||||||
|
await _interactionService.AddModuleAsync<TroubleshootingModule>(null));
|
||||||
|
|
||||||
|
Client.InteractionCreated += async (x) =>
|
||||||
{
|
{
|
||||||
var ctx = new SocketInteractionContext(_client, x);
|
var ctx = new SocketInteractionContext(Client, x);
|
||||||
await _interactionService.ExecuteCommandAsync(ctx, null);
|
await _interactionService.ExecuteCommandAsync(ctx, null);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,22 @@
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Remove="Modules\NewFolder\**" />
|
||||||
|
<EmbeddedResource Remove="Modules\NewFolder\**" />
|
||||||
|
<None Remove="Modules\NewFolder\**" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Discord.Net" Version="3.14.1" />
|
<PackageReference Include="Discord.Net" Version="3.14.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="Orpticon">
|
||||||
|
<HintPath>..\..\OrpticonDLL\bin\Debug\Orpticon.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Update="Properties\Resources.Designer.cs">
|
<Compile Update="Properties\Resources.Designer.cs">
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue