commit 03899f8e5bc3d3b2807be7f90a518c28a830a0bb Author: Mira <56395159+TheXorog@users.noreply.github.com> Date: Mon Jan 27 17:26:51 2025 +0100 Example Plugin diff --git a/.build.cmd b/.build.cmd new file mode 100644 index 0000000..e2bfcf9 --- /dev/null +++ b/.build.cmd @@ -0,0 +1,62 @@ +@echo off + +REM User-definable variables + +set PluginDir=C:\path\to\plugin\directory +set PluginName=ProjectMakoto.Plugins.Example + + +REM Build procedure, leave alone + +for %%I in (.) do set CurrDirName=%%~nxI + +echo Deleting conflicting files.. +del /S build.zip >NUL +del /S %CurrDirName%.pmpl >NUL +rmdir /S /Q bin >NUL +rmdir /S /Q build >NUL +echo Building project.. +dotnet clean +dotnet restore +dotnet publish %PluginName%.sln --property:PublishDir="build" --framework net9.0 +if %errorlevel% neq 0 goto error +echo Zipping project to build.zip.. +dotnet run --project "Tools\CreateZipFolder\CreateZipFolder.csproj" -- "build" "build.zip" +if %errorlevel% neq 0 goto error + +rename build.zip %CurrDirName%.pmpl + +echo Creating manifest.. +set current_dir=%cd% +cd ..\deps +dotnet ProjectMakoto.dll --build-manifests %current_dir% +cd %current_dir% + +echo. +echo. +echo Created pmpl-File at %cd%\%CurrDirName%.pmpl! + +echo Cleaning up.. +rmdir /S /Q bin >NUL +rmdir /S /Q build >NUL + +if "%PluginDir%"=="C:\path\to\plugin\directory" ( + echo. + echo Tip: You can define an output directory in this file by replacing PluginDir with the appropriate path. + timeout /T 3 >NUL + goto skipcopy + ) + +echo Copying to %PluginDir%.. +del /S %PluginDir%\%CurrDirName%.pmpl >NUL +timeout /t 1 >NUL +move %CurrDirName%.pmpl %PluginDir%\%CurrDirName%.pmpl +if %errorlevel% neq 0 goto error + +:skipcopy +exit /b 0 + +:error +echo Something went wrong! +pause >NUL +exit /b %errorlevel% \ No newline at end of file diff --git a/.build.sh b/.build.sh new file mode 100644 index 0000000..ef61873 --- /dev/null +++ b/.build.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +# User-definable variables +PluginDir="/path/to/plugin/directory" +PluginName="ProjectMakoto.Plugins.Example" + +# Build procedure, leave alone +CurrDirName=$(basename "$(pwd)") + +echo "Deleting conflicting files.." +rm -f build.zip +rm -f "${CurrDirName}.pmpl" +rm -rf bin +rm -rf build + +echo "Building project.." +dotnet clean +dotnet restore +dotnet publish "${PluginName}.sln" --property:PublishDir="build" --framework net9.0 +if [ $? -ne 0 ]; then + echo "Error: Build failed." + exit 1 +fi + +echo "Zipping project to build.zip.." +dotnet run --project "Tools/CreateZipFolder/CreateZipFolder.csproj" -- "build" "build.zip" + +if [ $? -ne 0 ]; then + echo "Error: Zipping failed." + exit 1 +fi + +mv build.zip "${CurrDirName}.pmpl" + +echo "Creating manifest.." +current_dir=$(pwd) +cd ../deps +dotnet ProjectMakoto.dll --build-manifests $current_dir +cd $current_dir + +echo -e "\n\nCreated pmpl-File at $(pwd)/${CurrDirName}.pmpl!" + +echo "Cleaning up.." +rm -rf bin +rm -rf build + +if [ "$PluginDir" = "/path/to/plugin/directory" ]; then + echo -e "\nTip: You can define an output directory in this file by replacing PluginDir with the appropriate path." + sleep 3 + exit 0 +fi + +echo -e "\nCopying to $PluginDir.." +rm -f "${PluginDir}/${CurrDirName}.pmpl" +sleep 1 +mv "${CurrDirName}.pmpl" "${PluginDir}/${CurrDirName}.pmpl" +if [ $? -ne 0 ]; then + echo "Error: Copying failed." + exit 1 +fi + +exit 0 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..c2d1a9e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,89 @@ +file_header_template = Project Makoto Example Plugin\nCopyright (C) 2023 Fortunevale\nThis code is licensed under MIT license (see 'LICENSE'-file for details) +[*.{cs,vb}] +dotnet_style_operator_placement_when_wrapping = beginning_of_line +tab_width = 4 +indent_size = 4 +end_of_line = crlf +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_auto_properties = true:silent +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = false:silent +[*.cs] +csharp_indent_labels = one_less_than_current +csharp_using_directive_placement = outside_namespace:silent +csharp_prefer_simple_using_statement = false:suggestion +csharp_prefer_braces = true:silent +csharp_style_namespace_declarations = file_scoped:silent +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent + +# CA1822: Mark members as static +dotnet_diagnostic.CA1822.severity = silent + +# IDE0290: Use primary constructor +dotnet_diagnostic.IDE0290.severity = silent + +[*.{cs,vb}] +#### Naming styles #### + +# Naming rules + +dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications + +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles + +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case +dotnet_style_prefer_simplified_boolean_expressions = true:suggestion + +# IDE0060: Remove unused parameter +dotnet_diagnostic.IDE0060.severity = silent + +# DV2001: No Dependency Diagram linked +dotnet_diagnostic.DV2001.severity = silent diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a52627f --- /dev/null +++ b/.gitignore @@ -0,0 +1,402 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml + +deps +deps/ +*.pmpl \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..7cd501e --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Tools"] + path = Tools + url = https://github.com/Fortunevale/ProjectMakoto.Tools diff --git a/Assets/Prod.png b/Assets/Prod.png new file mode 100644 index 0000000..71be3a7 Binary files /dev/null and b/Assets/Prod.png differ diff --git a/Commands/ExampleCommand.cs b/Commands/ExampleCommand.cs new file mode 100644 index 0000000..ea5e994 --- /dev/null +++ b/Commands/ExampleCommand.cs @@ -0,0 +1,23 @@ +// Project Makoto Example Plugin +// Copyright (C) 2023 Fortunevale +// This code is licensed under MIT license (see 'LICENSE'-file for details) + +using ProjectMakoto.Entities.Translation; +using ProjectMakoto.Plugins.Example; +using Translations = ProjectMakoto.Plugins.Example.Entities.Translations; + +namespace ProjectMakoto.Commands; + +internal class ExampleCommand : BaseCommand +{ + public override Task ExecuteCommand(SharedCommandContext ctx, Dictionary arguments) + { + return Task.Run(async () => + { + ExamplePlugin.Plugin!.UserData![ctx.User.Id].ExampleValue1 = !ExamplePlugin.Plugin.UserData![ctx.User.Id].ExampleValue1; + + _ = await this.RespondOrEdit(this.GetString(((Translations)ExamplePlugin.Plugin!.Translations).Commands.ValueSet, + new TVar("Value", ExamplePlugin.Plugin.UserData![ctx.User.Id].ExampleValue1))); + }); + } +} \ No newline at end of file diff --git a/Entities/ExampleSubTable1.cs b/Entities/ExampleSubTable1.cs new file mode 100644 index 0000000..34a0d6a --- /dev/null +++ b/Entities/ExampleSubTable1.cs @@ -0,0 +1,15 @@ +using ProjectMakoto.Database; +using ProjectMakoto.Enums; + +namespace ProjectMakoto.Plugins.Example.Entities; +public class ExampleSubTable1(Bot bot, ExampleTable parent) : RequiresParent(bot, parent) // You can easily add a Parent to a class by using +{ // RequiresParent, so theres no need for extensive + // constructors. + + [ColumnName("example_value3"), ColumnType(ColumnTypes.TinyInt), Default("1")] // In the sub-table, you simply do the same as in the parent. + public bool ExampleValue3 + { + get => this.Parent.GetValue(this.Parent.Id, "example_value3"); // The only difference being that you need to access the Parent + set => this.Parent.SetValue(this.Parent.Id, "example_value3", value); // for the Database Tools. + } +} diff --git a/Entities/ExampleTable.cs b/Entities/ExampleTable.cs new file mode 100644 index 0000000..17e0dc5 --- /dev/null +++ b/Entities/ExampleTable.cs @@ -0,0 +1,46 @@ +// Project Makoto Example Plugin +// Copyright (C) 2023 Fortunevale +// This code is licensed under MIT license (see 'LICENSE'-file for details) + +using Newtonsoft.Json; +using ProjectMakoto.Database; +using ProjectMakoto.Enums; + +namespace ProjectMakoto.Plugins.Example.Entities; + + +[TableName("exampletable")] +public class ExampleTable : PluginDatabaseTable +{ + public ExampleTable(BasePlugin plugin, ulong identifierValue) : base(plugin, identifierValue) + { + this.Id = identifierValue; // Don't forget to initialize the identifier so the getters and setters can do their work. + + this.SubTable1 = new(this.Plugin.Bot, this); + } + + [ColumnName("userid"), ColumnType(ColumnTypes.BigInt), Primary] // The identifier value is stored twice, once as key for indexing (access via List[id]) + internal ulong Id { get; init; } // and inside the value (this class) for easy actually communicating with the database + + [ColumnName("example_value1"), ColumnType(ColumnTypes.TinyInt), Default("1")] + public bool ExampleValue1 + { + get => this.GetValue(this.Id, "example_value1"); // This directly gets the value from the database. It can be frequently accessed, theres no need to cache the value. + // Makoto takes care of caching for you. Values are stored for a few seconds. + + set => this.SetValue(this.Id, "example_value1", value); // Setting the value removes the cached item. And refetches on next get. + } + + [ColumnName("example_value2"), ColumnType(ColumnTypes.LongText), Default("[]")] // Make sure to minify the json if you want to store large amounts of data. + public string[] ExampleValue2 // LongText can store up to 4GiB of text. + { // Another important note: It's recommended to use arrays instead of + // lists as they do not fire the setters when adding/removing items. + get => JsonConvert.DeserializeObject(this.GetValue(this.Id, "example_value2")) ?? []; // Storing more sophisticated data is usually done by converting it to json + // and storing the resulting string in the database. + + set => this.SetValue(this.Id, "example_value2", JsonConvert.SerializeObject(value)); + } + + [ContainsValues] // This attribute signals to Makoto to look for more columns inside this property. + public ExampleSubTable1 SubTable1 { get; init; } // This allows you to sort your table a little more so you don't get bombarded with +} // tons of properties everytime you want to access the table in your code. diff --git a/Entities/PluginConfig.cs b/Entities/PluginConfig.cs new file mode 100644 index 0000000..1e87c09 --- /dev/null +++ b/Entities/PluginConfig.cs @@ -0,0 +1,10 @@ +// Project Makoto Example Plugin +// Copyright (C) 2023 Fortunevale +// This code is licensed under MIT license (see 'LICENSE'-file for details) + +namespace ProjectMakoto.Plugins.Example.Entities; + +public class PluginConfig +{ + public string ExampleString { get; set; } = "Example Config Option"; +} diff --git a/Entities/Translations.cs b/Entities/Translations.cs new file mode 100644 index 0000000..ebac82b --- /dev/null +++ b/Entities/Translations.cs @@ -0,0 +1,24 @@ +// Project Makoto +// Copyright (C) 2023 Fortunevale +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY +namespace ProjectMakoto.Plugins.Example.Entities; +#pragma warning disable CS8981 +#pragma warning disable CS8618 +#pragma warning disable IDE1006 +public class Translations : ITranslations +{ + public Dictionary Progress = new(); + public CommandTranslation[] CommandList { get; set; } + #region AutoGenerated + public commands Commands; + public sealed class commands + { + public SingleTranslationKey ValueSet; + } + #endregion AutoGenerated +} \ No newline at end of file diff --git a/ExamplePlugin.cs b/ExamplePlugin.cs new file mode 100644 index 0000000..42e8c5b --- /dev/null +++ b/ExamplePlugin.cs @@ -0,0 +1,133 @@ +// Project Makoto Example Plugin +// Copyright (C) 2023 Fortunevale +// This code is licensed under MIT license (see 'LICENSE'-file for details) + +namespace ProjectMakoto.Plugins.Example; + +public class ExamplePlugin : BasePlugin +{ + // Set the plugin's information here. + + // The plugin's name. + public override string Name => "Example Plugin"; + + // The plugin's description. + public override string Description => "This is an example plugin."; + + // The current version of this plugin. Will be used for update checking. + public override SemVer Version => new(1, 0, 0); + + // The Api Versions this Plugin supports. + public override int[] SupportedPluginApis => [1]; + + // Your name. + public override string Author => "Mira"; + + // Your Discord Id, if you want to provide it. + public override ulong? AuthorId => 411950662662881290; + + // The repository url of your plugin. Used for automatic update checking. + public override string UpdateUrl => "https://github.com/Fortunevale/ProjectMakoto.Plugins.Example"; + + // Here you can provide github credentials for update checking, if your repository is private. + public override Octokit.Credentials? UpdateUrlCredentials => base.UpdateUrlCredentials; + + + // A reference to your own plugin accessible from anywhere inside of it. + public static ExamplePlugin? Plugin { get; set; } + + // When trying to get an entry which does not already exist, SelfFillingDatabaseDictionary will create one. + public SelfFillingDatabaseDictionary? UserData { get; set; } + + // You can directly interface with the already existing config.json of Project Makoto. This property allows you to. + private PluginConfig LoadedConfig + { + get + { + if (!this.CheckIfConfigExists()) + { + this._logger.LogDebug("Creating Plugin Config.."); + this.WriteConfig(new PluginConfig()); // You can use any class you choose, it gets saved with Newtonsoft.Json. + } + + var v = this.GetConfig(); + + if (v.GetType() == typeof(JObject)) + { + this.WriteConfig(((JObject)v).ToObject() ?? new PluginConfig()); // Automatically converts the config you get to your PluginConfig. + v = this.GetConfig(); + } + + return (PluginConfig)v; + } + } + + // Here you can do stuff when initializing your plugin. Happens on startup, before loading data. + public override ExamplePlugin Initialize() + { + ExamplePlugin.Plugin = this; // Allows you to access your Main Class from anywhere within your project. + + this.Connected += (s, e) => + { + this._logger.LogDebug("Hello from the Example Plugin!"); + + // There's several different events that fire. Connected being one of them. It fires upon successful log in to discord. + // The sender (s) is usually the 'Bot' Instance this plugin is loaded under, in this context also accessible via 'this.Bot'. + + // You don't need to register all events while initializing, you can register and unregister them at any time. + }; + + this.DatabaseInitialized += (s, e) => // The earliest a SelfFillingDatabaseDictionary can be initiated is after the Database has been initialized. + { // This event fires as soon as it is possible to initiate any database related list. + this._logger.LogDebug("Creating SelfFillingDatabaseDictionaries for {PluginName}!", this.Name); + + this.UserData = new SelfFillingDatabaseDictionary(this, typeof(ExampleTable), (id) => + { + return new ExampleTable(this, id); + }); // The predicate is required for the self-filling capability. + }; // There's also a DatabaseDictionary which does not have that. + + return this; + } + + // This allows you to register commands, they'll be registered as prefix and application command. Happens right before the login to discord. + public override async Task> RegisterCommands() + { + await Task.Delay(0); // You can do things when registering commands. + + return + [ + new("Example", // The name of this module. This will define in what group this command shows up in the help command. + [ + new("single-example", "Example command from an example plugin for Project Makoto.", typeof(ExampleCommand), + new MakotoCommandOverload(typeof(string), "example_arg1", "Example Argument 1", true, false), + new MakotoCommandOverload(typeof(string), "example_arg2", "Example Argument 2", false, true)), + + new("group-example", "Example command from an example plugin for Project Makoto.", + new MakotoCommand("subexample1", "Example command from an example plugin for Project Makoto.", typeof(ExampleCommand)), + new MakotoCommand("subexample2", "Example command from an example plugin for Project Makoto.", typeof(ExampleCommand))) + ]) + ]; + } + + // Allows you to define the tables you need to store user/guild/misc data. Any data that does not belong in the config. + public override Task?> RegisterTables() + { + return Task.FromResult?>( + [ + typeof(ExampleTable), + ]); + } + + // Here you can enable translations for your provided commands. + public override (string? path, Type? type) LoadTranslations() + { + return ("Translations/strings.json", typeof(Entities.Translations)); // Make sure to include the strings.json in your build directory via the csproj. + } // The type has to inherit ITranslation and the CommandList must include *ALL* commands that + // you registered in the RegisterCommands() Method, otherwise DisCatSharp will fail generating the + // command payload. + + // Here you can do stuff before shutting down. Happens at shutdown of Project Makoto. + public override Task Shutdown() + => base.Shutdown(); +} diff --git a/GlobalSuppressions.cs b/GlobalSuppressions.cs new file mode 100644 index 0000000..56b5932 --- /dev/null +++ b/GlobalSuppressions.cs @@ -0,0 +1,12 @@ +// Project Makoto Example Plugin +// Copyright (C) 2023 Fortunevale +// This code is licensed under MIT license (see 'LICENSE'-file for details) + +// This file is used by Code Analysis to maintain SuppressMessage +// attributes that are applied to this project. +// Project-level suppressions either have no target or are given +// a specific target and scoped to a namespace, type, member, etc. + +using System.Diagnostics.CodeAnalysis; + +[assembly: SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "", Scope = "member", Target = "~P:ProjectMakoto.Plugins.Example.ExamplePlugin.LoadedConfig")] diff --git a/Globals.cs b/Globals.cs new file mode 100644 index 0000000..6bb1eb6 --- /dev/null +++ b/Globals.cs @@ -0,0 +1,10 @@ +// Project Makoto Example Plugin +// Copyright (C) 2023 Fortunevale +// This code is licensed under MIT license (see 'LICENSE'-file for details) + +// You can import stuff in this file to have them imported everywhere in your project, you can also just use normal usings like always. + +global using Newtonsoft.Json.Linq; +global using ProjectMakoto.Commands; +global using ProjectMakoto.Plugins.Example.Entities; +global using ProjectMakoto.Entities; \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..54948d5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Fortunevale + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MSBuild.props b/MSBuild.props new file mode 100644 index 0000000..99db84f --- /dev/null +++ b/MSBuild.props @@ -0,0 +1,9 @@ + + + false + + + + false + + diff --git a/ProjectMakoto.Plugins.Example.csproj b/ProjectMakoto.Plugins.Example.csproj new file mode 100644 index 0000000..76a721c --- /dev/null +++ b/ProjectMakoto.Plugins.Example.csproj @@ -0,0 +1,75 @@ + + + + net9.0 + enable + $(OutputPath) + bin\ + None + false + enable + + + + embedded + + + + embedded + + + + + + + + + + + + + + + + + + deps\DisCatSharp.dll + + + deps\ProjectMakoto.dll + + + deps\DisCatSharp.Common.dll + + + deps\DisCatSharp.ApplicationCommands.dll + + + deps\DisCatSharp.Interactivity.dll + + + deps\DisCatSharp.CommandsNext.dll + + + deps\DisCatSharp.Experimental.dll + + + deps\DisCatSharp.Lavalink.dll + + + deps\Xorog.UniversalExtensions.dll + + + deps\Octokit.dll + + + deps\Newtonsoft.Json.dll + + + + + + Always + + + diff --git a/ProjectMakoto.Plugins.Example.sln b/ProjectMakoto.Plugins.Example.sln new file mode 100644 index 0000000..b586e5d --- /dev/null +++ b/ProjectMakoto.Plugins.Example.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.6.33417.168 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProjectMakoto.Plugins.Example", "ProjectMakoto.Plugins.Example.csproj", "{7CFAC90A-0FAE-4EDA-A465-714CC3EDC14B}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{C4374A3F-1569-4822-9943-4E27596F23BB}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7CFAC90A-0FAE-4EDA-A465-714CC3EDC14B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7CFAC90A-0FAE-4EDA-A465-714CC3EDC14B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7CFAC90A-0FAE-4EDA-A465-714CC3EDC14B}.Debug|x64.ActiveCfg = Debug|Any CPU + {7CFAC90A-0FAE-4EDA-A465-714CC3EDC14B}.Debug|x64.Build.0 = Debug|Any CPU + {7CFAC90A-0FAE-4EDA-A465-714CC3EDC14B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7CFAC90A-0FAE-4EDA-A465-714CC3EDC14B}.Release|Any CPU.Build.0 = Release|Any CPU + {7CFAC90A-0FAE-4EDA-A465-714CC3EDC14B}.Release|x64.ActiveCfg = Release|Any CPU + {7CFAC90A-0FAE-4EDA-A465-714CC3EDC14B}.Release|x64.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {A16A0C52-4504-4F57-B8A8-17BE801A4AB7} + EndGlobalSection +EndGlobal diff --git a/README.md b/README.md new file mode 100644 index 0000000..688a1cd --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +

Makoto Example Plugin

+

+

An example plugin for Makoto.

+ + +## Prerequisites + +- [.NET 8](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) +- [ProjectMakoto](https://github.com/Fortunevale/ProjectMakoto) +- Your favourite C# IDE. My personal choice is [Visual Studio Community 2022](https://visualstudio.microsoft.com/vs/community/). \ No newline at end of file diff --git a/RunTranslationGenerator.sh b/RunTranslationGenerator.sh new file mode 100644 index 0000000..39c4bae --- /dev/null +++ b/RunTranslationGenerator.sh @@ -0,0 +1,7 @@ +cd Tools/TranslationSourceGenerator + +git submodule update --init --depth 0 + +dotnet restore +dotnet run -- ../../Translations/strings.json ../../Entities/Translations.cs ProjectMakoto.Plugins.Example.Entities +sleep 60 \ No newline at end of file diff --git a/Tools b/Tools new file mode 160000 index 0000000..9f9113f --- /dev/null +++ b/Tools @@ -0,0 +1 @@ +Subproject commit 9f9113fdadbf3d2e95f570a8edbe0673c789ddba diff --git a/Translations/strings.json b/Translations/strings.json new file mode 100644 index 0000000..b3b38f3 --- /dev/null +++ b/Translations/strings.json @@ -0,0 +1,76 @@ +{ + "CommandList": [ + { + "Type": 1, + "Names": { + "en": "single-example", + "de": "einzel-beispiel" + }, + "Descriptions": { + "en": "Example command from an example plugin for Project Makoto.", + "de": "Beispielbefehl von einem Beispielplugin für Projekt Makoto." + }, + "Options": [ + { + "Names": { + "en": "example_arg1", + "de": "beispiel_arg1" + }, + "Descriptions": { + "en": "Example Argument 1", + "de": "Beispiel Argument 1" + } + }, + { + "Names": { + "en": "example_arg2", + "de": "beispiel_arg2" + }, + "Descriptions": { + "en": "Example Argument 2", + "de": "Beispiel Argument 2" + } + } + ] + }, + { + "Type": 1, + "Names": { + "en": "group-example", + "de": "gruppen-beispiel" + }, + "Descriptions": { + "en": "Example command from an example plugin for Project Makoto.", + "de": "Beispielbefehl von einem Beispielplugin für Projekt Makoto." + }, + "Commands": [ + { + "Names": { + "en": "subexample1", + "de": "subbeispiel1" + }, + "Descriptions": { + "en": "Example command from an example plugin for Project Makoto.", + "de": "Beispielbefehl von einem Beispielplugin für Projekt Makoto." + } + }, + { + "Names": { + "en": "subexample2", + "de": "subbeispiel2" + }, + "Descriptions": { + "en": "Example command from an example plugin for Project Makoto.", + "de": "Beispielbefehl von einem Beispielplugin für Projekt Makoto." + } + } + ] + } + ], + "Commands": { + "ValueSet": { + "en": "Hi! The configuration value is now {Value}!", + "de": "Hi! The Konfigurationswert ist jetzt {Value}!" + } + } +} \ No newline at end of file