Giter Site home page Giter Site logo

siscodeorg / sisbase Goto Github PK

View Code? Open in Web Editor NEW
1.0 3.0 0.0 1007 KB

An easy to use discord bot base for D#+. Discord Link :

Home Page: https://discord.gg/ycvm6xJ

License: MIT License

C# 100.00%
discord discordbot-framework csharp-library csharp dotnet-core3 discord-bot dsharpplus

sisbase's Introduction

A Simple to use Discord Bot Base based on DSharpPlus.

Starting up

DSharpPlus Sisbase Discord

Features

Fully featured help command with support for

  • Categories
  • Commands
  • Hidden Commands

Custom Systems!

  • With ISystem you can create custom systems (ReactRole, etc) outside of the main file
  • Available Interfaces :
    • IScheduledSystem (Provides a customizable timer)
    • IClientSystem (DiscordClient)
    • IStaticSystem

An EmbedBase containing parsers of:

  • Ordered List and List (Needs to be an scalar / provide an .ToString() override)
  • Input / Output
  • Help of Commands and Categories

An extensive utilities set:

  • Automatic Handling of Cancel Codes on the console
  • Simplified Unicode Emoji Support
  • Custom Attributes
  • Extensions for parsing input from DiscordMessage

sisbase's People

Contributors

roridev avatar wffirilat avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar

sisbase's Issues

Add ExecuteAsync to IClientSystem

This if accepted would allow for the system, on the startup phase to run some modules asynchronously.
Proposed API :

public Task ExecuteAsync(DiscordClient client);

Add InteractionMessage and InteractionMessageAccessor abstractions

InteractionMessage:
implspec:

concept: interface delegation
class InteractionMessage "imsg" : delegate(DiscordMessage)
val Interaction owner
override DiscordMessage.Edit():
    intr.Modify
override DiscordMessage.Delete():
    intr.Remove
async waitDelete()
async waitEdit()
async waitReaction{Toggle|Add|Remove}(pred?)
event OnEdit
event OnDelete
event OnReaction{Toggle|Add|Remove}


class Interaction:
async InteractionMessage SendMessage()
async InteractionMessage GetUserResponse()

void Dispatch() {
    foreach(message) if(message.wants(event)) message.Dispatch(event)
}

example usages:

intr.Origin.OnReactToggle += async (e) => ...
// instead of
intr.OnOriginReactToggle += ...
var imsg = await intr.SendMessageAsync();
imsg.AddReaction(":trash:");
imsg.OnReactionToggle += async (e) => {
    if (e.Emoji != ":trash:") return;
    ismg.Delete();
}

InteractionMessageAccessor:
implspec:

class InteractionMessageAccessor:
val Interaction owner
event On...
    ...
async Wait...
    ...
void Dispatch(EventArgs)

class ListInteractionAccessor : InteractionMessageAccessor:
mode = User | Bot | All
List<InteractionMessage> Get();
SingleAccessor First, Last

class SingleInteractionAccessor : InteractionMessageAccessor:
val ListAccessor parent
mode = First | Last
InteractionMessage Get();


class Interaction:
ListAccessor BotMessages
ListAccessor UserMessages
ListAccessor AllMessages
SingleAccessor Origin = UserMessages.First
SingleAccessor LatestMessage = AllMessages.Last

void Interaction.Dispatch {
    ...
    foreach (accessor) if (accessor.wants(event)) accessor.Dispatch(event)
}

example usages:

intr.UserMessages.Last.OnReactionAdd += ...
// NOT the same as
var imsg = ... // get latest user message
imsg.OnReactionAdd += ...

Improve Unicode emoji support (currently Utils/Unicode.cs)

(see this comment on #31 for motivating discussion)

Current Status:

Utils/Unicode.cs contains a list of unicode code points and discord emoji names, and provides two dictionaries Emojis and UnicodeEmojisByDiscordName that contain the forward and reverse mappings.

Proposed Changes:

  • Rename Utils/Unicode.cs to something more specific that indicates the relation to unicode emojis. (see issue #31)
  • Add helper functions that encapsulate the usage of the emoji lists. Perhaps DiscordEmojiNameFromUnicodeChar and UnicodeCharFromDiscordEmojiName?

Add behaviours to interaction.

Usage: By using InteractionBehaviour.DeleteReaction As soon as .WaitForReaction returns said reaction is deleted allowing for multiple button presses.

Another useful behaviour could be DeleteMesage.

The default behavior would be None.

Add documentation for setting up (probably on the wiki)

Current setup is convoluted mainly because of the process of adding the d#+ nightly nuget source. Making an wiki entry with a complete tutorial on how to setup a sisbase bot from scratch would make that a trivially easy step-by-step process.

Also include troubleshooting for common issues related to that.

Add multiple logging levels

sisbase logging should have multiple logging levels, something similar to dsp.
that would allow for giving more information if said level is one. the current logging behaviour would be the default one.

Hierarchy Utils

Problem

  • dsp

Currently on dsp, if a bot attempts to add a role which is higher on the higherarchy then itself an UnauthorizedException will be thrown.
There exists an int | DiscordMember#Hierarchy property which gives the position of the member on the role hierarchy, but thats hidden and its more common to see a try-catch then that property being used.

Proposal

The creation of an HierarchyUtils that adds the following functions

DiscordRole GetHighestRole(this DiscordMember m);
bool IsAbove(this DiscordMember m, DiscordRole r);
bool IsAbove(this DiscordRole l, DiscordRole r);

with more being added in the future.

That would allow for the following code

try {
    await member.GrantRoleAsync(role);
} catch (UnauthorizedException ex) {
   //Send message
}

to be simplified to:

if(bot.IsAbove(role)){
   await member.GrantRoleAsync(role);
} else {
  //Send message
}

General Code Audit

Meta-issue with all points on the code base that may need to be looked again. If said issue is big enough another issue may be created because of it. For better organization, new issues must be posted as a comment first then edited on the original message.

Reason : Discord webhook only notifies new comments not edits.

Issues here can range from code quality to major bugs.

Tags

NRE - Can cause / causes a NullReferenceException.
EXC - Can cause / causes an unhandled exception.
CQ - Code Quality.
BUG - Any bug. Includes unexpected behavior.
API - Issues on the current API design. Should have an proposal that addresses said issue annexed.

Format

Use the copy permalink feature on github and describe the issue on that piece of code.

List

CQ | API - Behaviours class works like a namespace, unnecessary nesting.

CQ | API - EmbedBase.ListEmbed uses IEnumerable<T> which is inconsistent with the api name, and likely could cause issues since IEnumerable can be anything that provides an enumerator.

CQ - Complex nested code could be made into a function

Sharding support

Currently there is no support for Sharding on a sisbase bot.
DSP has already implemented a DiscordShardedClient but their implementation would need to be review in order for us to determine if we either just use it or reimplement it.

Issues related to 2.0 migration process

Renames

Sisbase -> MainConfig
SisbaseBot#StartAsync -> SisbaseBot#Start (although its async. revert?)

Issues

Sisbase._ctor doesn't have a MainConfig override exposed even if MainConfig._ctor itself is exposed.

var config = new MainConfig();
var sisbase = new SisbaseBot( //CS1503
    config
);

IClientSystem API is outdated - #30 (Fixed)

void ApplyToClient(DiscordClient client);

Permissions is an ambiguous reference between DSharpPlus.Permissions and sisbase.Utils.Permissions - #31

⚠️ Config file format issue - #33 - Closed

Better handling of custom configs based on IConfiguration

Add a SisbaseBot.RegisterCustomConfig<T>(Path) where T:IConfiguration method so that registering custom configs are easier to the user.

Also look onto converting IConfiguration to an abstract class since most implementations of Create() and Update() would look like this :

public void Update() {
    File.WriteAllText(Path,JsonConvert.SerializeObject(this,Formatting.Indented));
}

public void Create(string Path) {
    if (File.Exists(Path)) {
        Data = JsonConvert.DeserializeObject<T>(File.ReadAllText(Path)).Data;
    }
    else {
        //Generate a default.
    }
}

EmbedBase overhaul

EmbedBase is the last bit of old unmodified code from the lolibase era. I really didn't knew any better.

Improve HierarchyUtils

Add extensions for getting the highest role with a given permission and allow predicates on GetHighestRole

-- Role GetHighestRole(this Member m);
++ Role GetHighestRole(this Member m, Func<Role,bool> pred);
++ Role GetHighestRole(this Member m) => m.GetHighestRole(_ => true);
++ Role GetHighestRoleWithPermission(this Member m , Perm p) => m.GetHighestRole(x => x.HasPermission(p));

Safely handle malformed/invalid config files

Current behaviour: The program will crash with an NRE when an invalid config file exists.

Ideal behaviour: The program will backup the existing malformed config file, print a warning, possibly give some information about why it is malformed, and then generate a new file with the default settings

Configuration Overhaul

The current bot configuration is drenched in hardcoded values and little to nothing is exposed to the user.

Functions from dsp.interactivity

Here's all dsp.interactivity functions. This issue was created to decide on what to port and what to discontinue support due to how different is the approach for both APIs are.

All functions will be posted as separate comments.

The format for the comments are:

<code block>
function_signature(params)
</code block>
---
Description : [Documentation from dsp if exists]
Status : [Accepted, Postponed (Added if requested in the future), Rejected, Ported]
Reason : 

Relicensing

The current license is outdated and relicensing should be considered

Copyright (c) 2019 LoliDevs

Proposed license : CC BY-NC-SA

Major 2.0 Refactoring

⚠️ = Depends on : feature:interactivity.

Todo

Systems [Moved to #17]

  • Permanent disabling behaviour to systems.
  • Permament disabling functionality to the system disable command
  • setmaster command utilize RequireSystemAttribute since mastersystem can be disabled.
  • Display permanently disabled systems on system list command

Configuration Overhaul ⚠️

  • Add IConfig interface ⚠️
  • Port using configuration files to use new IConfig interface ⚠️
  • Disableable commands ⚠️
  • Disableable systems
  • Toggleable dsp internal logger ⚠️

Logger

  • Move newline to EOL for dsp logger compatibility

API Changes ⚠️

  • void -> Task on IApplyToClient ⚠️

QOL ⚠️

  • sensible indentation ⚠️
  • Remove testbed system
  • Use .WhenCanceled instead of while on SisbaseBot
  • Convert Aggregate queries to string.Join
  • Use preconditions whenever possible ⚠️
  • Replace nested foreach with linq queries whenever possible ⚠️
  • Update dsp version to latest

Provide easy message-level interactivity

Draft:
a function public Task<DiscordMessage> Interact(DiscordMessage), to be used like

var message = PrepareMessage();
var response = await Interact(message);

where response is the next message sent in the context of message (In the correct channel, and by the correct user).
For ease of use, also add overloads for any type that can be trivially converted into a DiscordMessage, such as Interact(DiscordEmbed), Interact(string), and Interact(Attachment).

Implementation notes:
DSharpPlus.Interactivity provides several useful functions to get the next message, but all are at a lower level than the proposed Interact

Make Interactions expire after a timeout.

Suggested default timeout: 5 minutes.
When an interaction expires, it should:

  • Be removed from the interaction registry and free resources (Close and Dispose)
    • Should Close be the same as Dispose? Consider the OnClose event.
  • Propagate cancellation to any task still using it

Main config file porting

The root of the config.json from 1.0 is the Data of 2.0 and could easily be converted to.

Example 1.0 Config file

{
  "Token": "token",
  "MasterId": 123456789012345678,
  "PuppetId": [],
  "Prefixes": [
    "u!",
    "s!"
  ],
  "CustomSettings": {}
}

Example 2.0 Config file

{
  "Path": "C:\\Users\\roridev\\Development\\sisbase\\sisbase.Test\\bin\\Debug\\netcoreapp3.1/Config.json",
  "Data": {
    "Token": "token",
    "MasterId": 123456789012345678,
    "PuppetId": [],
    "Prefixes": ["s!"],
    "CustomSettings": {}
  }
}

Make possible to rename sisbase group names

Use case/scenario :
The user already has a config command/group, the build wouldn't be possible since there are a duplicate command.
With this behaviour implemented, that issue could be fixed since said user would be able to "rename" the sisbase's config group to E.g. sconfig, solving the conflict.

Make a way for systems to be interdependent

Use case : Lets suppose you made a Database as an ISystem and later use said database connection on a IClientSystem
On the case of said connection not being established the ClientSystem would return an error. Its possible for that to be implemented by the user but that could be added to the SMC codebase as a cleaner api, with the usage of a [Depends] Attribute.

List of issues waiting timeline unification

The following issues are on hold since it would make more sense to do them once a single timeline is achieved.

Refactoring

#5 - Major 2.0 Refactoring
#31 - Ambiguous reference for sisbase.Permissions
#32 - Improve unicode support
#25 - Localization
#46 - Purge static
#47 - SMC v3

Looking at alternative api wrappers

D#+ has some weird design decisions, that had to be completely redesigned on sisbase. If all of DSP's features that we rely upon need complete rework/ constant workarounds it may be beneficial to migrate to another wrapper that provides a purer implementation of the discord api.

This issue was pushed from being a 3.0 Candidate to a 2.0 Candidate.

Remove dependence on static singleton Instance of SisbaseBot

In particular, the areas where SisbaseBot.Instance are currently used are the SMC (being the legacy code that it is), and to access Sisbase infrastructure from commands (which belong to D#+.CommandsNext, and currently have no way to access the bot).

  • The conversion of SMC to a property on each bot instance should be fairly trivial
  • Accessing the "active" sisbase instance from within a command may be harder
    • currently, we are investigating CommandsNext dependency injection as a way to deliver the instance to the command, but it's possible that if D#+ doesn't allow a way to avoid boilerplate while doing this, we will reject that solution and have to find something else. Boilerplate is unacceptable.

Menu Api

Adds a Menu abstraction in order to add create menus with embeds.

Said api must provide support for a discordembed to be used as a display and buttons for the user interaction.

Buttons must be dynamically added and have a limit of 20 buttons (due to discord api limitations).

Proposed usage:

var testMenu = new Menu {
    Embed = EmbedBase.OutputEmbed("Test"),
    Buttons = new Dictionary<DiscordEmoji, Func<Task>> {
        [emojiA] = emojiAClicked,
        [emojiB] = emojiBClicked
    },
    Behaviour = ButtonBehaviour.Action
};

Proposed sisbase Implementation:

class MenuIconActions : IDisposable {
    Dictionary<DiscordEmoji, Func<Task>> actions;
    DiscordMessage menu;
    DiscordClient client;

    MenuActionIcons(DiscordClient c, DiscordMessage menumsg) { 
        menu = menumsg;
        client = c;
        client.ReactionAddedEvent += Dispatch;
    }

    async Task Dispatch(ReactionAddedEvent e) {
        if(e.Message != menu) return;
        var action = actions.TryGetValue(e.Emoji);
        if (action = null) return;
        await action();
    }

    void Register(DiscordEmoji emoji, Func<Task> action) => actions[emoji] = action;

    void Dispose() {
        client.ReactionAddedEvent -= Dispatch;
    }
}

SystemManager (SMC 3.0) API specification

Here is the currently proposed SystemManager API specification

  • Modify the current SMC structure to :
-- interface IStaticSystem
-- interface IClientSystem
++ abstract class BaseSystem 
++ abstract class ClientSystem : BaseSystem
  • BaseSystem will expose SisbaseBot SisbaseInstance
  • ClientSystem will expose DiscordClient Client

Getting a system in a command

class command : SisbaseCommandModule {
  public SystemType System = SisbaseInstance.Systems.Get<>();
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.