6 Commits

Author SHA1 Message Date
208d7638c9 Merge branch 'preview' 2022-07-06 13:57:02 +03:00
26a74a9269 Moved to JSON format for settings 2022-06-09 18:01:05 +03:00
ffa6692e07 2022-06-03 22:37:58 +03:00
44690f8e9d 2022-06-03 22:37:16 +03:00
9aa9d5ab03 2022-05-27 12:38:09 +03:00
Wizzy69
88ff621f22 Delete FreeGames directory 2022-05-27 12:31:55 +03:00
73 changed files with 669 additions and 1517 deletions

2
.gitignore vendored
View File

@@ -362,5 +362,3 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd
*.txt

View File

@@ -1,13 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/projectSettingsUpdater.xml
/contentModel.xml
/.idea.SethDiscordBot.iml
/modules.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@@ -1 +0,0 @@
SethDiscordBot

View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
</project>

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="UserContentModel">
<attachedFolders />
<explicitIncludes />
<explicitExcludes />
</component>
</project>

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

4
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,4 @@
{
"rpc.enabled": true,
"discord.enabled": true
}

Binary file not shown.

Binary file not shown.

View File

@@ -6,25 +6,12 @@
"compilationOptions": {},
"targets": {
".NETCoreApp,Version=v6.0": {
"Music Commands/1.0.0": {
"MusicCommands/1.0.0": {
"dependencies": {
"PluginManager": "1.0.0",
"YoutubeExplode": "6.2.0"
"PluginManager": "1.0.0"
},
"runtime": {
"Music Commands.dll": {}
}
},
"AngleSharp/0.17.0": {
"dependencies": {
"System.Buffers": "4.5.1",
"System.Text.Encoding.CodePages": "5.0.0"
},
"runtime": {
"lib/netstandard2.0/AngleSharp.dll": {
"assemblyVersion": "0.17.0.0",
"fileVersion": "0.17.0.0"
}
"MusicCommands.dll": {}
}
},
"Discord.Net/3.7.2": {
@@ -121,7 +108,6 @@
}
}
},
"Microsoft.NETCore.Platforms/5.0.0": {},
"Newtonsoft.Json/13.0.1": {
"runtime": {
"lib/netstandard2.0/Newtonsoft.Json.dll": {
@@ -130,7 +116,6 @@
}
}
},
"System.Buffers/4.5.1": {},
"System.Collections.Immutable/5.0.0": {},
"System.Interactive.Async/5.0.0": {
"dependencies": {
@@ -159,23 +144,7 @@
}
}
},
"System.Text.Encoding.CodePages/5.0.0": {
"dependencies": {
"Microsoft.NETCore.Platforms": "5.0.0"
}
},
"System.ValueTuple/4.5.0": {},
"YoutubeExplode/6.2.0": {
"dependencies": {
"AngleSharp": "0.17.0"
},
"runtime": {
"lib/net5.0/YoutubeExplode.dll": {
"assemblyVersion": "6.2.0.0",
"fileVersion": "6.2.0.0"
}
}
},
"PluginManager/1.0.0": {
"dependencies": {
"Discord.Net": "3.7.2"
@@ -187,18 +156,11 @@
}
},
"libraries": {
"Music Commands/1.0.0": {
"MusicCommands/1.0.0": {
"type": "project",
"serviceable": false,
"sha512": ""
},
"AngleSharp/0.17.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-74haoXINcj4SdMsmiNzk+9VUwIX1U9P61O6AZd5Uao8SGNnJJB8Y/r8VJRc8orn4c7Vk/oURAKSNF9XcSDxbfA==",
"path": "anglesharp/0.17.0",
"hashPath": "anglesharp.0.17.0.nupkg.sha512"
},
"Discord.Net/3.7.2": {
"type": "package",
"serviceable": true,
@@ -255,13 +217,6 @@
"path": "microsoft.extensions.dependencyinjection.abstractions/5.0.0",
"hashPath": "microsoft.extensions.dependencyinjection.abstractions.5.0.0.nupkg.sha512"
},
"Microsoft.NETCore.Platforms/5.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==",
"path": "microsoft.netcore.platforms/5.0.0",
"hashPath": "microsoft.netcore.platforms.5.0.0.nupkg.sha512"
},
"Newtonsoft.Json/13.0.1": {
"type": "package",
"serviceable": true,
@@ -269,13 +224,6 @@
"path": "newtonsoft.json/13.0.1",
"hashPath": "newtonsoft.json.13.0.1.nupkg.sha512"
},
"System.Buffers/4.5.1": {
"type": "package",
"serviceable": true,
"sha512": "sha512-Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg==",
"path": "system.buffers/4.5.1",
"hashPath": "system.buffers.4.5.1.nupkg.sha512"
},
"System.Collections.Immutable/5.0.0": {
"type": "package",
"serviceable": true,
@@ -304,13 +252,6 @@
"path": "system.reactive/5.0.0",
"hashPath": "system.reactive.5.0.0.nupkg.sha512"
},
"System.Text.Encoding.CodePages/5.0.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-NyscU59xX6Uo91qvhOs2Ccho3AR2TnZPomo1Z0K6YpyztBPM/A5VbkzOO19sy3A3i1TtEnTxA7bCe3Us+r5MWg==",
"path": "system.text.encoding.codepages/5.0.0",
"hashPath": "system.text.encoding.codepages.5.0.0.nupkg.sha512"
},
"System.ValueTuple/4.5.0": {
"type": "package",
"serviceable": true,
@@ -318,13 +259,6 @@
"path": "system.valuetuple/4.5.0",
"hashPath": "system.valuetuple.4.5.0.nupkg.sha512"
},
"YoutubeExplode/6.2.0": {
"type": "package",
"serviceable": true,
"sha512": "sha512-oH5kst4w1QkUwRjJco0alF57JOmFofSGlPkr4OniODB8R6MEyRWn1xFg3JS2wFYd6scZluoXRDhM3/uyUjO9/g==",
"path": "youtubeexplode/6.2.0",
"hashPath": "youtubeexplode.6.2.0.nupkg.sha512"
},
"PluginManager/1.0.0": {
"type": "project",
"serviceable": false,

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -4,7 +4,7 @@
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<BaseOutputPath>bin\</BaseOutputPath>
<BaseOutputPath>..\DiscordBot\bin\Debug\net6.0\Data\Plugins\Commands\LevelingSystem</BaseOutputPath>
</PropertyGroup>
<ItemGroup>

View File

@@ -11,8 +11,6 @@ internal class Level : DBCommand
{
public string Command => "level";
public List<string> Aliases => new() { "lvl" };
public string Description => "Display tour current level";
public string Usage => "level";

View File

@@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<BaseOutputPath>bin\</BaseOutputPath>
<BaseOutputPath></BaseOutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

View File

@@ -1,14 +1,11 @@
using Discord.Commands;
using Discord.WebSocket;
using PluginManager.Interfaces;
using System.Collections.Generic;
internal class Echo : DBCommand
{
public string Command => "echo";
public List<string> Aliases => null;
public string Description => "Replay with the same message";
public string Usage => "echo [message]";

View File

@@ -1,7 +1,6 @@
using Discord.Commands;
using Discord.WebSocket;
using PluginManager.Interfaces;
using System.Collections.Generic;
namespace CMD_Utils;
@@ -9,8 +8,6 @@ internal class FlipCoin : DBCommand
{
public string Command => "flip";
public List<string> Aliases => null;
public string Description => "Flip a coin";
public string Usage => "flip";

View File

@@ -11,8 +11,6 @@ public class Poll : DBCommand
{
public string Command => "poll";
public List<string> Aliases => null;
public string Description => "Create a poll with options";
public string Usage => "poll [This-is-question] [This-is-answer-1] [This-is-answer-2] ... ";

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using Discord.Commands;
using Discord.Commands;
using Discord.WebSocket;
using PluginManager.Interfaces;
@@ -7,8 +6,6 @@ public class Random : DBCommand
{
public string Command => "random";
public List<string> Aliases => new() { "rnd" };
public string Description => "random number between number1 and number2";
public string Usage => "random [number1] [number2]";

BIN
DiscordBot.dll Normal file

Binary file not shown.

View File

@@ -1,6 +1,4 @@
using System.Collections.Generic;
using System.Linq;
using Discord;
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using PluginManager.Interfaces;
@@ -19,17 +17,15 @@ internal class Help : DBCommand
/// </summary>
public string Command => "help";
public List<string> Aliases => null;
/// <summary>
/// Command Description
/// </summary>
public string Description => "This command allows you to check all loaded commands";
public string Description => "This command allows you to check all loadded commands";
/// <summary>
/// Command usage
/// </summary>
public string Usage => "help <command>";
public string Usage => "help";
/// <summary>
/// Check if the command can be used <inheritdoca DM <see cref="IChannel" />/>
@@ -61,10 +57,10 @@ internal class Help : DBCommand
foreach (var item in args)
{
var e = GenerateHelpCommand(item);
if (e is null)
context.Channel.SendMessageAsync("Unknown Command " + item);
else
if (e != null)
context.Channel.SendMessageAsync(embed: e.Build());
else
context.Channel.SendMessageAsync("Unknown Command " + item);
}
return;
@@ -78,12 +74,10 @@ internal class Help : DBCommand
foreach (var cmd in PluginLoader.Commands!)
{
if (cmd.canUseDM)
DMCommands += cmd.Command + " ";
if (cmd.canUseDM) DMCommands += cmd.Command + " ";
if (cmd.requireAdmin)
adminCommands += cmd.Command + " ";
if (cmd.canUseServer)
normalCommands += cmd.Command + " ";
adminCommands += cmd.Command + " ";
else if (cmd.canUseServer) normalCommands += cmd.Command + " ";
}
embedBuilder.AddField("Admin Commands", adminCommands);
@@ -95,14 +89,11 @@ internal class Help : DBCommand
private EmbedBuilder GenerateHelpCommand(string command)
{
var embedBuilder = new EmbedBuilder();
var cmd = PluginLoader.Commands!.Find(p => p.Command == command || (p.Aliases is not null && p.Aliases.Contains(command)));
var cmd = PluginLoader.Commands.Find(p => p.Command == command);
if (cmd == null) return null;
embedBuilder.AddField("Usage", cmd.Usage);
embedBuilder.AddField("Description", cmd.Description);
if (cmd.Aliases is null)
return embedBuilder;
embedBuilder.AddField("Alias", cmd.Aliases.Count == 0 ? "-" : string.Join(", ", cmd.Aliases));
return embedBuilder;
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Discord.WebSocket;
using PluginManager.Interfaces;
@@ -18,8 +17,6 @@ internal class Restart : DBCommand
/// </summary>
public string Command => "restart";
public List<string> Aliases => null;
/// <summary>
/// Command Description
/// </summary>

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using Discord;
using Discord.Commands;
using Discord.WebSocket;
@@ -15,8 +14,6 @@ internal class Settings : DBCommand
/// </summary>
public string Command => "set";
public List<string> Aliases => null;
/// <summary>
/// Command Description
/// </summary>

View File

@@ -60,9 +60,7 @@ internal class Boot
/// <returns>Task</returns>
public async Task Awake()
{
DiscordSocketConfig config = new DiscordSocketConfig { AlwaysDownloadUsers = true };
client = new DiscordSocketClient(config);
client = new DiscordSocketClient();
service = new CommandService();
CommonTasks();
@@ -98,6 +96,16 @@ internal class Boot
Console.Title = "ONLINE";
isReady = true;
new Thread(() =>
{
while (true)
{
Config.SaveConfig();
Thread.Sleep(10000);
}
}
).Start();
return Task.CompletedTask;
}

View File

@@ -47,16 +47,13 @@ internal class CommandHandler
{
try
{
if (Message as SocketUserMessage == null)
return;
if (Message as SocketUserMessage == null) return;
var message = Message as SocketUserMessage;
if (message == null)
return;
if (message == null) return;
if (!message.Content.StartsWith(botPrefix))
return;
if (!message.Content.StartsWith(botPrefix)) return;
var argPos = 0;
@@ -66,14 +63,17 @@ internal class CommandHandler
return;
}
if (message.Author.IsBot)
return;
if (message.Author.IsBot) return;
var context = new SocketCommandContext(client, message);
await commandService.ExecuteAsync(context, argPos, null);
await commandService.ExecuteAsync(
context,
argPos,
null
);
var plugin = PluginLoader.Commands!.Where(p => p.Command == message.Content.Split(' ')[0].Substring(botPrefix.Length) || (p.Aliases is not null && p.Aliases.Contains(message.Content.Split(' ')[0].Substring(botPrefix.Length)))).FirstOrDefault();
var plugin = PluginLoader.Commands!.Where(p => p.Command == message.Content.Split(' ')[0].Substring(botPrefix.Length)).FirstOrDefault();
if (plugin != null)

View File

@@ -8,15 +8,15 @@
<StartupObject />
<SignAssembly>False</SignAssembly>
<IsPublishable>True</IsPublishable>
<AssemblyVersion>1.0.0.2</AssemblyVersion>
<AssemblyVersion>1.0.0.1</AssemblyVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>none</DebugType>
<DebugType>none</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>none</DebugType>
<DebugType>none</DebugType>
</PropertyGroup>
<ItemGroup>

View File

@@ -2,12 +2,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using DiscordBot.Discord.Core;
using PluginManager;
using PluginManager.Items;
using PluginManager.Online;
@@ -27,44 +23,11 @@ public class Program
[Obsolete]
public static void Main(string[] args)
{
Directory.CreateDirectory("./Data/Resources");
Directory.CreateDirectory("./Data/Plugins/Commands");
Directory.CreateDirectory("./Data/Plugins/Events");
PreLoadComponents().Wait();
if (!Config.ContainsKey("ServerID"))
{
do
{
Console.Clear();
Console.WriteLine("Please enter the server ID: ");
Console_Utilities.WriteColorText("You can find it in the Server Settings at &r\"Widget\"&c section");
Console.WriteLine("Example: 1234567890123456789");
Console.WriteLine("This is not required, but is recommended. If you refuse to provide the ID, just press enter.\nThe server id is required to make easier for the bot to interact with the server.\nRemember: this bot is for one server ONLY.");
Console.Write("User Input > ");
ConsoleKeyInfo key = Console.ReadKey();
if (key.Key == ConsoleKey.Enter)
Config.AddValueToVariables("ServerID", "null", false);
else
{
string SID = key.KeyChar + Console.ReadLine();
if (SID.Length != 18)
{
Console.WriteLine("Your server ID is not 18 characters long. Please try again.");
continue;
}
Config.AddValueToVariables("ServerID", SID, false);
}
break;
} while (true);
}
if (!Config.ContainsKey("token") || Config.GetValue<string>("token") == null || Config.GetValue<string>("token")?.Length != 70)
{
Console.WriteLine("Please insert your token");
@@ -80,8 +43,7 @@ public class Program
Console.Write("Prefix = ");
var prefix = Console.ReadLine()![0];
if (prefix == ' ' || char.IsDigit(prefix))
return;
if (prefix == ' ' || char.IsDigit(prefix)) return;
Config.AddValueToVariables("prefix", prefix.ToString(), false);
}
@@ -103,26 +65,20 @@ public class Program
/// The main loop for the discord bot
/// </summary>
/// <param name="discordbooter">The discord booter used to start the application</param>
private static void NoGUI(Boot discordbooter)
private static Task NoGUI(Boot discordbooter)
{
var consoleCommandsHandler = new ConsoleCommandsHandler(discordbooter.client);
#if DEBUG
Console.WriteLine();
consoleCommandsHandler.HandleCommand("lp");
#else
if (loadPluginsOnStartup) consoleCommandsHandler.HandleCommand("lp");
if (listPluginsAtStartup) consoleCommandsHandler.HandleCommand("listplugs");
#endif
Config.SaveConfig();
while (true)
{
//Console_Utilities.WriteColorText("&rSethBot (&yDEBUG&r) &c> ", false);
Console.ForegroundColor = ConsoleColor.White;
var cmd = Console.ReadLine();
if (!consoleCommandsHandler.HandleCommand(cmd!,
#if DEBUG
false
#endif
) && cmd.Length > 0)
if (!consoleCommandsHandler.HandleCommand(cmd))
Console.WriteLine("Failed to run command " + cmd);
}
}
@@ -136,33 +92,19 @@ public class Program
Console.Clear();
Console.ForegroundColor = ConsoleColor.DarkYellow;
List<string> startupMessageList = await ServerCom.ReadTextFromURL("https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/StartupMessage");
List<string> startupMessageList = await ServerCom.ReadTextFromFile("https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/StartupMessage");
foreach (var message in startupMessageList)
Console.WriteLine(message);
foreach (var message in startupMessageList) Console.WriteLine(message);
Console.WriteLine($"Running on version: {Config.GetValue<string>("Version") ?? System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()}");
Console.WriteLine($"Git URL: {Config.GetValue<string>("GitURL") ?? " Could not find Git URL"}");
Console_Utilities.WriteColorText("&rRemember to close the bot using the ShutDown command (&ysd&r) or some settings won't be saved\n");
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine($"============================ LOG ============================");
try
{
var token = Config.GetValue<string>("token");
#if DEBUG
Console.WriteLine("Starting in DEBUG MODE");
if (!Directory.Exists("./Data/BetaTest"))
Console.WriteLine("Failed to start in debug mode because the folder ./Data/BetaTest does not exist");
else
{
token = File.ReadAllText("./Data/BetaTest/token.txt");
//Debug mode code...
}
#endif
var token = Config.GetValue<string>("token");
var prefix = Config.GetValue<string>("prefix");
var discordbooter = new Boot(token, prefix);
@@ -182,7 +124,7 @@ public class Program
/// <param name="d">Directory path</param>
private static Task ClearFolder(string d)
{
var files = Directory.GetFiles(d);
var files = Directory.GetFiles(d);
var fileNumb = files.Length;
for (var i = 0; i < fileNumb; i++)
{
@@ -203,7 +145,7 @@ public class Program
if (len == 3 && args[0] == "/download")
{
var url = args[1];
var url = args[1];
var location = args[2];
await ServerCom.DownloadFileAsync(url, location);
@@ -213,11 +155,8 @@ public class Program
if (len > 0 && (args.Contains("--cmd") || args.Contains("--args") || args.Contains("--nomessage")))
{
if (args.Contains("lp") || args.Contains("loadplugins"))
loadPluginsOnStartup = true;
if (args.Contains("listplugs"))
listPluginsAtStartup = true;
if (args.Contains("lp") || args.Contains("loadplugins")) loadPluginsOnStartup = true;
if (args.Contains("listplugs")) listPluginsAtStartup = true;
len = 0;
}
@@ -225,9 +164,7 @@ public class Program
if (len == 0 || (args[0] != "--exec" && args[0] != "--execute"))
{
var b = await StartNoGUI();
Thread mainThread = new Thread(() => NoGUI(b));
mainThread.Start();
await NoGUI(b);
return;
}
@@ -253,7 +190,15 @@ public class Program
case "--help":
case "-help":
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine("\tCommand name\t\t\t\tDescription\n" + "-- help | -help\t\t ------ \tDisplay the help message\n" + "--reset-full\t\t ------ \tReset all files (clear files)\n" + "--reset-settings\t ------ \tReset only bot settings\n" + "--reset-logs\t\t ------ \tClear up the output folder\n" + "--start\t\t ------ \tStart the bot\n" + "exit\t\t\t ------ \tClose the application");
Console.WriteLine(
"\tCommand name\t\t\t\tDescription\n" +
"-- help | -help\t\t ------ \tDisplay the help message\n" +
"--reset-full\t\t ------ \tReset all files (clear files)\n" +
"--reset-settings\t ------ \tReset only bot settings\n" +
"--reset-logs\t\t ------ \tClear up the output folder\n" +
"--start\t\t ------ \tStart the bot\n" +
"exit\t\t\t ------ \tClose the application"
);
break;
case "--reset-full":
await ClearFolder("./Data/Resources/");
@@ -267,12 +212,16 @@ public class Program
case "--reset-logs":
await ClearFolder("./Output/Logs");
await ClearFolder("./Output/Errors");
Console.WriteLine("Successfully clear logs folder");
Console.WriteLine("Successfully cleard logs folder");
break;
case "--exit":
case "exit":
Environment.Exit(0);
break;
case "--start":
var booter = await StartNoGUI();
await NoGUI(booter);
return;
default:
Console.WriteLine("Failed to execute command " + message[0]);
@@ -288,14 +237,14 @@ public class Program
if (Config.GetValue<bool>("DeleteLogsAtStartup"))
foreach (var file in Directory.GetFiles("./Output/Logs/"))
File.Delete(file);
List<string> OnlineDefaultKeys = await ServerCom.ReadTextFromURL("https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/SetupKeys");
List<string> OnlineDefaultKeys = await ServerCom.ReadTextFromFile("https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/SetupKeys");
Config.PluginConfig.Load();
if (!Config.ContainsKey("Version"))
Config.AddValueToVariables("Version", Assembly.GetExecutingAssembly().GetName().Version.ToString(), false);
Config.AddValueToVariables("Version", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(), false);
else
Config.SetValue("Version", Assembly.GetExecutingAssembly().GetName().Version.ToString());
Config.SetValue("Version", System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString());
foreach (var key in OnlineDefaultKeys)
{
@@ -303,8 +252,7 @@ public class Program
string[] s = key.Split(' ');
try
{
if (Config.ContainsKey(s[0])) Config.SetValue(s[0], s[1]);
else Config.GetAndAddValueToVariable(s[0], s[1], s[2].Equals("true", StringComparison.CurrentCultureIgnoreCase));
Config.GetAndAddValueToVariable(s[0], s[1], s[2].Equals("true", StringComparison.CurrentCultureIgnoreCase));
}
catch (Exception ex)
{
@@ -312,7 +260,7 @@ public class Program
}
}
List<string> onlineSettingsList = await ServerCom.ReadTextFromURL("https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/OnlineData");
List<string> onlineSettingsList = await ServerCom.ReadTextFromFile("https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/OnlineData");
foreach (var key in onlineSettingsList)
{
if (key.Length <= 3 || !key.Contains(' ')) continue;
@@ -340,7 +288,7 @@ public class Program
Console.WriteLine("\n\n");
await Task.Delay(1000);
int waitTime = 10; //wait time to proceed
int waitTime = 20; //wait time to proceed
Console.Write($"The bot will start in {waitTime} seconds");
while (waitTime > 0)
@@ -358,7 +306,6 @@ public class Program
}
}
Console_Utilities.Initialize();
Config.SaveConfig();
}

View File

@@ -1,14 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\PluginManager\PluginManager.csproj" />
</ItemGroup>
</Project>

View File

@@ -1,21 +0,0 @@
using PluginManager.Online.Updates;
try
{
bool requireUpdate = await PluginUpdater.CheckForUpdates("DiscordBotConsoleLauncher");
if (requireUpdate)
{
var update = await PluginUpdater.DownloadUpdateInfo("DiscordBotConsoleLauncher");
if (update == Update.Empty)
return;
Console.WriteLine("Found an update: ");
Console.WriteLine(update.ToString());
}
}
catch (Exception ex)
{
Console.WriteLine("An exception was thrown. ");
Console.WriteLine(ex.Message);
Environment.Exit(-2);
}

View File

@@ -21,8 +21,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EVE_LevelingSystem", "EVE_L
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CMD_LevelingSystem", "CMD_LevelingSystem\CMD_LevelingSystem.csproj", "{1A4E49FF-9A0A-4C54-AF35-CFFBA64353D9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Roles", "Roles\Roles.csproj", "{954F2AA9-6624-4554-946D-0F17B84487C3}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -53,10 +51,6 @@ Global
{1A4E49FF-9A0A-4C54-AF35-CFFBA64353D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A4E49FF-9A0A-4C54-AF35-CFFBA64353D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A4E49FF-9A0A-4C54-AF35-CFFBA64353D9}.Release|Any CPU.Build.0 = Release|Any CPU
{954F2AA9-6624-4554-946D-0F17B84487C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{954F2AA9-6624-4554-946D-0F17B84487C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{954F2AA9-6624-4554-946D-0F17B84487C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{954F2AA9-6624-4554-946D-0F17B84487C3}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -68,7 +62,6 @@ Global
{B1B4976E-5112-4217-B57B-3A03C5207B6E} = {449FA364-0B72-43FF-B3A3-806E2916200E}
{EEC445DC-0C4B-43EA-8694-606BA0390B77} = {A290C028-77C4-4D1D-AB43-DDFE6ABD9012}
{1A4E49FF-9A0A-4C54-AF35-CFFBA64353D9} = {449FA364-0B72-43FF-B3A3-806E2916200E}
{954F2AA9-6624-4554-946D-0F17B84487C3} = {449FA364-0B72-43FF-B3A3-806E2916200E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3FB3C5DE-ED21-4D2E-ABDD-3A00EE4A2FFF}

View File

@@ -4,7 +4,7 @@
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<BaseOutputPath></BaseOutputPath>
<BaseOutputPath>..\DiscordBot\bin\Debug\net6.0\Data\Plugins\Events\LevelingSystem</BaseOutputPath>
</PropertyGroup>
<ItemGroup>

View File

@@ -1,8 +1,6 @@
using Discord;
using Discord.WebSocket;
using EVE_LevelingSystem.LevelingSystemCore;
using PluginManager;
using PluginManager.Interfaces;
using PluginManager.Others;
@@ -11,20 +9,17 @@ namespace EVE_LevelingSystem
{
internal class Level : DBEvent
{
public string name => "Leveling System Event Handler";
public string description => "The Leveling System Event Handler";
public string name => "Leveling System Event Handler";
public string description => "The Leveling System Event Handler";
internal static Settings globalSettings = new();
public async void Start(DiscordSocketClient client)
{
Directory.CreateDirectory("./Data/Resources/LevelingSystem");
if (!Config.ContainsKey("LevelingSystemPath"))
Config.AddValueToVariables("LevelingSystemPath", "./Data/Resources/LevelingSystem", true);
if (!Config.ContainsKey("LevelingSystemSettingsFile"))
Config.AddValueToVariables("LevelingSystemSettingsFile", "./Data/Resources/LevelingSystemSettings.txt", true);
//PluginManager.Config.AddValueToVariables
Config.AddValueToVariables("LevelingSystemPath", "./Data/Resources/LevelingSystem", true);
Config.AddValueToVariables("LevelingSystemSettingsFile", "./Data/Resources/LevelingSystemSettings.txt", true);
if (!File.Exists(Config.GetValue<string>("LevelingSystemSettingsFile")))
{
globalSettings = new Settings { TimeToWaitBetweenMessages = 5 };
@@ -41,7 +36,7 @@ namespace EVE_LevelingSystem
{
if (arg.Author.IsBot || arg.IsTTS || arg.Content.StartsWith(Config.GetValue<string>("prefix"))) return;
string userID = arg.Author.Id.ToString();
User user;
User user;
if (File.Exists($"{Config.GetValue<string>("LevelingSystemPath")}/{userID}.dat"))
{
user = await Functions.ConvertFromJson<User>(Config.GetValue<string>("LevelingSystemPath")! + $"/{userID}.dat");

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PluginManager;
namespace EVE_LevelingSystem.LevelingSystemCore
@@ -19,7 +18,7 @@ namespace EVE_LevelingSystem.LevelingSystemCore
internal static void LevelUp(this User user)
{
user.CurrentEXP = 0;
user.CurrentEXP = 0;
user.RequiredEXPToLevelUp = GetNextLevelRequiredEXP(user.CurrentLevel);
user.CurrentLevel++;
}
@@ -27,15 +26,15 @@ namespace EVE_LevelingSystem.LevelingSystemCore
internal static bool AddEXP(this User user)
{
if (OnWaitingList.Contains(user.user.userID.ToString())) return false;
Random r = new Random();
int exp = r.Next(Level.globalSettings.MinEXP, Level.globalSettings.MaxEXP + 1);
Int64 userXP = user.CurrentEXP;
Int64 reqEXP = user.RequiredEXPToLevelUp;
Random r = new Random();
int exp = r.Next(2, 12);
Int64 userXP = user.CurrentEXP;
Int64 reqEXP = user.RequiredEXPToLevelUp;
if (userXP + exp >= reqEXP)
{
user.LevelUp();
user.CurrentEXP = exp - (reqEXP - userXP);
//Console.WriteLine("Level up");
Console.WriteLine("Level up");
return true;
}
@@ -50,7 +49,7 @@ namespace EVE_LevelingSystem.LevelingSystemCore
Thread.Sleep(60000 * minutesToWait);
OnWaitingList.Remove(user.user.userID.ToString());
}
).Start();
);
return false;
}

View File

@@ -9,7 +9,5 @@ namespace EVE_LevelingSystem
public class Settings
{
public int TimeToWaitBetweenMessages { get; set; }
public int MinEXP { get; set; }
public int MaxEXP { get; set; }
}
}

View File

@@ -1,34 +0,0 @@
using AngleSharp.Dom;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MusicCommands
{
internal class AudioFile
{
internal string Name { get; set; }
internal string Url { get; set; }
internal AudioFile(string name, string url)
{
Name = name;
Url = url;
}
internal async Task DownloadAudioFile()
{
Process proc = new Process();
proc.StartInfo.FileName = "MusicDownloader.exe";
proc.StartInfo.Arguments = $"{Url},{Name}";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.RedirectStandardOutput = true;
proc.Start();
await proc.WaitForExitAsync();
}
}
}

View File

@@ -8,6 +8,5 @@ internal static class Data
internal static IAudioClient audioClient = null;
internal static IVoiceChannel voiceChannel = null;
internal static MusicPlayer MusicPlayer = null;
internal static MusicPlaylist Playlist = new();
internal static MusicPlayer CurrentlyRunning = null;
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using Discord.Commands;
using Discord.Commands;
using Discord.WebSocket;
using PluginManager.Interfaces;
@@ -9,8 +8,6 @@ internal class Leave : DBCommand
{
public string Command => "leave";
public List<string> Aliases => null;
public string Description => "Leave the voice channel";
public string Usage => "leave";
@@ -25,20 +22,10 @@ internal class Leave : DBCommand
{
if (Data.audioClient is not null && Data.voiceChannel is not null)
{
Data.CurrentlyRunning.Stop();
Data.CurrentlyRunning = null;
await Data.audioClient.StopAsync();
await Data.voiceChannel.DisconnectAsync();
}
if (Data.Playlist is not null)
{
Data.Playlist.ClearQueue();
Data.Playlist = new();
}
if (Data.MusicPlayer is not null)
{
Data.MusicPlayer.Stop();
Data.MusicPlayer = null;
}
}
}

View File

@@ -3,8 +3,7 @@
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>warnings</Nullable>
<BaseOutputPath>bin\</BaseOutputPath>
<AssemblyName>Music Commands</AssemblyName>
<BaseOutputPath>..\DiscordBot\bin\Debug\net6.0\Data\Plugins\Commands\MusicCommands</BaseOutputPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
@@ -18,8 +17,4 @@
<ProjectReference Include="..\PluginManager\PluginManager.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="YoutubeExplode" Version="6.2.0" />
</ItemGroup>
</Project>

View File

@@ -1,53 +1,118 @@
using System.IO;
using System;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using PluginManager.Others;
namespace MusicCommands;
internal class MusicPlayer
{
private Stream outputStream { get; }
internal AudioFile NowPlaying = null;
internal bool isPlaying, isPaused;
public MusicPlayer(Stream outputChannel)
public MusicPlayer(Stream input, Stream output)
{
outputStream = outputChannel;
inputStream = input;
outputStream = output;
}
public async Task Play(Stream source, int byteSize, AudioFile songPlaying)
public MusicPlayer(Stream output)
{
isPlaying = true;
NowPlaying = songPlaying;
while (isPlaying)
{
if (isPaused)
continue;
var bits = new byte[byteSize];
var read = await source.ReadAsync(bits, 0, byteSize);
if (read == 0)
break;
try
{
await outputStream.WriteAsync(bits, 0, read);
}
catch
{
break;
}
}
await source.FlushAsync();
await source.DisposeAsync();
source.Close();
await outputStream.FlushAsync();
isPlaying = false;
inputStream = null;
outputStream = output;
}
public Stream inputStream { get; } // from FFMPEG
public Stream outputStream { get; } // to Voice Channel
public bool Paused { get; set; }
private bool _stop { get; set; }
public void Stop()
{
isPlaying = false;
_stop = true;
}
public async Task StartSendAudioFromLink(string URL)
{
/* using (HttpClient client = new HttpClient())
using (HttpResponseMessage response = await client.GetAsync(URL))
using (var content = response.Content)
{
await (await content.ReadAsStreamAsync()).CopyToAsync(outputStream);
}*/
Stream ms = new MemoryStream();
var bsize = 512;
new Thread(async delegate(object o)
{
var response = await new HttpClient().GetAsync(URL);
using (var stream = await response.Content.ReadAsStreamAsync())
{
var buffer = new byte[bsize];
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
{
var pos = ms.Position;
ms.Position = ms.Length;
ms.Write(buffer, 0, read);
ms.Position = pos;
}
}
}
).Start();
Console.Write("Reading data: ");
while (ms.Length < bsize * 10)
{
await Task.Delay(1000);
Console.Title = "Reading data: " + ms.Length + " bytes read of " + bsize * 10;
Console.Write(".");
}
Console.WriteLine("\nDone");
ms.Position = 0;
_stop = false;
Paused = false;
while (!_stop)
{
if (Paused) continue;
var buffer = new byte[bsize];
var read = await ms.ReadAsync(buffer, 0, buffer.Length);
if (read > 0)
await outputStream.WriteAsync(buffer, 0, read);
else
break;
}
}
public async Task StartSendAudio()
{
Paused = false;
_stop = false;
while (!_stop)
{
if (Paused) continue;
var bsize = 512;
var buffer = new byte[bsize];
var bcount = await inputStream.ReadAsync(buffer, 0, bsize);
if (bcount <= 0)
{
Stop();
Data.CurrentlyRunning = null;
break;
}
try
{
await outputStream.WriteAsync(buffer, 0, bcount);
}
catch (Exception ex)
{
await outputStream.FlushAsync();
Functions.WriteLogFile(ex.ToString());
}
}
}
}

View File

@@ -1,25 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MusicCommands
{
internal class MusicPlaylist
{
internal MusicPlaylist()
{
Console.WriteLine("Initialized playlist.");
}
public Queue<AudioFile> QueueList = new();
public void Enqueue(AudioFile query) => QueueList.Enqueue(query);
public void ClearQueue() => QueueList.Clear();
public int Count => QueueList.Count;
public AudioFile GetNextSong => QueueList.Dequeue();
public AudioFile WhatIsNext => QueueList.Peek();
}
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using Discord.Commands;
using Discord.Commands;
using Discord.WebSocket;
using PluginManager.Interfaces;
@@ -9,9 +8,7 @@ internal class Pause : DBCommand
{
public string Command => "pause";
public List<string> Aliases => null;
public string Description => "Pause/Unpause the music that is currently running";
public string Description => "Pause the music";
public string Usage => "pause";
@@ -23,6 +20,6 @@ internal class Pause : DBCommand
public void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
{
Data.MusicPlayer.isPaused = !Data.MusicPlayer.isPaused;
Data.CurrentlyRunning.Paused = true;
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Discord;
@@ -13,13 +12,11 @@ namespace MusicCommands;
internal class Play : DBCommand
{
public string Command => "play";
public List<string> Aliases => new() { "p" };
public string Command => "fplay";
public string Description => "Play music from a file";
public string Usage => "play [name/url]";
public string Usage => "fplay [name]";
public bool canUseDM => false;
@@ -29,90 +26,36 @@ internal class Play : DBCommand
public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
{
Directory.CreateDirectory("Music");
var path = "./Music/";
string[] splitted = message.Content.Split(' ');
if (splitted.Length < 2)
return;
do
var path = "./Music";
var FileName = Functions.GetArguments(message).ToArray().MergeStrings(0);
path += "/" + FileName + ".ogg";
if (!File.Exists(path))
{
if (splitted.Length == 2 && splitted[1].Contains("youtube.com") || splitted[1].Contains("youtu.be"))
{
var url = splitted[1];
path += $"{Functions.CreateMD5(url)}";
if (File.Exists(path))
{
Data.Playlist.Enqueue(new AudioFile(path, null));
}
else
{
var file = new AudioFile(path, url);
await file.DownloadAudioFile();
Data.Playlist.Enqueue(file);
}
}
else
{
var searchString = splitted.MergeStrings(1);
path += $"{Functions.CreateMD5(searchString)}";
if (File.Exists(path))
{
Data.Playlist.Enqueue(new AudioFile(path, null));
}
else
{
await context.Channel.SendMessageAsync("Searching for " + searchString);
var file = new AudioFile(path, searchString);
await file.DownloadAudioFile();
Data.Playlist.Enqueue(file);
if (Data.MusicPlayer is null)
await context.Channel.SendMessageAsync("Playing: " + searchString);
}
}
if (Data.MusicPlayer is not null)
{
await context.Channel.SendMessageAsync("Queued your request: " + splitted.MergeStrings(1));
return;
}
Console.WriteLine("Unknown path " + path);
return;
}
while (false); // run only one time !
Data.voiceChannel = (context.User as IGuildUser)?.VoiceChannel;
if (Data.voiceChannel == null)
{
await context.Channel.SendMessageAsync("User must be in a voice channel, or a voice channel must be passed as an argument.");
return;
}
if (Data.audioClient is null)
Data.audioClient = await Data.voiceChannel.ConnectAsync();
using (var ffmpeg = CreateStream(path))
using (var output = ffmpeg.StandardOutput.BaseStream)
using (var discord = Data.audioClient.CreatePCMStream(AudioApplication.Mixed))
{
Data.audioClient = await Data.voiceChannel.ConnectAsync(true);
Data.MusicPlayer = null;
}
using (var discordChanneAudioOutStream = Data.audioClient.CreatePCMStream(AudioApplication.Mixed))
{
Data.MusicPlayer ??= new MusicPlayer(discordChanneAudioOutStream);
while (Data.Playlist.Count > 0)
{
var nowPlaying = Data.Playlist.GetNextSong;
using (var ffmpeg = CreateStream(nowPlaying.Name))
using (var ffmpegOutputBaseStream = ffmpeg.StandardOutput.BaseStream)
{
await Data.MusicPlayer.Play(ffmpegOutputBaseStream, 1024, nowPlaying);
Console.WriteLine("Finished playing from " + nowPlaying.Url);
}
}
Data.MusicPlayer = null;
if (Data.CurrentlyRunning != null) Data.CurrentlyRunning.Stop();
Data.CurrentlyRunning = new MusicPlayer(output, discord);
await Data.CurrentlyRunning.StartSendAudio();
}
}
private static Process CreateStream(string path)
private Process CreateStream(string path)
{
return Process.Start(new ProcessStartInfo { FileName = "ffmpeg", Arguments = $"-hide_banner -loglevel panic -i \"{path}\" -ac 2 -f s16le -ar 48000 pipe:1", UseShellExecute = false, RedirectStandardOutput = true });
}

View File

@@ -1,42 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using Discord.WebSocket;
using PluginManager.Interfaces;
namespace MusicCommands
{
public class Skip : DBCommand
{
public string Command => "skip";
public List<string> Aliases => null;
public string Description => "skip the music that is currently running";
public string Usage => "skip";
public bool canUseDM => false;
public bool canUseServer => true;
public bool requireAdmin => false;
public void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
{
var loadedSong = Data.MusicPlayer.NowPlaying;
if (loadedSong is null || Data.MusicPlayer.isPlaying == false)
{
message.Channel.SendMessageAsync("There is no music playing");
return;
}
Data.MusicPlayer.isPlaying = false;
message.Channel.SendMessageAsync($"You have skipped {loadedSong.Name}");
}
}
}

25
MusicCommands/Unpause.cs Normal file
View File

@@ -0,0 +1,25 @@
using Discord.Commands;
using Discord.WebSocket;
using PluginManager.Interfaces;
namespace MusicCommands;
internal class Unpause : DBCommand
{
public string Command => "unpause";
public string Description => "Unpause the music";
public string Usage => "unpause";
public bool canUseDM => false;
public bool canUseServer => true;
public bool requireAdmin => false;
public void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
{
Data.CurrentlyRunning.Paused = false;
}
}

49
MusicCommands/lplay.cs Normal file
View File

@@ -0,0 +1,49 @@
using Discord;
using Discord.Audio;
using Discord.Commands;
using Discord.WebSocket;
using PluginManager.Interfaces;
namespace MusicCommands;
internal class lplay : DBCommand
{
public string Command => "lplay";
public string Description => "Play music from a link";
public string Usage => "lplay [url]";
public bool canUseDM => false;
public bool canUseServer => false;
public bool requireAdmin => false;
public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
{
var URL = message.Content.Split(' ')[1];
if (!URL.EndsWith(".mp3") && !URL.EndsWith(".wav") && !URL.EndsWith(".flac") && !URL.EndsWith(".ogg"))
{
await message.Channel.SendMessageAsync("Invalid URL");
return;
}
Data.voiceChannel = (context.User as IGuildUser)?.VoiceChannel;
if (Data.voiceChannel == null)
{
await context.Channel.SendMessageAsync("User must be in a voice channel, or a voice channel must be passed as an argument.");
return;
}
Data.audioClient = await Data.voiceChannel.ConnectAsync();
using (var discord = Data.audioClient.CreatePCMStream(AudioApplication.Mixed))
{
await message.Channel.SendMessageAsync("Loading...");
Data.CurrentlyRunning = new MusicPlayer(discord);
await Data.CurrentlyRunning.StartSendAudioFromLink(URL);
}
}
}

View File

@@ -1,32 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using Discord.WebSocket;
using PluginManager.Interfaces;
namespace MusicCommands
{
public class queue : DBCommand
{
public string Command => "queue";
public List<string> Aliases => new() { "q" };
public string Description => "check queue";
public string Usage => "queue";
public bool canUseDM => false;
public bool canUseServer => true;
public bool requireAdmin => false;
public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
{
await context.Channel.SendMessageAsync($"You have {Data.Playlist.Count} items in queue");
}
}
}

View File

@@ -4,24 +4,22 @@ using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading;
using Newtonsoft.Json.Linq;
namespace PluginManager
{
internal class AppConfig
{
public Dictionary<string, object>? ApplicationVariables { get; init; }
public List<string>? ProtectedKeyWords { get; init; }
public Dictionary<string, string> PluginVersions { get; init; }
public Dictionary<string, object>? ApplicationVariables { get; set; }
public List<string>? ProtectedKeyWords { get; set; }
}
public static class Config
{
public static class PluginConfig
{
public static readonly List<Tuple<string, PluginType>> InstalledPlugins = new();
public static List<Tuple<string, PluginType>> InstalledPlugins = new();
public static void Load()
{
@@ -31,27 +29,27 @@ namespace PluginManager
private static void LoadCommands()
{
string cmd_path = "./Data/Plugins/Commands/";
string[] files = Directory.GetFiles(cmd_path, $"*.{Loaders.PluginLoader.pluginCMDExtension}", SearchOption.AllDirectories);
string cmd_path = "./Data/Plugins/Commands/";
string[] files = Directory.GetFiles(cmd_path, $"*.{Loaders.PluginLoader.pluginCMDExtension}", SearchOption.AllDirectories);
foreach (var file in files)
if (!file.Contains("PluginManager", StringComparison.InvariantCultureIgnoreCase))
{
string PluginName = new FileInfo(file).Name;
string name = PluginName.Substring(0, PluginName.Length - 1 - PluginManager.Loaders.PluginLoader.pluginCMDExtension.Length);
string name = PluginName.Substring(0, PluginName.Length - 1 - PluginManager.Loaders.PluginLoader.pluginCMDExtension.Length);
InstalledPlugins.Add(new(name, PluginType.Command));
}
}
private static void LoadEvents()
{
string eve_path = "./Data/Plugins/Events/";
string[] files = Directory.GetFiles(eve_path, $"*.{Loaders.PluginLoader.pluginEVEExtension}", SearchOption.AllDirectories);
string eve_path = "./Data/Plugins/Events/";
string[] files = Directory.GetFiles(eve_path, $"*.{Loaders.PluginLoader.pluginEVEExtension}", SearchOption.AllDirectories);
foreach (var file in files)
if (!file.Contains("PluginManager", StringComparison.InvariantCultureIgnoreCase))
if (!file.Contains("PluginManager", StringComparison.InvariantCultureIgnoreCase))
{
string PluginName = new FileInfo(file).Name;
string name = PluginName.Substring(0, PluginName.Length - 1 - PluginManager.Loaders.PluginLoader.pluginEVEExtension.Length);
string name = PluginName.Substring(0, PluginName.Length - 1 - PluginManager.Loaders.PluginLoader.pluginEVEExtension.Length);
InstalledPlugins.Add(new(name, PluginType.Event));
}
}
@@ -69,9 +67,9 @@ namespace PluginManager
public static PluginType GetPluginType(string pluginName)
{
foreach (var tuple in InstalledPlugins)
if (tuple.Item1 == pluginName)
return tuple.Item2;
{
if (tuple.Item1 == pluginName) return tuple.Item2;
}
return PluginType.Unknown;
}
@@ -79,56 +77,20 @@ namespace PluginManager
private static AppConfig? appConfig { get; set; }
public static string GetPluginVersion(string pluginName) => appConfig.PluginVersions[pluginName];
public static void SetPluginVersion(string pluginName, string newVersion)
public static bool AddValueToVariables<T>(string key, T value, bool isProtected)
{
if (appConfig.PluginVersions.ContainsKey(pluginName))
appConfig.PluginVersions[pluginName] = newVersion;
else appConfig.PluginVersions.Add(pluginName, newVersion);
// SaveConfig();
}
public static void RemovePluginVersion(string pluginName) => appConfig.PluginVersions.Remove(pluginName);
public static bool PluginVersionsContainsKey(string pluginName) => appConfig.PluginVersions.ContainsKey(pluginName);
public static void AddValueToVariables<T>(string key, T value, bool isProtected)
{
if (value == null)
throw new Exception("The value cannot be null");
if (appConfig!.ApplicationVariables!.ContainsKey(key))
throw new Exception($"The key ({key}) already exists in the variables. Value {GetValue<T>(key)}");
if (appConfig!.ApplicationVariables!.ContainsKey(key)) return false;
if (value == null) return false;
appConfig.ApplicationVariables.Add(key, value);
if (isProtected && key != "Version")
appConfig.ProtectedKeyWords!.Add(key);
if (isProtected && key != "Version") appConfig.ProtectedKeyWords!.Add(key);
SaveConfig();
}
public static Type GetVariableType(string value)
{
if (int.TryParse(value, out var intValue))
return typeof(int);
if (bool.TryParse(value, out var boolValue))
return typeof(bool);
if (float.TryParse(value, out var floatValue))
return typeof(float);
if (double.TryParse(value, out var doubleValue))
return typeof(double);
if (uint.TryParse(value, out var uintValue))
return typeof(uint);
if (long.TryParse(value, out var longValue))
return typeof(long);
if (byte.TryParse(value, out var byteValue))
return typeof(byte);
return typeof(string);
return true;
}
public static void GetAndAddValueToVariable(string key, string value, bool isReadOnly)
{
if (Config.ContainsKey(key))
return;
if (Config.ContainsKey(key)) return;
if (int.TryParse(value, out var intValue))
Config.AddValueToVariables(key, intValue, isReadOnly);
else if (bool.TryParse(value, out var boolValue))
@@ -161,26 +123,24 @@ namespace PluginManager
}
}
public static void SetValue<T>(string key, T value)
public static bool SetValue<T>(string key, T value)
{
if (value == null)
throw new Exception("Value is null");
if (!appConfig!.ApplicationVariables!.ContainsKey(key))
throw new Exception("Key does not exist in the config file");
if (appConfig.ProtectedKeyWords!.Contains(key))
throw new Exception("Key is protected");
if (!appConfig!.ApplicationVariables!.ContainsKey(key)) return false;
if (appConfig.ProtectedKeyWords!.Contains(key)) return false;
if (value == null) return false;
appConfig.ApplicationVariables[key] = JsonSerializer.SerializeToElement(value);
SaveConfig();
return true;
}
public static void RemoveKey(string key)
public static bool RemoveKey(string key)
{
if (key == "Version" || key == "token" || key == "prefix")
throw new Exception("Key is protected");
if (key == "Version" || key == "token" || key == "prefix") return false;
appConfig!.ApplicationVariables!.Remove(key);
appConfig.ProtectedKeyWords!.Remove(key);
SaveConfig();
return true;
}
public static async void SaveConfig()
@@ -198,12 +158,12 @@ namespace PluginManager
Functions.WriteLogFile($"Loaded {appConfig.ApplicationVariables!.Keys.Count} application variables.\nLoaded {appConfig.ProtectedKeyWords!.Count} readonly variables.");
}
else
appConfig = new() { ApplicationVariables = new Dictionary<string, object>(), ProtectedKeyWords = new List<string>(), PluginVersions = new Dictionary<string, string>() };
appConfig = new() { ApplicationVariables = new Dictionary<string, object>(), ProtectedKeyWords = new List<string>() };
}
public static bool ContainsValue<T>(T value) => appConfig!.ApplicationVariables!.ContainsValue(value!);
public static bool ContainsKey(string key) => appConfig!.ApplicationVariables!.ContainsKey(key);
public static bool ContainsKey(string key) => appConfig!.ApplicationVariables!.ContainsKey(key);
public static ReadOnlyDictionary<string, object> GetAllVariables() => new(appConfig!.ApplicationVariables!);
public static Dictionary<string, object> GetAllVariables() => new(appConfig!.ApplicationVariables!);
}
}

View File

@@ -1,5 +1,4 @@
using System.Collections.Generic;
using Discord.Commands;
using Discord.Commands;
using Discord.WebSocket;
namespace PluginManager.Interfaces;
@@ -12,11 +11,6 @@ public interface DBCommand
/// </summary>
string Command { get; }
/// <summary>
/// Command aliases. Users may use this to execute the command
/// </summary>
List<string>? Aliases { get; }
/// <summary>
/// Command description
/// </summary>
@@ -50,5 +44,8 @@ public interface DBCommand
/// <param name="message">The message that the user types</param>
/// <param name="client">The discord client of the bot</param>
/// <param name="isDM">true if the message was sent from DM, otherwise false. It is always false if canUseDM is false</param>
void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM);
void Execute(SocketCommandContext context,
SocketMessage message,
DiscordSocketClient client,
bool isDM);
}

View File

@@ -1,12 +1,11 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Discord.WebSocket;
using PluginManager.Others;
namespace PluginManager.Items;
public class Command
internal class Command
{
/// <summary>
/// The author of the command
@@ -21,7 +20,10 @@ public class Command
{
Author = message.Author;
var data = message.Content.Split(' ');
Arguments = data.Length > 1 ? new List<string>(data.MergeStrings(1).Split(' ')) : new List<string>();
if (data.Length > 1)
Arguments = new List<string>(data.MergeStrings(1).Split(' '));
else
Arguments = new List<string>();
CommandName = data[0].Substring(1);
PrefixUsed = data[0][0];
}
@@ -44,8 +46,8 @@ public class Command
public class ConsoleCommand
{
public string CommandName { get; init; }
public string Description { get; init; }
public string Usage { get; init; }
public Action<string[]> Action { get; init; }
public string CommandName { get; set; }
public string Description { get; set; }
public string Usage { get; set; }
public Action<string[]> Action { get; set; }
}

View File

@@ -1,43 +1,33 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using Discord.WebSocket;
using PluginManager.Interfaces;
using PluginManager.Loaders;
using PluginManager.Online;
using PluginManager.Online.Helpers;
using PluginManager.Online.Updates;
using PluginManager.Others;
namespace PluginManager.Items;
public class ConsoleCommandsHandler
{
private static readonly PluginsManager manager = new("https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/Plugins.txt");
private static readonly List<ConsoleCommand> commandList = new();
private readonly DiscordSocketClient? client;
private static bool isDownloading = false;
private static bool pluginsLoaded = false;
private static readonly PluginsManager manager = new("https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/Plugins.txt");
public static List<ConsoleCommand> commandList = new();
private readonly DiscordSocketClient? client;
public ConsoleCommandsHandler(DiscordSocketClient client)
{
this.client = client;
InitializeBasicCommands();
//Console.WriteLine("Initialized console command handler !");
Console.WriteLine("Initialized console command handler !");
}
private void InitializeBasicCommands()
{
var pluginsLoaded = false;
commandList.Clear();
AddCommand("help", "Show help", "help <command>", args =>
@@ -53,12 +43,14 @@ public class ConsoleCommandsHandler
foreach (var command in commandList)
{
var pa = from p in command.Action.Method.GetParameters() where p.Name != null select p.ParameterType.FullName;
var pa = from p in command.Action.Method.GetParameters()
where p.Name != null
select p.ParameterType.FullName;
items.Add(new[] { command.CommandName, command.Description, command.Usage });
}
items.Add(new[] { "-", "-", "-" });
Console_Utilities.FormatAndAlignTable(items, TableFormat.DEFAULT);
Console_Utilities.FormatAndAlignTable(items);
}
else
{
@@ -78,14 +70,12 @@ public class ConsoleCommandsHandler
AddCommand("lp", "Load plugins", () =>
{
if (pluginsLoaded)
return;
if (pluginsLoaded) return;
var loader = new PluginLoader(client!);
loader.onCMDLoad += (name, typeName, success, exception) =>
{
Console.ForegroundColor = ConsoleColor.Green;
if (name == null || name.Length < 2)
name = typeName;
if (name == null || name.Length < 2) name = typeName;
if (success)
Console.WriteLine("[CMD] Successfully loaded command : " + name);
else
@@ -94,8 +84,7 @@ public class ConsoleCommandsHandler
};
loader.onEVELoad += (name, typeName, success, exception) =>
{
if (name == null || name.Length < 2)
name = typeName;
if (name == null || name.Length < 2) name = typeName;
Console.ForegroundColor = ConsoleColor.Green;
if (success)
Console.WriteLine("[EVENT] Successfully loaded event : " + name);
@@ -108,14 +97,12 @@ public class ConsoleCommandsHandler
}
);
AddCommand("listplugs", "list available plugins", () => { manager.ListAvailablePlugins().Wait(); });
AddCommand("listplugs", "list available plugins", async () => { await manager.ListAvailablePlugins(); });
AddCommand("dwplug", "download plugin", "dwplug [name]", async args =>
{
isDownloading = true;
if (args.Length == 1)
{
isDownloading = false;
Console.WriteLine("Please specify plugin name");
return;
}
@@ -129,27 +116,26 @@ public class ConsoleCommandsHandler
{
if (name == "")
{
isDownloading = false;
Console_Utilities.WriteColorText("Name is invalid");
return;
}
isDownloading = false;
Console_Utilities.WriteColorText($"Failed to find plugin &b{name} &c!" + " Use &glistplugs &ccommand to display all available plugins !");
Console_Utilities.WriteColorText($"Failed to find plugin &b{name} &c!" +
" Use &glistplugs &ccommand to display all available plugins !"
);
return;
}
string path;
if (info[0] == "Command" || info[0] == "Event")
path = "./Data/Plugins/" + info[0] + "s/" + name + "." + (info[0] == "Command" ? PluginLoader.pluginCMDExtension : PluginLoader.pluginEVEExtension);
path = "./Data/Plugins/" + info[0] + "s/" + name + ".dll";
else
path = $"./{info[1].Split('/')[info[1].Split('/').Length - 1]}";
//Console.WriteLine("Downloading: " + path + " [" + info[1] + "]");
await ServerCom.DownloadFileAsync(info[1], path);
if (info[0] == "Command" || info[0] == "Event")
if (info[0] == "Event")
Config.PluginConfig.InstalledPlugins.Add(new(name, PluginType.Event));
else if (info[0] == "Command")
Config.PluginConfig.InstalledPlugins.Add(new(name, PluginType.Command));
else if (info[0] == "Command") Config.PluginConfig.InstalledPlugins.Add(new(name, PluginType.Command));
Console.WriteLine("\n");
@@ -160,39 +146,37 @@ public class ConsoleCommandsHandler
{
Console.WriteLine($"Downloading requirements for plugin : {name}");
var lines = await ServerCom.ReadTextFromURL(info[2]);
var lines = await ServerCom.ReadTextFromFile(info[2]);
foreach (var line in lines)
{
if (!(line.Length > 0 && line.Contains(",")))
continue;
if (!(line.Length > 0 && line.Contains(","))) continue;
var split = line.Split(',');
Console.WriteLine($"\nDownloading item: {split[1]}");
await ServerCom.DownloadFileAsync(split[0], "./" + split[1]);
Console.WriteLine();
if (split[0].EndsWith(".zip") || split[0].EndsWith(".pak") || split[0].EndsWith(".pkg"))
if (split[0].EndsWith(".zip"))
{
Console.WriteLine($"Extracting {split[1]}");
var proc = 0f;
var proc = 0d;
var isExtracting = true;
var bar = new Console_Utilities.ProgressBar { Max = 100f, Color = ConsoleColor.Green };
var bar = new Console_Utilities.ProgressBar { Max = 100, Color = ConsoleColor.Green };
IProgress<float> extractProgress = new Progress<float>(value => { proc = value; });
new Thread(new Task(() =>
{
while (isExtracting)
{
bar.Update(proc);
if (proc >= 99.9f)
isExtracting = false;
bar.Update((int)proc);
if (proc >= 99.9f) break;
Thread.Sleep(500);
}
}
).Start
).Start();
await Functions.ExtractArchive("./" + split[1], "./", extractProgress, UnzipProgressType.PercentageFromTotalSize);
bar.Update(100f);
await Functions.ExtractArchive("./" + split[1], "./", extractProgress);
bar.Update(100);
isExtracting = false;
await Task.Delay(1000);
bar.Update(100);
@@ -203,34 +187,25 @@ public class ConsoleCommandsHandler
Console.WriteLine();
}
VersionString? ver = await VersionString.GetVersionOfPackageFromWeb(name);
if (ver is null) throw new Exception("Incorrect version");
Config.SetPluginVersion(name, $"{ver.PackageID}.{ver.PackageMainVersion}.{ver.PackageCheckVersion}");
// Console.WriteLine();
isDownloading = false;
}
);
AddCommand("value", "read value from VariableStack", "value [key]", args =>
AddCommand("value", "read value from VariableStack", "value [key]",args =>
{
if (args.Length != 2)
return;
if (!Config.ContainsKey(args[1]))
return;
if (args.Length != 2) return;
if (!Config.ContainsKey(args[1])) return;
var data = Config.GetValue<string>(args[1]);
Console.WriteLine($"{args[1]} => {data}");
}
);
AddCommand("add", "add variable to the system variables", "add [key] [value] [isReadOnly=true/false]", args =>
AddCommand("add", "add variable to the system variables","add [key] [value] [isReadOnly=true/false]", args =>
{
if (args.Length < 4)
return;
var key = args[1];
var value = args[2];
if (args.Length < 4) return;
var key = args[1];
var value = args[2];
var isReadOnly = args[3].Equals("true", StringComparison.CurrentCultureIgnoreCase);
try
@@ -247,60 +222,46 @@ public class ConsoleCommandsHandler
AddCommand("remv", "remove variable from system variables", "remv [key]", args =>
{
if (args.Length < 2)
return;
if (args.Length < 2) return;
Config.RemoveKey(args[1]);
}
);
AddCommand("sd", "Shuts down the discord bot", () =>
AddCommand("vars", "Display all variables", () =>
{
if (client is null)
return;
client.StopAsync();
client.DisposeAsync();
Config.SaveConfig();
Console.WriteLine("Bot is closing in 2 seconds ! Please wait to save data !");
Thread.Sleep(2000);
Environment.Exit(0);
var d = Config.GetAllVariables();
var data = new List<string[]>();
data.Add(new[] { "-", "-" });
data.Add(new[] { "Key", "Value" });
data.Add(new[] { "-", "-" });
foreach (var kvp in d) data.Add(new[] { kvp.Key, kvp.Value.ToString()! });
data.Add(new[] { "-", "-" });
Console_Utilities.FormatAndAlignTable(data);
}
);
AddCommand("extern", "Load an external command", "extern [pluginName]", async (args) =>
{
if (args.Length <= 1) return;
string pName = Functions.MergeStrings(args, 1);
HttpClient client = new HttpClient();
string url = (await manager.GetPluginLinkByName(pName))[1];
Stream s = await client.GetStreamAsync(url);
MemoryStream str = new MemoryStream();
await s.CopyToAsync(str);
var asmb = Assembly.Load(str.ToArray());
var types = asmb.GetTypes();
foreach (var type in types)
AddCommand("sd", "Shuts down the discord bot", async () =>
{
if (type.IsClass && typeof(DBEvent).IsAssignableFrom(type))
{
DBEvent instance = (DBEvent)Activator.CreateInstance(type);
instance.Start(this.client);
Console.WriteLine($"Loaded external {type.FullName}!");
}
else if (type.IsClass && typeof(DBCommand).IsAssignableFrom(type))
{
Console.WriteLine("Only events can be loaded from external sources !");
return;
}
if (client is null) return;
await client.StopAsync();
await client.DisposeAsync();
Config.SaveConfig();
Environment.Exit(0);
}
});
);
//Sort the commands by name
commandList.Sort((x, y) => x.CommandName.CompareTo(y.CommandName));
}
public static void AddCommand(string command, string description, string usage, Action<string[]> action)
{
commandList.Add(new ConsoleCommand { CommandName = command, Description = description, Action = action, Usage = usage });
commandList.Add(new ConsoleCommand
{
CommandName = command,
Description = description,
Action = action,
Usage = usage
});
Console.ForegroundColor = ConsoleColor.White;
Console_Utilities.WriteColorText($"Command &r{command} &cadded to the list of commands");
}
@@ -317,7 +278,7 @@ public class ConsoleCommandsHandler
public static bool CommandExists(string command)
{
return GetCommand(command) is not null;
return !(GetCommand(command) is null);
}
public static ConsoleCommand? GetCommand(string command)
@@ -325,23 +286,8 @@ public class ConsoleCommandsHandler
return commandList.FirstOrDefault(t => t.CommandName == command);
}
internal static async Task ExecuteCommad(string command)
{
var args = command.Split(' ');
foreach (var item in commandList.ToList())
if (item.CommandName == args[0])
{
item.Action.Invoke(args);
Console.WriteLine();
while (isDownloading) await Task.Delay(1000);
}
}
public bool HandleCommand(string command, bool removeCommandExecution = true)
{
Console.ForegroundColor = ConsoleColor.White;
var args = command.Split(' ');
foreach (var item in commandList.ToList())
if (item.CommandName == args[0])
@@ -349,14 +295,12 @@ public class ConsoleCommandsHandler
if (removeCommandExecution)
{
Console.SetCursorPosition(0, Console.CursorTop - 1);
for (int i = 0; i < command.Length + 30; i++)
Console.Write(" ");
for (int i = 0; i < command.Length; i++) Console.Write(" ");
Console.SetCursorPosition(0, Console.CursorTop);
}
Console.WriteLine();
item.Action(args);
return true;
}

View File

@@ -3,32 +3,29 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using PluginManager.Online.Updates;
using PluginManager.Others;
namespace PluginManager.Loaders;
internal class LoaderArgs : EventArgs
{
internal string? PluginName { get; init; }
internal string? TypeName { get; init; }
internal bool IsLoaded { get; init; }
internal Exception? Exception { get; init; }
internal object? Plugin { get; init; }
internal string? PluginName { get; init; }
internal string? TypeName { get; init; }
internal bool IsLoaded { get; init; }
internal Exception? Exception { get; init; }
internal object? Plugin { get; init; }
}
internal class Loader<T>
{
internal Loader(string path, string extension)
{
this.path = path;
this.path = path;
this.extension = extension;
}
private string path { get; }
private string path { get; }
private string extension { get; }
@@ -52,17 +49,16 @@ internal class Loader<T>
var files = Directory.GetFiles(path, $"*.{extension}", SearchOption.AllDirectories);
foreach (var file in files)
{
Assembly.LoadFrom(file);
if (FileLoaded != null)
{
var args = new LoaderArgs
{
Exception = null,
TypeName = nameof(T),
IsLoaded = false,
PluginName = new FileInfo(file).Name.Split('.')[0],
Plugin = null
Exception = null,
TypeName = nameof(T),
IsLoaded = false,
PluginName = file,
Plugin = null
};
FileLoaded.Invoke(args);
}
@@ -87,13 +83,13 @@ internal class Loader<T>
if (PluginLoaded != null)
PluginLoaded.Invoke(new LoaderArgs
{
Exception = null,
IsLoaded = true,
PluginName = type.FullName,
TypeName = nameof(T),
Plugin = plugin
}
{
Exception = null,
IsLoaded = true,
PluginName = type.FullName,
TypeName = nameof(T),
Plugin = plugin
}
);
}
catch (Exception ex)

View File

@@ -1,15 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using Discord.WebSocket;
using PluginManager.Interfaces;
using PluginManager.Online.Helpers;
using PluginManager.Online.Updates;
using PluginManager.Others;
namespace PluginManager.Loaders;
@@ -23,8 +15,8 @@ public class PluginLoader
private const string pluginCMDFolder = @"./Data/Plugins/Commands/";
private const string pluginEVEFolder = @"./Data/Plugins/Events/";
internal const string pluginCMDExtension = "dll";
internal const string pluginEVEExtension = "dll";
internal const string pluginCMDExtension = "dll";
internal const string pluginEVEExtension = "dll";
private readonly DiscordSocketClient _client;
/// <summary>
@@ -60,97 +52,42 @@ public class PluginLoader
/// <summary>
/// The main mathod that is called to load all events
/// </summary>
public async void LoadPlugins()
public void LoadPlugins()
{
//Check for updates in commands
foreach (var file in Directory.GetFiles("./Data/Plugins/Commands", $"*.{pluginCMDExtension}", SearchOption.AllDirectories))
{
await Task.Run(async () =>
{
string name = new FileInfo(file).Name.Split('.')[0];
if (!Config.PluginVersionsContainsKey(name))
Config.SetPluginVersion(name, (await VersionString.GetVersionOfPackageFromWeb(name))?.PackageID + ".0.0");
if (await PluginUpdater.CheckForUpdates(name))
await PluginUpdater.Download(name);
});
}
//Check for updates in events
foreach (var file in Directory.GetFiles("./Data/Plugins/Events", $"*.{pluginEVEExtension}", SearchOption.AllDirectories))
{
await Task.Run(async () =>
{
string name = new FileInfo(file).Name.Split('.')[0];
if (!Config.PluginVersionsContainsKey(name))
Config.SetPluginVersion(name, (await VersionString.GetVersionOfPackageFromWeb(name))?.PackageID + ".0.0");
if (await PluginUpdater.CheckForUpdates(name))
await PluginUpdater.Download(name);
});
}
//Save the new config file (after the updates)
Config.SaveConfig();
//Load all plugins
Commands = new List<DBCommand>();
Events = new List<DBEvent>();
Events = new List<DBEvent>();
Functions.WriteLogFile("Starting plugin loader ... Client: " + _client.CurrentUser.Username);
Console.WriteLine("Loading plugins");
var commandsLoader = new Loader<DBCommand>(pluginCMDFolder, pluginCMDExtension);
var eventsLoader = new Loader<DBEvent>(pluginEVEFolder, pluginEVEExtension);
var eventsLoader = new Loader<DBEvent>(pluginEVEFolder, pluginEVEExtension);
commandsLoader.FileLoaded += OnCommandFileLoaded;
commandsLoader.FileLoaded += OnCommandFileLoaded;
commandsLoader.PluginLoaded += OnCommandLoaded;
eventsLoader.FileLoaded += EventFileLoaded;
eventsLoader.FileLoaded += EventFileLoaded;
eventsLoader.PluginLoaded += OnEventLoaded;
Commands = commandsLoader.Load();
Events = eventsLoader.Load();
Events = eventsLoader.Load();
}
private void EventFileLoaded(LoaderArgs e)
{
if (!e.IsLoaded)
{
Functions.WriteLogFile($"[EVENT] Event from file [{e.PluginName}] has been successfully created !");
}
if (e.IsLoaded) Functions.WriteLogFile($"[EVENT] Event from file [{e.PluginName}] has been successfully created !");
}
private void OnCommandFileLoaded(LoaderArgs e)
{
if (!e.IsLoaded)
{
Functions.WriteLogFile($"[CMD] Command from file [{e.PluginName}] has been successfully loaded !");
}
if (e.IsLoaded) Functions.WriteLogFile($"[CMD] Command from file [{e.PluginName}] has been successfully loaded !");
}
private void OnEventLoaded(LoaderArgs e)
{
try
{
if (e.IsLoaded)
((DBEvent)e.Plugin!).Start(_client);
if (e.IsLoaded) ((DBEvent)e.Plugin!).Start(_client);
onEVELoad?.Invoke(((DBEvent)e.Plugin!).name, e.TypeName!, e.IsLoaded, e.Exception);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.WriteLine("Plugin: " + e.PluginName);
Console.WriteLine("Type: " + e.TypeName);
Console.WriteLine("IsLoaded: " + e.IsLoaded);
}
onEVELoad?.Invoke(((DBEvent)e.Plugin!).name, e.TypeName!, e.IsLoaded, e.Exception);
}
private void OnCommandLoaded(LoaderArgs e)

View File

@@ -18,32 +18,32 @@ namespace PluginManager.Online.Helpers
/// <param name="progress">The <see cref="IProgress{T}"/> that is used to track the download progress</param>
/// <param name="cancellation">The cancellation token</param>
/// <returns></returns>
internal static async Task DownloadFileAsync(this HttpClient client, string url, Stream destination, IProgress<float>? progress = null, IProgress<long>? downloadedBytes = null, int bufferSize = 81920, CancellationToken cancellation = default)
internal static async Task DownloadFileAsync(this HttpClient client, string url, Stream destination,
IProgress<float>? progress = null, IProgress<long>? downloadedBytes = null, CancellationToken cancellation = default)
{
using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead, cancellation))
using (var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
{
var contentLength = response.Content.Headers.ContentLength;
using (var download = await response.Content.ReadAsStreamAsync(cancellation))
using (var download = await response.Content.ReadAsStreamAsync())
{
// Ignore progress reporting when no progress reporter was
// passed or when the content length is unknown
if (progress == null || !contentLength.HasValue)
{
await download.CopyToAsync(destination, cancellation);
await download.CopyToAsync(destination);
return;
}
// Convert absolute progress (bytes downloaded) into relative progress (0% - 100%)
var relativeProgress = new Progress<long>(totalBytes =>
{
progress.Report((float)totalBytes / contentLength.Value * 100);
downloadedBytes?.Report(totalBytes);
}
);
{
progress.Report((float)totalBytes / contentLength.Value * 100);
downloadedBytes?.Report(totalBytes);
});
// Use extension method to report progress while downloading
await download.CopyToOtherStreamAsync(destination, bufferSize, relativeProgress, cancellation);
await download.CopyToOtherStreamAsync(destination, 81920, relativeProgress, cancellation);
progress.Report(1);
}
}
@@ -57,8 +57,10 @@ namespace PluginManager.Online.Helpers
/// <returns></returns>
internal static async Task<string> DownloadStringAsync(string url, CancellationToken cancellation = default)
{
using var client = new HttpClient();
return await client.GetStringAsync(url, cancellation);
using (var client = new HttpClient())
{
return await client.GetStringAsync(url);
}
}

View File

@@ -1,82 +0,0 @@
using PluginManager.Others;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
namespace PluginManager.Online.Helpers
{
public class VersionString
{
public int PackageID;
public int PackageMainVersion;
public int PackageCheckVersion;
public VersionString(string version)
{
string[] data = version.Split('.');
try
{
PackageID = int.Parse(data[0]);
PackageMainVersion = int.Parse(data[1]);
PackageCheckVersion = int.Parse(data[2]);
}
catch (Exception ex)
{
throw new Exception("Failed to write Version", ex);
}
}
public static bool operator >(VersionString s1, VersionString s2)
{
if (s1.PackageID != s2.PackageID) throw new Exception("Can not compare two different paks");
if (s1.PackageMainVersion > s2.PackageMainVersion) return true;
if (s1.PackageMainVersion == s2.PackageMainVersion && s1.PackageCheckVersion > s2.PackageCheckVersion) return true;
return false;
}
public static bool operator <(VersionString s1, VersionString s2) => !(s1 > s2) && s1 != s2;
public static bool operator ==(VersionString s1, VersionString s2)
{
if (s1.PackageID == s2.PackageID && s1.PackageMainVersion == s2.PackageMainVersion && s1.PackageCheckVersion == s2.PackageCheckVersion) return true;
return false;
}
public static bool operator !=(VersionString s1, VersionString s2) => !(s1 == s2);
public static bool operator <=(VersionString s1, VersionString s2) => (s1 < s2 || s1 == s2);
public static bool operator >=(VersionString s1, VersionString s2) => (s1 > s2 || s1 == s2);
public override string ToString()
{
return "{PackageID: " + PackageID + ", PackageVersion: " + PackageMainVersion + ", PackageCheckVersion: " + PackageCheckVersion + "}";
}
public string ToShortString()
{
return $"{PackageID}.{PackageMainVersion}.{PackageCheckVersion}";
}
public static VersionString? GetVersionOfPackage(string pakName)
{
if (!Config.PluginVersionsContainsKey(pakName))
return null;
return new VersionString(Config.GetPluginVersion(pakName));
}
public static async Task<VersionString?> GetVersionOfPackageFromWeb(string pakName)
{
string url = "https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/Versions";
List<string> data = await ServerCom.ReadTextFromURL(url);
string? version = (from item in data
where !item.StartsWith("#") && item.StartsWith(pakName)
select item.Split(',')[1]).FirstOrDefault();
if (version == default || version == null) return null;
return new VersionString(version);
}
}
}

View File

@@ -30,7 +30,7 @@ public class PluginsManager
{
try
{
var list = await ServerCom.ReadTextFromURL(PluginsLink);
var list = await ServerCom.ReadTextFromFile(PluginsLink);
var lines = list.ToArray();
var data = new List<string[]>();
@@ -43,8 +43,7 @@ public class PluginsManager
data.Add(new[] { "-", "-", "-", "-", "-" });
for (var i = 0; i < len; i++)
{
if (lines[i].Length <= 2)
continue;
if (lines[i].Length <= 2) continue;
var content = lines[i].Split(',');
var display = new string[titles.Length];
if (op == OperatingSystem.WINDOWS)
@@ -55,7 +54,7 @@ public class PluginsManager
display[1] = content[1];
display[2] = content[2];
if (content.Length == 6 && (content[5] != null || content[5].Length > 2))
display[3] = ((await ServerCom.ReadTextFromURL(content[5])).Count + 1).ToString();
display[3] = ((await ServerCom.ReadTextFromFile(content[5])).Count + 1).ToString();
else
display[3] = "1";
@@ -73,8 +72,7 @@ public class PluginsManager
display[0] = content[0];
display[1] = content[1];
display[2] = content[2];
if (content.Length == 6 && (content[5] != null || content[5].Length > 2))
display[3] = ((await ServerCom.ReadTextFromURL(content[5])).Count + 1).ToString();
if (content.Length == 6 && (content[5] != null || content[5].Length > 2)) display[3] = ((await ServerCom.ReadTextFromFile(content[5])).Count + 1).ToString();
if (Config.PluginConfig.Contains(content[0]) || Config.PluginConfig.Contains(content[0]))
display[4] = "✓";
else
@@ -90,7 +88,7 @@ public class PluginsManager
}
catch (Exception exception)
{
Console.WriteLine("Failed to execute command: listplugs\nReason: " + exception.Message);
Console.WriteLine("Failed to execute command: listlang\nReason: " + exception.Message);
Functions.WriteErrFile(exception.ToString());
}
}
@@ -104,7 +102,7 @@ public class PluginsManager
{
try
{
var list = await ServerCom.ReadTextFromURL(PluginsLink);
var list = await ServerCom.ReadTextFromFile(PluginsLink);
var lines = list.ToArray();
var len = lines.Length;
for (var i = 0; i < len; i++)
@@ -112,10 +110,8 @@ public class PluginsManager
var contents = lines[i].Split(',');
if (contents[0] == name)
{
if (contents.Length == 6)
return new[] { contents[2], contents[3], contents[5] };
if (contents.Length == 5)
return new[] { contents[2], contents[3], string.Empty };
if (contents.Length == 6) return new[] { contents[2], contents[3], contents[5] };
if (contents.Length == 5) return new[] { contents[2], contents[3], string.Empty };
throw new Exception("Failed to download plugin. Invalid Argument Length");
}
}

View File

@@ -9,14 +9,15 @@ using PluginManager.Others;
namespace PluginManager.Online
{
public static class ServerCom
public class ServerCom
{
/// <summary>
/// Read all lines from a file async
/// </summary>
/// <param name="link">The link of the file</param>
/// <returns></returns>
public static async Task<List<string>> ReadTextFromURL(string link)
public static async Task<List<string>> ReadTextFromFile(string link)
{
string response = await OnlineFunctions.DownloadStringAsync(link);
string[] lines = response.Split('\n');
@@ -51,12 +52,15 @@ namespace PluginManager.Online
/// <returns></returns>
public static async Task DownloadFileAsync(string URL, string location)
{
bool isDownloading = true;
float c_progress = 0;
bool isDownloading = true;
int c_progress = 0;
Console_Utilities.ProgressBar pbar = new Console_Utilities.ProgressBar { Max = 100f, NoColor = true };
Console_Utilities.ProgressBar pbar = new Console_Utilities.ProgressBar { Max = 100, NoColor = true };
IProgress<float> progress = new Progress<float>(percent => { c_progress = percent; });
IProgress<float> progress = new Progress<float>(percent =>
{
c_progress = (int)percent;
});
Task updateProgressBarTask = new Task(() =>
@@ -64,8 +68,7 @@ namespace PluginManager.Online
while (isDownloading)
{
pbar.Update(c_progress);
if (c_progress == 100f)
break;
if (c_progress == 100) break;
Thread.Sleep(500);
}
}
@@ -75,8 +78,8 @@ namespace PluginManager.Online
await DownloadFileAsync(URL, location, progress);
c_progress = pbar.Max;
pbar.Update(100f);
c_progress = 100;
pbar.Update(100);
isDownloading = false;
}
}

View File

@@ -1,51 +0,0 @@
using PluginManager.Items;
using PluginManager.Online.Helpers;
using PluginManager.Others;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace PluginManager.Online.Updates
{
public class PluginUpdater
{
public static async Task<bool> CheckForUpdates(string pakName)
{
try
{
var webV = await VersionString.GetVersionOfPackageFromWeb(pakName);
var local = VersionString.GetVersionOfPackage(pakName);
if (local is null) return true;
if (webV is null) return false;
if (webV == local) return false;
if (webV > local) return true;
}
catch (Exception ex) { Console.WriteLine(ex.Message); }
return false;
}
public static async Task<Update> DownloadUpdateInfo(string pakName)
{
string url = "https://raw.githubusercontent.com/Wizzy69/installer/discord-bot-files/Versions";
List<string> info = await ServerCom.ReadTextFromURL(url);
VersionString? version = await VersionString.GetVersionOfPackageFromWeb(pakName);
if (version is null) return Update.Empty;
Update update = new Update(pakName, string.Join('\n', info), version);
return update;
}
public static async Task Download(string pakName)
{
Console_Utilities.WriteColorText("An update was found for &g" + pakName + "&c. Version: &r" + (await VersionString.GetVersionOfPackageFromWeb(pakName))?.ToShortString() + "&c. Current Version: &y" + VersionString.GetVersionOfPackage(pakName)?.ToShortString());
await ConsoleCommandsHandler.ExecuteCommad("dwplug " + pakName);
}
}
}

View File

@@ -1,36 +0,0 @@
using PluginManager.Online.Helpers;
namespace PluginManager.Online.Updates
{
public class Update
{
public static Update Empty = new Update(null, null, null);
public string pakName;
public string UpdateMessage;
public VersionString newVersion;
private bool isEmpty;
public Update(string pakName, string updateMessage, VersionString newVersion)
{
this.pakName = pakName;
UpdateMessage = updateMessage;
this.newVersion = newVersion;
if (pakName is null && updateMessage is null && newVersion is null)
isEmpty = true;
}
public override string ToString()
{
if (isEmpty)
throw new System.Exception("The update is EMPTY. Can not print information about an empty update !");
return $"Package Name: {this.pakName}\n" +
$"Update Message: {UpdateMessage}\n" +
$"Version: {newVersion.ToString()}";
}
}
}

View File

@@ -1,43 +1,21 @@
using Discord;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
namespace PluginManager.Others
{
public static class Console_Utilities
public class Console_Utilities
{
public static void Initialize()
{
if (!Config.ContainsKey("TableVariables"))
Config.AddValueToVariables("TableVariables", new Dictionary<string, string> { { "DefaultSpace", "3" } }, false);
if (!Config.ContainsKey("ColorDataBase"))
Config.AddValueToVariables("ColorDataBase", new Dictionary<char, ConsoleColor>()
{
{ 'g', ConsoleColor.Green },
{ 'b', ConsoleColor.Blue },
{ 'r', ConsoleColor.Red },
{ 'm', ConsoleColor.Magenta },
{ 'y', ConsoleColor.Yellow },
}, false
);
if (!Config.ContainsKey("ColorPrefix"))
Config.AddValueToVariables("ColorPrefix", '&', false);
}
/// <summary>
/// Progress bar object
/// </summary>
public class ProgressBar
{
public float Max { get; init; }
public int Max { get; init; }
public ConsoleColor Color { get; init; }
public bool NoColor { get; init; }
public void Update(float progress, double speed = -1, string? unit = null)
public void Update(int progress, double speed = -1, string? unit = null)
{
Console.CursorLeft = 0;
Console.Write("[");
@@ -50,212 +28,129 @@ namespace PluginManager.Others
for (int i = 0; i < onechunk * progress; i++)
{
Console.BackgroundColor = NoColor ? ConsoleColor.Black : this.Color;
if (NoColor)
Console.BackgroundColor = ConsoleColor.Black; //this.Color
else
Console.BackgroundColor = this.Color;
Console.CursorLeft = position++;
Console.Write("#");
}
for (int i = position; i <= 31; i++)
{
Console.BackgroundColor = NoColor ? ConsoleColor.Black : ConsoleColor.DarkGray;
if (NoColor)
Console.BackgroundColor = ConsoleColor.Black; // background of empty bar
else
Console.BackgroundColor = ConsoleColor.DarkGray;
Console.CursorLeft = position++;
Console.Write(" ");
}
Console.CursorLeft = 35;
Console.BackgroundColor = ConsoleColor.Black;
if (speed is -1 || unit == null)
if (speed == -1 || unit == null)
{
if (progress.CanAproximateTo(Max))
Console.Write(progress + " % ✓");
else
Console.Write(MathF.Round(progress, 2) + " % ");
if (progress == Max)
Console.Write(progress.ToString() + " % ✓");
else Console.Write(progress.ToString() + " % ");
}
else
Console.Write(progress + $"{speed} {unit}/s ");
Console.Write(progress.ToString() + $"{speed} {unit}/s ");
}
}
private static bool CanAproximateTo(this float f, float y) => (MathF.Abs(f - y) < 0.000001);
/// <summary>
/// A way to create a table based on input data
/// </summary>
/// <param name="data">The List of arrays of strings that represent the rows.</param>
public static void FormatAndAlignTable(List<string[]> data, TableFormat format = TableFormat.CENTER_EACH_COLUMN_BASED)
public static void FormatAndAlignTable(List<string[]> data)
{
if (format == TableFormat.CENTER_EACH_COLUMN_BASED)
char tableLine = '-';
char tableCross = '+';
char tableWall = '|';
int[] len = new int[data[0].Length];
foreach (var line in data)
{
char tableLine = '-';
char tableCross = '+';
char tableWall = '|';
int[] len = new int[data[0].Length];
foreach (var line in data)
for (int i = 0; i < line.Length; i++)
if (line[i].Length > len[i])
len[i] = line[i].Length;
foreach (string[] row in data)
{
if (row[0][0] == tableLine)
Console.Write(tableCross);
else
Console.Write(tableWall);
for (int l = 0; l < row.Length; l++)
{
if (row[l][0] == tableLine)
{
for (int i = 0; i < len[l] + 4; ++i)
Console.Write(tableLine);
}
else if (row[l].Length == len[l])
{
Console.Write(" ");
Console.Write(row[l]);
Console.Write(" ");
}
else
{
int lenHalf = row[l].Length / 2;
for (int i = 0; i < ((len[l] + 4) / 2 - lenHalf); ++i)
Console.Write(" ");
Console.Write(row[l]);
for (int i = (len[l] + 4) / 2 + lenHalf + 1; i < len[l] + 4; ++i)
Console.Write(" ");
if (row[l].Length % 2 == 0)
Console.Write(" ");
}
Console.Write(row[l][0] == tableLine ? tableCross : tableWall);
}
Console.WriteLine(); //end line
}
return;
for (int i = 0; i < line.Length; i++)
if (line[i].Length > len[i])
len[i] = line[i].Length;
}
if (format == TableFormat.CENTER_OVERALL_LENGTH)
foreach (string[] row in data)
{
int maxLen = 0;
foreach (string[] row in data)
foreach (string s in row)
if (s.Length > maxLen)
maxLen = s.Length;
int div = (maxLen + 4) / 2;
foreach (string[] row in data)
if (row[0][0] == tableLine) Console.Write(tableCross);
else Console.Write(tableWall);
for (int l = 0; l < row.Length; l++)
{
Console.Write("\t");
if (row[0] == "-")
Console.Write("+");
if (row[l][0] == tableLine)
{
for (int i = 0; i < len[l] + 4; ++i)
Console.Write(tableLine);
}
else if (row[l].Length == len[l])
{
Console.Write(" ");
Console.Write(row[l]);
Console.Write(" ");
}
else
Console.Write("|");
foreach (string s in row)
{
if (s == "-")
{
for (int i = 0; i < maxLen + 4; ++i)
Console.Write("-");
}
else if (s.Length == maxLen)
{
Console.Write(" ");
Console.Write(s);
Console.Write(" ");
}
else
{
int lenHalf = s.Length / 2;
for (int i = 0; i < div - lenHalf; ++i)
Console.Write(" ");
Console.Write(s);
for (int i = div + lenHalf + 1; i < maxLen + 4; ++i)
Console.Write(" ");
if (s.Length % 2 == 0)
Console.Write(" ");
}
if (s == "-")
Console.Write("+");
else
Console.Write("|");
}
Console.WriteLine(); //end line
}
return;
}
if (format == TableFormat.DEFAULT)
{
int[] widths = new int[data[0].Length];
int space_between_columns = int.Parse(Config.GetValue<Dictionary<string, string>>("TableVariables")?["DefaultSpace"]!);
for (int i = 0; i < data.Count; i++)
{
for (int j = 0; j < data[i].Length; j++)
{
if (data[i][j].Length > widths[j])
widths[j] = data[i][j].Length;
}
}
for (int i = 0; i < data.Count; i++)
{
for (int j = 0; j < data[i].Length; j++)
{
if (data[i][j] == "-")
data[i][j] = " ";
Console.Write(data[i][j]);
for (int k = 0; k < widths[j] - data[i][j].Length + 1 + space_between_columns; k++)
int lenHalf = row[l].Length / 2;
for (int i = 0; i < ((len[l] + 4) / 2 - lenHalf); ++i)
Console.Write(" ");
Console.Write(row[l]);
for (int i = (len[l] + 4) / 2 + lenHalf + 1; i < len[l] + 4; ++i)
Console.Write(" ");
if (row[l].Length % 2 == 0)
Console.Write(" ");
}
Console.WriteLine();
if (row[l][0] == tableLine) Console.Write(tableCross);
else Console.Write(tableWall);
}
Console.WriteLine(); //end line
return;
}
throw new Exception("Unknown type of table");
}
public static void WriteColorText(string text, bool appendNewLineAtEnd = true)
public static void WriteColorText(string text, bool appendNewLine = true)
{
ConsoleColor initialForeGround = Console.ForegroundColor;
char[] input = text.ToCharArray();
for (int i = 0; i < input.Length; i++)
{
if (input[i] == Config.GetValue<char>("ColorPrefix"))
{
if (i + 1 < input.Length)
{
if (Config.GetValue<Dictionary<char, ConsoleColor>>("ColorDataBase")!.ContainsKey(input[i + 1]))
{
Console.ForegroundColor = Config.GetValue<Dictionary<char, ConsoleColor>>("ColorDataBase")![input[i + 1]];
i++;
}
else if (input[i + 1] == 'c')
{
Console.ForegroundColor = initialForeGround;
i++;
}
}
}
else
Console.Write(input[i]);
}
Console.ForegroundColor = initialForeGround;
if (appendNewLineAtEnd)
Console.WriteLine();
string[] words = text.Split(' ');
ConsoleColor fg = Console.ForegroundColor;
Dictionary<string, ConsoleColor> colors = new Dictionary<string, ConsoleColor>()
{
{ "&g", ConsoleColor.Green },
{ "&b", ConsoleColor.Blue },
{ "&r", ConsoleColor.Red },
{ "&m", ConsoleColor.Magenta },
{ "&y", ConsoleColor.Yellow },
{ "&c", fg }
};
foreach (string word in words)
{
if (word.Length >= 2)
{
string prefix = word.Substring(0, 2);
if (colors.ContainsKey(prefix))
Console.ForegroundColor = colors[prefix];
}
string m = word;
foreach (var key in colors.Keys) { m = m.Replace(key, ""); }
Console.Write(m + " ");
}
if (appendNewLine)
Console.Write('\n');
Console.ForegroundColor = fg;
}
}
}

View File

@@ -26,8 +26,4 @@ public enum OutputLogLevel { NONE, INFO, WARNING, ERROR, CRITICAL }
/// <summary>
/// Plugin Type
/// </summary>
public enum PluginType { Command, Event, Unknown }
public enum UnzipProgressType { PercentageFromNumberOfFiles, PercentageFromTotalSize }
public enum TableFormat { CENTER_EACH_COLUMN_BASED, CENTER_OVERALL_LENGTH, DEFAULT }
public enum PluginType { Command, Event, Unknown }

View File

@@ -4,7 +4,6 @@ using System;
using System.Threading.Tasks;
using System.Linq;
using System.Collections.Generic;
using System.Security.Cryptography;
using Discord.WebSocket;
using PluginManager.Items;
using System.Threading;
@@ -38,11 +37,6 @@ namespace PluginManager.Others
/// </summary>
public static readonly string pakFolder = @"./Data/Resources/PAK/";
/// <summary>
/// Beta testing folder
/// </summary>
public static readonly string betaFolder = @"./Data/BetaTest/";
/// <summary>
/// Read data from a file that is inside an archive (ZIP format)
@@ -50,15 +44,31 @@ namespace PluginManager.Others
/// <param name="FileName">The file name that is inside the archive or its full path</param>
/// <param name="archFile">The archive location from the PAKs folder</param>
/// <returns>A string that represents the content of the file or null if the file does not exists or it has no content</returns>
public static Stream? ReadFromPakAsync(string FileName, string archFile)
public static async Task<Stream?> ReadFromPakAsync(string FileName, string archFile)
{
archFile = pakFolder + archFile;
Directory.CreateDirectory(pakFolder);
if (!File.Exists(archFile)) throw new FileNotFoundException("Failed to load file !");
using ZipArchive archive = ZipFile.OpenRead(archFile);
ZipArchiveEntry? entry = archive.GetEntry(FileName);
return entry?.Open();
Stream? textValue = null;
var fs = new FileStream(archFile, FileMode.Open);
var zip = new ZipArchive(fs, ZipArchiveMode.Read);
foreach (var entry in zip.Entries)
{
if (entry.Name == FileName || entry.FullName == FileName)
{
Stream s = entry.Open();
StreamReader reader = new StreamReader(s);
textValue = reader.BaseStream;
textValue.Position = 0;
reader.Close();
s.Close();
fs.Close();
break;
}
}
return textValue;
}
/// <summary>
@@ -67,8 +77,8 @@ namespace PluginManager.Others
/// <param name="LogMessage">The message to be wrote</param>
public static void WriteLogFile(string LogMessage)
{
string logsPath = logFolder + $"{DateTime.Today.ToShortDateString().Replace("/", "-").Replace("\\", "-")} Log.txt";
Directory.CreateDirectory(logFolder);
string logsPath = logFolder + "Log.txt";
if (!Directory.Exists(logFolder)) Directory.CreateDirectory(logFolder);
File.AppendAllText(logsPath, LogMessage + " \n");
}
@@ -78,8 +88,8 @@ namespace PluginManager.Others
/// <param name="ErrMessage">The message to be wrote</param>
public static void WriteErrFile(string ErrMessage)
{
string errPath = errFolder + $"{DateTime.Today.ToShortDateString().Replace("/", "-").Replace("\\", "-")} Error.txt";
Directory.CreateDirectory(errFolder);
string errPath = errFolder + "Error.txt";
if (!Directory.Exists(errFolder)) Directory.CreateDirectory(errFolder);
File.AppendAllText(errPath, ErrMessage + " \n");
}
@@ -91,8 +101,8 @@ namespace PluginManager.Others
/// <returns>A string built based on the array</returns>
public static string MergeStrings(this string[] s, int indexToStart)
{
string r = "";
int len = s.Length;
string r = "";
int len = s.Length;
if (len <= indexToStart) return "";
for (int i = indexToStart; i < len - 1; ++i)
{
@@ -142,9 +152,9 @@ namespace PluginManager.Others
if (!stream.CanRead) throw new InvalidOperationException("The stream is not readable.");
if (!destination.CanWrite) throw new ArgumentException("Destination stream is not writable", nameof(destination));
byte[] buffer = new byte[bufferSize];
long totalBytesRead = 0;
int bytesRead;
byte[] buffer = new byte[bufferSize];
long totalBytesRead = 0;
int bytesRead;
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
{
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
@@ -159,69 +169,33 @@ namespace PluginManager.Others
/// </summary>
/// <param name="zip">The zip location</param>
/// <param name="folder">The target location</param>
/// <param name="progress">The progress that is updated as a file is processed</param>
/// <param name="type">The type of progress</param>
/// <returns></returns>
public static async Task ExtractArchive(string zip, string folder, IProgress<float> progress, UnzipProgressType type)
public static async Task ExtractArchive(string zip, string folder, IProgress<float> progress)
{
if (!Directory.Exists(folder)) Directory.CreateDirectory(folder);
using (ZipArchive archive = ZipFile.OpenRead(zip))
{
if (type == UnzipProgressType.PercentageFromNumberOfFiles)
int totalZIPFiles = archive.Entries.Count();
int currentZIPFile = 0;
foreach (ZipArchiveEntry entry in archive.Entries)
{
int totalZIPFiles = archive.Entries.Count();
int currentZIPFile = 0;
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (entry.FullName.EndsWith("/")) // it is a folder
Directory.CreateDirectory(Path.Combine(folder, entry.FullName));
else
try
{
entry.ExtractToFile(Path.Combine(folder, entry.FullName), true);
}
catch (Exception ex)
{
Console.WriteLine($"Failed to extract {entry.Name}. Exception: {ex.Message}");
}
currentZIPFile++;
await Task.Delay(10);
progress.Report((float)currentZIPFile / totalZIPFiles * 100);
}
}
else if (type == UnzipProgressType.PercentageFromTotalSize)
{
ulong zipSize = 0;
foreach (ZipArchiveEntry entry in archive.Entries)
zipSize += (ulong)entry.CompressedLength;
ulong currentSize = 0;
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (entry.FullName.EndsWith("/"))
{
Directory.CreateDirectory(Path.Combine(folder, entry.FullName));
continue;
}
if (entry.FullName.EndsWith("/"))
Directory.CreateDirectory(Path.Combine(folder, entry.FullName));
else
try
{
entry.ExtractToFile(Path.Combine(folder, entry.FullName), true);
currentSize += (ulong)entry.CompressedLength;
}
catch (Exception ex)
catch
{
Console.WriteLine($"Failed to extract {entry.Name}. Exception: {ex.Message}");
}
await Task.Delay(10);
progress.Report((float)currentSize / zipSize * 100);
}
currentZIPFile++;
await Task.Delay(10);
progress.Report((float)currentZIPFile / totalZIPFiles * 100);
}
}
}
@@ -261,8 +235,7 @@ namespace PluginManager.Others
/// <returns></returns>
public static async Task SaveToJsonFile<T>(string file, T Data)
{
File.Delete(file);
var s = File.Open(file, FileMode.OpenOrCreate);
var s = File.OpenWrite(file);
await JsonSerializer.SerializeAsync(s, Data, typeof(T), new JsonSerializerOptions { WriteIndented = true });
s.Close();
}
@@ -277,7 +250,7 @@ namespace PluginManager.Others
{
Stream text;
if (File.Exists(input))
text = File.OpenRead(input);
text = File.Open(input, FileMode.OpenOrCreate);
else
text = new MemoryStream(Encoding.ASCII.GetBytes(input));
@@ -330,15 +303,5 @@ namespace PluginManager.Others
var data = jsonObject.RootElement.TryGetProperty(codeName, out element);
return data;
}
public static string CreateMD5(string input)
{
using (MD5 md5 = MD5.Create())
{
byte[] inputBytes = Encoding.ASCII.GetBytes(input);
byte[] hashBytes = md5.ComputeHash(inputBytes);
return Convert.ToHexString(hashBytes);
}
}
}
}

View File

@@ -5,6 +5,7 @@ This project is based on:
- [.NET 6 (C#)](https://dotnet.microsoft.com/en-us/download/dotnet/6.0)
- [Discord.Net](https://github.com/discord-net/Discord.Net)
- [Avalonia UI](https://avaloniaui.net/) for `DiscordBotUI` extension
## Plugins
@@ -16,10 +17,9 @@ Plugin Types:
1. Commands
2. Events
<!--
Project Structure
![Image](../../blob/gh-pages/Pictures/architecture2.png)-->
![Image](../../blob/gh-pages/Pictures/architecture2.png)
### How to create a plugin

View File

@@ -1,57 +0,0 @@
using System.IO.Compression;
using System.Runtime.CompilerServices;
using Discord;
using Discord.Commands;
using Discord.Rest;
using Discord.WebSocket;
using Microsoft.Win32.SafeHandles;
using PluginManager.Interfaces;
using PluginManager.Others;
using Roles.Internals;
namespace Roles
{
public class AddRole : DBCommand
{
public string Command => "addrole";
public List<string> Aliases => new() { "ar", "addr", "roleadd" };
public string Description => "Role options";
public string Usage => "addrole [user1] [user2] ... [role1] [role2] ...";
public bool canUseDM => false;
public bool canUseServer => true;
public bool requireAdmin => true;
public async void Execute(SocketCommandContext context, SocketMessage message, DiscordSocketClient client, bool isDM)
{
if (message.MentionedUsers.Count == 0 || message.MentionedRoles.Count == 0)
{
await context.Channel.SendMessageAsync($"Invalid invocation\nUsage:{Usage}");
return;
}
try
{
var users = message.MentionedUsers;
var roles = message.MentionedRoles as IEnumerable<IRole>;
foreach (var user in users)
{
SocketGuildUser? usr = context.Client.GetUser(user.Username, user.Discriminator) as SocketGuildUser;
if (usr is null)
throw new Exception("User is null");
await usr.AddRolesAsync(roles);
}
}
catch (Exception ex)
{
await context.Channel.SendMessageAsync(ex.Message);
}
}
}
}

View File

@@ -1,79 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord;
using Discord.WebSocket;
using PluginManager.Others;
namespace Roles.Internals
{
internal static class RoleManagement
{
internal static async void AddRole(this SocketGuildUser user, string roleName)
{
string role = roleName;
IRole? r = user.Guild.Roles.FirstOrDefault(rl => rl.Name == role || rl.Mention == role);
if (r is null)
throw new Exception("The role does not exist");
try
{
await user.AddRoleAsync(r);
}
catch (Exception ex)
{
if (ex.Message.Contains("Permission", StringComparison.CurrentCultureIgnoreCase))
throw new Exception("Insufficient permissions");
}
}
internal static async void AddRole(this SocketGuildUser user, IRole role)
{
try
{
await user.AddRoleAsync(role);
}
catch (Exception ex)
{
if (ex.Message.Contains("Permission", StringComparison.CurrentCultureIgnoreCase))
throw new Exception("Insufficient permissions");
}
}
internal static async void AddRoles(this SocketGuildUser user, string[] roleNames)
{
foreach (string rolename in roleNames)
{
string roleName = rolename;
IRole? r = user.Guild.Roles.FirstOrDefault(rl => rl.Name == roleName || rl.Mention == roleName);
if (r is null)
throw new Exception("The role does not exist");
try
{
await user.AddRoleAsync(r);
}
catch (Exception ex)
{
if (ex.Message.Contains("Permission", StringComparison.CurrentCultureIgnoreCase))
throw new Exception("Insufficient permissions");
}
}
}
internal static async void AddRoles(this SocketGuildUser user, IEnumerable<IRole> roles)
{
try
{
await user.AddRolesAsync(roles);
}
catch (Exception ex)
{
if (ex.Message.Contains("Permission", StringComparison.CurrentCultureIgnoreCase))
throw new Exception("Insufficient permissions");
}
}
}
}

View File

@@ -1,13 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\PluginManager\PluginManager.csproj" />
</ItemGroup>
</Project>

70
TODO Normal file
View File

@@ -0,0 +1,70 @@
Discord Bot:
✔ Create bootloader
✔ Create commands handler
✔ Create bot launcher
✔ Enable startup commands
✔ Enable console input
☐ Create self update feature
Plugin Manager:
Define plugin interface:
✔ DBCommand
✔ DBPlugin
Functions.cs:
✔ Read from file
✔ Read from archive (PAK)
✔ Write Logs & Errors
✔ Manipulate settings (files) and strings
✔ Stream copy async
Console Utilities:
✔ Progress bar
✔ Create table
✔ Write to console with colors
Discord Permissions:
✔ Check if user has permission
✔ Check if user is owner
Discord Plugins:
✔ Create loader for commands
✔ Create loader for events
☐ Improve memory efficiency
☐ Improve performance
☐ Improve stability
Language System:
✔ Create language system
✔ Load language files
Server Communication:
✔ Plugin Download system
✔ Language Download system
☐ Move to a new server
☐ Create plugin versioning system
☐ Create plugin update system
Plugins:
Events:
✔ Leveling system
Utilities:
✔ Random number generator
✔ Flip a coin
✔ Poll
Commands:
✔ Leveling system
☐ Music Commands @started
// Windows only version
// Download as a patch but replaces old DiscordBot executable with a new one
// Adds new dll to support windows forms
// Must act the same as the old version
☐ Create version of discord bot with windows form
☐ Download system and patch will result in a windows only based version of bot
☐ Possibility to reverse patch to get back to original version

1
Version.txt Normal file
View File

@@ -0,0 +1 @@
0