Example Plugin

This commit is contained in:
Mira 2025-01-27 17:26:51 +01:00
commit 03899f8e5b
Signed by untrusted user who does not match committer: Xorog
GPG key ID: 983798ED9C3E7C36
23 changed files with 1128 additions and 0 deletions

62
.build.cmd Normal file
View file

@ -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%

62
.build.sh Normal file
View file

@ -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

89
.editorconfig Normal file
View file

@ -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

2
.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

402
.gitignore vendored Normal file
View file

@ -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

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "Tools"]
path = Tools
url = https://github.com/Fortunevale/ProjectMakoto.Tools

BIN
Assets/Prod.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 480 KiB

View file

@ -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<string, object> 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)));
});
}
}

View file

@ -0,0 +1,15 @@
using ProjectMakoto.Database;
using ProjectMakoto.Enums;
namespace ProjectMakoto.Plugins.Example.Entities;
public class ExampleSubTable1(Bot bot, ExampleTable parent) : RequiresParent<ExampleTable>(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<bool>(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.
}
}

46
Entities/ExampleTable.cs Normal file
View file

@ -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<bool>(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<string[]>(this.GetValue<string>(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.

10
Entities/PluginConfig.cs Normal file
View file

@ -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";
}

24
Entities/Translations.cs Normal file
View file

@ -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<string, int> Progress = new();
public CommandTranslation[] CommandList { get; set; }
#region AutoGenerated
public commands Commands;
public sealed class commands
{
public SingleTranslationKey ValueSet;
}
#endregion AutoGenerated
}

133
ExamplePlugin.cs Normal file
View file

@ -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<ExampleTable>? 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<PluginConfig>() ?? 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<ExampleTable>(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<IEnumerable<MakotoModule>> 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<IEnumerable<Type>?> RegisterTables()
{
return Task.FromResult<IEnumerable<Type>?>(
[
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();
}

12
GlobalSuppressions.cs Normal file
View file

@ -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 = "<Pending>", Scope = "member", Target = "~P:ProjectMakoto.Plugins.Example.ExamplePlugin.LoadedConfig")]

10
Globals.cs Normal file
View file

@ -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;

21
LICENSE Normal file
View file

@ -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.

9
MSBuild.props Normal file
View file

@ -0,0 +1,9 @@
<Project>
<PropertyGroup>
<BuildProjectReferences>false</BuildProjectReferences>
</PropertyGroup>
<PropertyGroup>
<ValidateArchitecture>false</ValidateArchitecture>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,75 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="MSBuild.props" />
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<PackageOutputPath>$(OutputPath)</PackageOutputPath>
<BaseOutputPath>bin\</BaseOutputPath>
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
<ValidateArchitecture>false</ValidateArchitecture>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>embedded</DebugType>
</PropertyGroup>
<ItemGroup>
<Compile Remove="deps\**" />
<Compile Remove="Tools\**" />
<EmbeddedResource Remove="deps\**" />
<EmbeddedResource Remove="Tools\**" />
<None Remove="deps\**" />
<None Remove="Tools\**" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<Reference Include="DisCatSharp">
<HintPath>deps\DisCatSharp.dll</HintPath>
</Reference>
<Reference Include="ProjectMakoto">
<HintPath>deps\ProjectMakoto.dll</HintPath>
</Reference>
<Reference Include="DisCatSharp.Common">
<HintPath>deps\DisCatSharp.Common.dll</HintPath>
</Reference>
<Reference Include="DisCatSharp.ApplicationCommands">
<HintPath>deps\DisCatSharp.ApplicationCommands.dll</HintPath>
</Reference>
<Reference Include="DisCatSharp.Interactivity">
<HintPath>deps\DisCatSharp.Interactivity.dll</HintPath>
</Reference>
<Reference Include="DisCatSharp.CommandsNext">
<HintPath>deps\DisCatSharp.CommandsNext.dll</HintPath>
</Reference>
<Reference Include="DisCatSharp.Experimental">
<HintPath>deps\DisCatSharp.Experimental.dll</HintPath>
</Reference>
<Reference Include="DisCatSharp.Lavalink">
<HintPath>deps\DisCatSharp.Lavalink.dll</HintPath>
</Reference>
<Reference Include="Xorog.UniversalExtensions">
<HintPath>deps\Xorog.UniversalExtensions.dll</HintPath>
</Reference>
<Reference Include="Octokit">
<HintPath>deps\Octokit.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>deps\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<None Update="Translations\strings.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View file

@ -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

10
README.md Normal file
View file

@ -0,0 +1,10 @@
<h1 align="center">Makoto Example Plugin</h1>
<p align="center"><img src="Assets/Prod.png" width=250 align="center"></p>
<p align="center" style="font-weight:bold;">An example plugin for Makoto.</p>
## 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/).

View file

@ -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

1
Tools Submodule

@ -0,0 +1 @@
Subproject commit 9f9113fdadbf3d2e95f570a8edbe0673c789ddba

76
Translations/strings.json Normal file
View file

@ -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}!"
}
}
}