Giter Site home page Giter Site logo

abnersquared / orikivo Goto Github PK

View Code? Open in Web Editor NEW
5.0 2.0 0.0 3.37 MB

A Discord bot that contains an ever-growing collection of fun mechanics and multiplayer sessions.

Home Page: https://abnersquared.github.io/Orikivo.Web/changelogs/arcadia

License: GNU General Public License v3.0

C# 99.87% Smalltalk 0.13%
discord-bot discord-net bot discord csharp text-formatting dotnet multiplayer discord-bot-framework

orikivo's Introduction

Orikivo

CodeFactor

Orikivo is a Discord bot library containing a wide range of helpful utilities, mechanics, and systems to incorporate a wide variety of fun things to do!

Invite Orikivo Arcade here!
View the most recent changelog here!

Contents

  • Orikivo: The primary and original library, containing all extensions and primary services used by most Discord bots in this area
  • Orikivo.Desync: This is a library focusing on RPG mechanics and features that handle pathfinding, early shopping mechanics, as well as a full-blown dialogue system
  • Orikivo.Drawing: This is a library that provides mathematical methods and graphical assistance, primarily towards rendering pixel art
  • Orikivo.Text: This is a library that provides an extensive set of text formatting tools and helper classes to make formatting text much easier
  • Orikivo.Net: This is a clone of Miki.Http.Net, which is no longer available, with additional utility classes included to make API requests faster
  • Orikivo.Framework: This is a library that provides the barebones of a Discord bot, offering a quick client builder, logging features, and other useful tools
  • Arcadia: This is the current libary focus, providing everything from achievements, quests, item mechanics, multiplayer, casino features, shopping, and other useful services for incorporating fun features

Contributing

Since this is my first time letting a project I've spent a while on go public, this might be a bit of a challenge for me. As of now, I will only accept contributions for issues that are explicitly marked with the tag tag:up for grabs. A StyleCop inclusion is currently planned in the future, but as of now, you can refer to a rough structure for how all code should look in REFACTORING_GUIDELINES.md. More will be fleshed out in the future in relation to this topic.

orikivo's People

Contributors

abnersquared avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

orikivo's Issues

Restructure code base

While this doesn't mean that everything has to be restarted, It would be helpful to take a few extra measures to implement an organized structure that:

  • Separates everything related to Discord
  • Keeps base class structures and models into their own namespace
  • Creates a layer between the actual classes performing work and their interface counterpart, which simply requests the method

Likewise, it might be a better idea to:

  • Separate all assets (items, merits, objectives, etc.) into a read-only database structure, so that editing is only handled directly
  • Replace all static helper classes into their own structure

With Orikivo, since it more than most likely might be cancelled, this should be re-structured so that everything that it offers can be more of a building template. Orikivo.Desync should also be completely isolated from Orikivo, as well as remove any requirements to Discord. The goal of this is to make it so that implementing APIs, as well as implementing this bot into other interfaces work in a much better format.

Orikivo library plans:

  • Remove global dependencies to Discord.Net as a whole, but instead isolate them so that they are only required in Orikivo.Discord instead, so that the base structure of Orikivo is kept separate
  • Create a database structure that is more on the generic side, so that JSON and other database libraries can be isolated into their own namespaces (i.e. Orikivo.Database.Json)
  • Remove BaseUser.Discriminator, as it isn't really utilized

Arcadia plans:

  • Tweak and re-structure the multiplayer system to be a bit more generic-friendly, as well as remove the requirement for requiring everything to have an explicit GameProperty reference (an example could easily be IPlayerBase, which can expose the base player, as well as the properties that the GameBase wishes to expose)
  • Isolate all command results into their own services to help keep the framework organized
  • Restructure all static helper classes into base interface services that can be called at any point
  • Restructure service results so that they can return a base result that from which can be formatted when handled in Discord
  • Move all asset-like objects into their own structures as Orikivo.Core, and isolate all methods into their own services, so that the core design of each model is kept in their own folder
  • Isolate all methods specified in ArcadeUser to their own service
  • Organize boost formulas and mechanics so that it is handled at the same location of which updating user values are

Orikivo plans:

  • Restructure Orikivo so that all base and common classes that are often inherited can easily be requested in Orikivo.Core instead
  • Tweak and delete redundant message extensions that might not be required to implement
  • Create base service interfaces for each required service
  • Seperate actual service functions with interface calls, so that the requirement of Discord for those services can be isolated
  • Separate InfoService to be the new default alternative to CommandService
  • Create a proper command framework to be placed instead in Orikivo.Framework.Commands
  • Move several utility classes over to Orikivo.Text

Orikivo.Text plans:

  • Isolate all AsciiEngine systems into their own public class

Orikivo.Drawing plans:

  • Since this library is primarily created to simply System.Drawing, as well as add a few new mathematical helpers, it might be wise to scrap Graphics3D, as it was mainly used as a test. Graphics3D can be placed and archived into its own library instead. Graphics2D might also be isolated, and any unique classes dedicated to the Orikivo structure can instead be handled in Orikivo.Graphics.

Orikivo.Desync plans:

  • Make the Engine class instead become a generic interface of IDesyncService, which will handle all mechanics from there. DesyncService will be the internal version that exists, so that the interface can call the methods, but not require explicit exposure to the actual structure

Orikivo.Framework plans:

  • Overhaul the logging system, so that it implements a more friendly and generic interface structure

Create custom command parser

As one of the steps needed to separate Orikivo from the entire Discord.Net library, a custom command parser needs to be created. This can utilize Orikivo.Text.StringReader to handle all of the input parsing, but a base structure for commands still needs to be specified.

Rough Steps:

  • Create class CommandParser
  • Introduce a method to parse a raw input into a CommandParseResult, which should contain:
    • The Command that was specified
    • The parameters that the input has specified
    • If the parse was a success
    • The reason the parse failed, if any
    • The options that the input has specified, if any (See #41)

Once this is implemented, you can use the CommandParser class as an internal structure that is applied to each MessageReceived event.

This should follow the general structure:

  • A message is received from a Discord-based client
  • The message is then converted into a friendly equivalent for parsing
  • The input provided is then passed over to the parser
  • The command parser will then attempt to collect and find all of the best matching commands
  • If a command could not be found, return the closest match and include it in the CommandParseResult
  • If a command could be found, pass the matching command over along with its input to a command processor
  • The command processor will then look at all of the specified preconditions the matching command has
  • If a precondition is not met, the command result is returned as a failed attempt
  • If all preconditions were met, the command result is now passed back into the command handler
  • If there are any early prerequisites for the command, they would be handled here if any of them failed
  • The command is then executed in the command handler
  • If there are any late prerequisites for the command, they would be handled here
  • Once a command is executed, an event called CommandExecuted would be invoked, containing the CommandResult from the command
  • The CommandResult contains everything needed to apply, such as a possible ratelimit, if accounts need to be updated, and the content that was returned

Store guild IDs to server connections

Storing guild IDs to server connections is required to calculate how many active servers are open within a guild. This is intended to pair with server configuration, which can disable game servers entirely.

Implement stats for blackjack

Blackjack doesn't currently have any connected stats to its session handler. A couple of good starting stats would be blackjack:times_played and blackjack:times_won.

Fix CodeFactor issues

This is a difficult task due to the current count of files in comparison to issues. However, they are all currently simple fixes (aside from complex methods).

Create auto-removing expired cooldowns

This is needed to remove cooldowns that might already be expired. The only exception in this case would be cooldowns that are still needed when the next request or update is called (in this case, the daily system).

Create challenge provider

Challenges are intended to be smaller-scale versions of quests. They are relatively quick to complete, and offer small rewards as a result. The upside to this is that challenges are always available. You are given a set of challenges, and are rewarded for each set you complete. After completing 3 sets, the reward pool for challenges would decrease, resulting in less income, but still available.

Include required assets

Orikivo and Arcadia both require specific assets in order to properly function. It might help by including /assets/ folders in each of their respective project folders, and by copying them into the build files on each compile.

Enforce StyleCop and other code ettiquette

This is mainly needed to help retain consistency across Orikivo as a whole. Since the code has been worked on across several months, some areas of the code are inconsistent, and need clean-up. This should also remove all of the comments that tend to span across files (excluding TODO: or REF:).

Implement weekly bonus game

This should allow Orikivo to randomly select a game once a week to mark it as the game that would reward extra experience for playing.

Rough Steps:

  • Create a property in ArcadeData called BonusGameId
  • Create a property in ArcadeData called BonusAssignedAt
  • Create a method in GameManager called GetOrAssignBonusGame, which randomly selects a new bonus game or loads the existing one if it has not yet expired

Overhaul game base framework

โš ๏ธ This is a requirement before any further games can be added.

Revision

Hierarchy

The way the hierarchy of how connections are established feels a bit off, as players can have direct message channels that can also be subscribed to a game server. The new approach makes both players and connections inherit from a base class called IReceiver, which is a base class that subscribes to an IBroadcast, the core foundation of what is displayed and determines the game state of a receiver. In this approach, you can now detect if a receiver is a direct message channel, and games can now prohibit the initialization of receiver connections if they are initialized from a direct message channel.

The new structure framework is as shown:

public interface IBroadcast { }

public interface IReceiver { }

public interface IPlayer : IReceiver { }

public interface IConnection : IReceiver { }

Groups

Because of this new change style, receiver grouping is now handled by the subscription. As a result, specifying group IDs are no longer required.

Server Structure

The game server structure can remain as is, but instead adding a new method called GetReceivers(), which would return the summed result of all receivers, which include players now. This can be used to group up multiple channels to be subscribed to a single broadcast, so that updating the broadcast updates all receivers connected to it instead. Likewise, each receiver can receive individual messages if needed, such as notifying a single player about a specific event in a game that nobody else should see.

Broadcast Initialization

Since broadcasts are now the primary focus for handling content between receivers, building a collection of broadcasts are now going to be in a class called GameChannel, which stores the previous DisplayContent and InputController as mentioned before. This way, all new broadcast copies are initialized with a GameChannel reference, from which their contents are copied onto the broadcast, so that each broadcast can update and modify the content within.

Original Approach

Framework

The GameBase class is currently a bit sloppy on how it handles things, and is even missing plenty of handling methods for certain events. This includes:

  • A player joining mid-game
  • A player leaving mid-game
  • A player being removed for idling too long
  • A server connection being removed mid-game
  • A game being soft-locked (nothing is updated for 3-5 minutes)

Tasks

The new approach for what each method should return is now going to ensure that all methods return as a Task, to retain thread safety and locking for games that can potentially freeze. Some may return results (an example being Task<IReadOnlyList<TPlayer> OnBuildPlayers(in IEnumerable<Player>), but this new approach will be handy for future use when it comes to asynchronous handling.

Variant Generics

The new design of the GameBase would include methods relating to these features, which would require the GameManager to now provide support for said methods. Likewise, to further support the new game property concept, the way player data is handled is going to have to be modified. As such, the GameBase class will now have a generic variant, utilizing a new IPlayerData interface to work with on it's inferred version as well. An example of this would be GameBase<TriviaPlayer>, where TriviaPlayer would store all of the properties that is needed for the TriviaGame class, while at the same time, keeping the other methods that already exist for flexibility. Building players in this new approach become much easier to handle.

Sessions

Due to this new approach, game sessions as a whole can easily just be the game itself. As such, the GameSession class is going to merge with the generic GameBase class to provide all of the methods related to queuing actions, specifying spectator frequency, activity bar, and player data. This should make it much easier to handle in games.

Connections

The way game connections are handled are a bit messy at the moment, as none of them represent or inherit a base interface. Instead of ServerConnection and PlayerChannel being separate, the new approach is to implement an interface called IConnection, which will specify all required properties for every connection. The structure of IConnection is as follows:

public interface IConnection
{
    // If a connection is disabled, is it completely ignored from updating and input handling
    bool Disabled { get; }

    // These are used to determine which broadcast the connection is pointing towards
    string Group { get; }
    int Frequency { get; }
    GameState State { get; }
    // This would be base representative values that the connection can modify at any point in time.
    // These values would be marked as protected, as these don't need to be exposed to a common use case
    TextDisplay Display { get; }
    InputController Controller { get; }

    // These are base endpoint values that are required for each connection
    Discord.IMessageChannel Channel { get; } // The channel that the message is stored in, used to recover in case of deletion
    Discord.IUserMessage Message { get; } // The message that this connection is displaying
    bool CanSendMessages { get; } // Determines if a connection is allowed to receive messages

    // These methods indirectly handle the connection display content
    Task<bool> UpdateAsync();
    Task<bool> DestroyAsync();
    Task<bool> ReplaceAsync();
}

The new TextDisplay and InputController classes are specified in further depth below. The goal of this approach is to be able to create a base framework for connections to further simplify approaches.

Players

While the current state of players is decent, there are a couple of areas that it falls short in:

  • Sending messages to players becomes a hassle, as there's no real easy way to allow them to have a content or broadcast
  • Determining if a player can support direct messages isn't handled before the game, which can lead to issues

The new approach would be to make the Player class inherit IConnection. While this sounds odd at first, this would now allow all players to easily be able have a direct channel content override. This can now be used to check if a player can receive messages, which can be toggled off at any point in time that a message being sent is returned as an HTTP Error 50007: Forbidden. This value can then be used for verification before a game starts that requires all players to have direct messages open. If any player ends up setting it up as forbidden mid-game, the player will be kicked immediately, with the new game method OnPlayerRemoved being invoked in place of it to handle the player's properties beforehand. A couple of methods originally specified in PlayerChannel will be transferred over to the Player class now to reduce overall complexity.

To further improve handling for games, a new interface called IPlayerData will be included. This works exactly the same as PlayerData, but instead of having the properties be stored in a List<GameProperty>, the values would now be stored in the inheriting class, where all properties that are marked are included in the set, now returning an IReadOnlyList<GameProperty> instead. The positive to this approach is that handling player data during games will become much easier.

Broadcasts

This overhaul is going to completely revamp server connections that point to broadcasts are handled. Due to the ability of retaining data for a class by object reference, referencing broadcasts become much easier to implement. The new approach for broadcasts (aside from renaming it to better fit from DisplayBroadcast to GameBroadcast) is to essentially be a compact storage for what is currently being displayed for this broadcast alongside what everyone connected to this broadcast can control. While that is currently the case, it isn't modular at the moment.

This would modify GameBroadcast to store the visual display in TextDisplay (previously DisplayContent), and to store all input reading in InputController (previously a property List<IInput> Inputs). The same approach can then be applied to all generic IConnection values now, so that each individual connection can explicitly specify their own displays and input. If either is left null, it will instead refer to the broadcast that the connection is currently pointing to.

The TextDisplay class will follow this structure:

public class TextDisplay
{
    public IEnumerable<ITextComponent> Components { get; }

    // ContentOverride is used to override what the components are currently displaying
    public string ContentOverride { get; set; }

    // This method is where all of the components are drawn
    public override string ToString();
}

Likewise, the InputController class will follow this structure:

public class InputController
{
    // As before, this is the collection of possible inputs that this controller stores
    public IEnumerable<IInput> Inputs { get; }

    // This is used to completely prevent input from being read
    public bool Disabled { get; set; }
}

Properties

How game properties are stored and retrieved become very tedious. As an example of how annoying it can get, here's an example:

OnExecute = delegate(InputContext ctx)
{
    var data = ctx.Session.DataOf(ctx.Invoker.Id);

    if (data.ValueOf<bool>("has_answered"))
        return;

    var answerSelected = CurrentAnswers.ElementAt(0);

    data.SetValue("has_answered", true);

    if (answerSelected.IsCorrect)
    {
        data.AddToValue("streak", 1);
        data.AddToValue(TriviaVars.TotalCorrect, 1);
    }
    else
    {
        data.ResetProperty("streak");
    }

    ctx.Session.AddToValue("players_answered", 1);
    data.SetValue("answer_position", ctx.Session.ValueOf<int>("players_answered"));
    ctx.Session.InvokeAction("try_get_question_result");
}

The reason for this is that all values that a game requires is stored in the GameSession, with its original purpose being to remove the requirement of needing to keep a GameBase in memory. It was obvious that ended up not being case, which completely removes the need for this in the first place. After weighing the pros and cons, I've found that:

+ Games don't need to create custom classes for each type, as all values are stored in PlayerData
+ The complexity of type inheritance is simplified, as type casting doesn't really need to occur in relation to games overall

- Retrieving properties become drastically more difficult than it should be, as a method needs to be called on each occasion
- Retrieving properties immediately require casting for each stored value, which can easily cause errors on minor invalid type specification

To help keep the positives of this approach in play, I've decided to go with an Attribute-based approach, which would allow the creator of the game to explicitly specify which properties they would want to be able to retrieve globally by marking the property with a IncludePropertyAttribute.

To further improve upon this framework, this would include ReadOnlyAttribute as another feature to make sure that the property that is read is read-only, meaning that it cannot be modified during a game session, but can be modified before-hand.

Other methods would be implemented, such as PropertyExists(string) to check if a property exists before comparing, and PropertyEquals(string, object) to indirectly check if the property equals the specified value without explicit casting before returning.

This can be fine-tuned to throw an error on an invalid type specification, but by default, it would simply return false if invalid. Sadly, casting is still a requirement for methods such as ValueOf<T>(string), since it can't be implicitly inferred. The generic ValueOf(string) is still a plausible approach for those who can do something else with the value though.

To clean up the game base framework, it would split GameBase into two variations, GameBase, and GameBase<TPlayer>. The properties that the game stores would now be specified in the class itself, but as mentioned earlier, can be marked as a property that is retrieved when wanting to view a collection of properties. Here is a rough example of this approach:

public sealed class TriviaGame : GameBase<TriviaPlayer>
{
    [IncludeProperty("players_answered")]
    public int PlayersAnswered { get; private set; }
}

Now instead of having to use session.ValueOf<int>("players_answered"), this is now a simple PlayersAnswered. The goal of this approach is to reduce complexity when handling the game mechanics itself, while at the same time, retaining the flexibility of handling properties outside of the GameBase classes for other features, such as criteria for a challenge.

Returning to that previously verbose method, it can reduced down to this now:

OnExecute = delegate(InputContext ctx)
{
    // TriviaPlayer would inherit a form of IPlayerData, which would still provide the methods relating to game properties
    TriviaPlayer data = ctx.Session.DataOf(ctx.Invoker.Id);

    if (data.HasAnswered)
        return;

    var selectedAnswer = CurrentAnswers.ElementAt(0);

    data.HasAnswered = true;
    data.SetValue("is_correct", answerSelected.IsCorrect);

    if (selectedAnswer.IsCorrect)
    {
        data.Streak++;
        data.TotalCorrect++;
    }
    else
    {
        data.Streak = 0;
    }

    PlayersAnswered++;
    data.AnswerPosition = PlayersAnswered;
    ctx.Session.InvokeAction("try_get_question_result");
}

Add unit tests

Unit tests would be a nice feature to include for Orikivo to easily verify methods that might be very detailed in how it handles.

  • Add unit tests for Var validation
  • Add unit tests for Booster validation
  • Add unit tests for experience validation
  • Add unit tests for all casino game modes
  • Add unit tests for all multiplayer game modes
  • Add unit tests for items
  • Add unit tests for merits
  • Add unit tests for quests
  • Add unit tests for cooldowns
  • Add unit tests for text formatting

Overhaul multiplayer text system

The multiplayer framework has a weak text system, often relying a lot on the Draw() method. This overhaul should make it much easier to handle text formatting.

Rough Steps:

  • Replace Component to TextContainer
  • Create an abstract class BaseTextContainer
  • TextContainer values should utilize a set string format, with variables that can be specified in it
  • TextContainer values should mimic the Buffer system from the original Component classes
  • TextContainer values should have more methods related to formatting, such as markdown implementation, padding and text alignment, and other scenarios
  • TextListContainer should also be implemented as a way to easily introduce lists, similar to ComponentGroup
  • TextListContainer should have base text formatting, individual element formatting, and a separator
  • TextContainer values should now be able to specify a character limit to block off extremely long lines of text
  • TextContainer values should include automated pagination support, which can be peeked at by jumping to an index
  • To prevent out of range errors, TextContainer pagination methods should revolve around TryMoveNext, TryMovePrevious, First, Last, which will attempt to jump to the specified pages
  • All missing text values in a TextContainer should instead be noted by a INVALID_VALUE or a VALUE_NOT_SPECIFIED, as opposed to errors
  • Errors can easily be toggled depending on how severe text issues are
  • The BaseTextContainer class should be easily accessible and customizable
  • The BaseTextContainer class should expose core methods and properties that inheriting classes can manipulate or modify for their own purpose

Split message result from method results

While it may sound confusing at first, the intention of this issue is to split the literal message result from executed methods. An example would be Gimi, where all of the stats that are updated are handled alongside the money to give and such. You would split that so that the message that method sends is handled in one method, while the base method is handled in another. This is to simplify and group methods to make it easier to edit and/or update without the risk of running into issues in-between them.

Add usage examples for usable items

This is to allow the user to understand how to use an item. An example would be Gift Wrap, where you would need to type the usage as use t_gw <data_id>, where data_id would be referring to an item data that the user currently has.

Create interface IParseable<T>

This interface would be used to allow classes to be able to specify a few generic methods that are commonly used, such as Parse() and TryParse().

Create command options

Commands that have a lot of variety should introduce an easier way to specify options. This would incorporate the introduction of command options.

The goal of this is to allow commands to easily specify optional parameters that the main command does not require. Note that this would not be for simple scenarios, such as excluding the page index, but instead for scenarios where a user would want to pull up a listed version of a specific command where details aren't important.

This can go two routes:

Route A: Command options are specified by using the OptionAttribute, which requires the specification of the enclosing type, the name of the option (and aliases). These options would then be handled in the CommandParser class (see #40), where the class would retrieve all custom option attributes, and attempt to parse each one. An error would be thrown if there is a duplicate option with the exact same name (only for the parsed name result, not just colliding names in general).

Route B: Command options are marked on optional parameters in a method by using the OptionAttribute. The specification of a name is optional, but is not required. Options cannot be specified on a required parameter. These options would also be handled in the CommandParser class, where the parser would ignore all optional parameters marked with the specified attribute, separating them into their own list instead to be handled. This might be the better approach to take, as this would make it easier to manipulate parameters directly from a method, instead of imposing a result load requirement in the body of each command that has options. The result containing each respectively parsed option would be stored in a class called OptionContainer, where it would be passed to the executing method that would return a CommandResult (see #42) for the module.

The rough structure of a command using the OptionAttribute would look like this:

[Module("Demo")]
public class DemoModule : BaseModule
{
    private readonly DemoService _service;

    [Command("command")]
    public async Task<CommandResult> RunCommandAsync(
        string required,
        int page = 1,
        [Option("tooltips")]bool showTooltips = false)
    {
       return await _service.RunCommandAsync(Context.Options);        
    }
}

Create API for Arcadia

This is a hefty inclusion, but can be paired with Orikivo.Net to provide a working API system. The API should be able to provide data for:

  • Users
  • Guilds
  • Items
  • Shops
  • Merits
  • Objectives

Likewise, it should also be able to provide:

  • Item icons
  • Merit icons
  • User-generated cards
  • Changelogs
  • Search filters

If a OAuth is utilized, it should be able to allow:

  • Editing of user config
  • Using items
  • Inspecting current merits
  • Inspecting items
  • Using items
  • Buying items from shops

Example methods:

GET | Get merit
GET | Get item
GET | Get user inventory
POST | Update card config
POST | Update user config
POST | Update guild config
GET | Get user
GET | Get guild
GET | Get user card
GET | Get user merits
GET | Get user stats
GET | Get user stat
GET | Get leaderboard
POST | Use item
POST | Sell item
POST | Buy item

Create JSON migration service

This should be a quick utility class that can help with transferring all existing JSON files to import them in a database. In this case, it would be used for MongoDB once it has been established, so that users do not lose their data.

Change all services to return the result to modify instead of the message

An example would be inspecting an item. A service called ItemService would instead be in place, with the method ViewItem(IUser invoker, string id) in place, returning an object of type Item. For Discord, the Item provided would be passed over to a message builder (such as CatalogWriter.ViewItem(ArcadeUser, Item)) to send into the channel. For a website, the Item provided would be handled in another class of sorts that would display the item in its own way. In short, all services need to provide the MODEL that is being handled, instead of the RESULT of the execution.

Automatically update on new releases

This system should be able to automatically update once a new GitHub release is posted. An event would be invoked that notifies the bot that an update was released, which would then attempt to pull and extract the new files from that release. Once that is complete, the bot would then restart, and launch again by using the new files, effectively replacing all old files. This would possibly mean that a console application framework would have to be created, so that it can be possible to initialize inner executable files automatically, without closing the true program session.

Create inventory pagination

The inventory display should be able to support pagination. The command for viewing inventories of other users can be renamed to inventoryof, while an extra overload for the main inventory command can be paired, to prevent username/page collision. Another nice thing to include would be to display the total count of each item in a specific group, shown as simple counters on the header. This can be easily resolved using the Paginate class in Orikivo.Text.

Example:
image

Create command results

All module classes should incorporate a base result class that contains more information than the base result that was specified. This would introduce a class called CommandResult, where it would contain details about the result of a command.

The class would be structured in this format:

  • The Command that was executed
  • The account that executed the command
  • If the command was a success or not
  • The raw input that was given for this command
  • The reason this command result failed, if any (can store exceptions as well, in a class called CommandError)
  • The TextBody that was provided for this command result, if any (if the command failed, this is null)

The CommandResult class can effectively be utilized to handle the updating of cooldowns and other scenarios. Likewise, The result of a command can be ignored entirely, and instead passed over to an event called CommandExecuted instead, which would be provided by a CommandService class (similar to Discord.Commands.CommandService). The event parameters would contain only a CommandResult.

Separate server connection channels that are initialized during a game session

Game sessions have the ability to create and initialize new server connection channels for specific players and such when it is required. Since they aren't created with the intent to remain as an open channel for players, they should be automatically removed once a session is destroyed. Another possible solution could be to instead use the PlayerChannel class, which can handle sending and/or updating current messages for a session.

Remove players from server if their DMs get disabled mid-game

This minor issue is intended to fix some errors that could occur when a player disables their DMs during a game session. The simple fix would be to attempt to send a message to that player, and if an HTTP error occurs with the code of 50007, you would then remove the player from the game, and handle it from there.

Isolate Arcadia into its own solution

Because Orikivo currently contains the code structure for two completely different bots, it might be better to have Arcadia in its own solution to be kept separate from the rest of Orikivo.

Create player auto-kick handlers for GameBase

The GameBase should have AFK handling during an active game session to automatically send players back to the lobby and/or kick them if they are inactive for too long. An AFK counter can be made to where if the player fails to respond to actions for a set amount of time, they would then be kicked accordingly.

Reduce multiplayer service complexity

This focus is to reduce the complexity and confusion plenty of the multiplayer classes have. Some of the ways to mitigate this can be to break down methods into smaller methods, reduce the number of unique classes the framework uses, simplify message handling mechanics, and to simplify the display portion used with server connections.

Create player removal handlers for GameBase

When a player is removed from a game session during an active game, it can lead to a lot of issues and possibly soft-lock a game. The solution would be to create a couple of handlers for when a user is removed from a guild or game session, and pass those down to the GameBase class. If the specified user matches any of the players, they are removed from the session. Their properties can then be accessed one last time before the player is disposed to handle any issues that could occur then.

Create text template system

The purpose of this system would provide immense help when it comes to creating returning bodies of text for a command. More will be filled on this later.

Isolate Arcadia.Multiplayer into its own library

Due to the complexity that the multiplayer framework has, I figured it would be better to isolate that entire library into its own project. The steps needed to perform this task would be:

  • Remove all game searching and selection methods from GameManager, instead creating a GameManagerConfig class that can be used to specify the default game ID, alongside the collection of available games
  • Move all game information methods into the GameViewer class
  • Place all available games into Assets, from which GameManagerConfig can store as a property
  • Move all remaining classes into a new project Arcadia.Multiplayer
  • Place all games specified in Arcadia.Multiplayer.Games into a folder in Arcadia/Discord/Games
  • Connect the new Arcadia.Multiplayer library to Arcadia as a reference

Move assets to an external file

The Assets class, while useful, should not be stored as a static readonly class. To further reduce the amount of static classes Arcadia stores, this class should instead be stored as a JSON file of some sort, where all of the files are loaded when the bot starts, preventing any external changes until the next launch.

Change leaderboard to be a service instead

This is a simple issue, but is needed to maintain consistency with models and services. Since the Leaderboard class doesn't exactly need to store variables, it can instead be handled as a service.

Have Orikivo.Drawing use System.Drawing.Color classes instead

Classes such as:

  • GammaPalette
  • Gamma

These set of classes aren't exactly flexible in how they are used, as they are primarily focused towards providing a set of 8 colors for card palettes, as that is the limit intended. What this fix intends to do, is transfer these inflexible classes over towards their namespace, from which it's better suited for. Orikivo.Drawing is intended to be a freeform graphics class.

Implement levelling criteria

This would allow the specifications of criteria requirements that the user needs to meet alongside the expected experience. This can be used to further provide challenges and active participation for levelling up.

Store merit unlock data in a Var instead

This change would reduce the total amount of unique data entries for a user that would be needed.

The steps for this would be to:

  • Get the DateTime at which this merit was unlocked
  • Convert the DateTime into ticks, and divide it by TimeSpan.TicksPerSecond
  • Multiply the ticks by 10 to provide an extra 0
  • The extra zero can then be used to specify if the merit rewards were claimed or not (as 0 or 1)

Add auto-timeout for game servers

As of now, game servers are always left open with nothing set to handle idle servers. The solution would be to create a timer that expires after a set amount, containing the method to close the game server automatically if no responses are sent.

Shift player and game data over to GameBase instead of GameSession

The GameBase class is currently a hallow handler for how games are played out, with the GameSession storing all player and game data. The issue with this is that because the data classes are interpreted as generic, retrieving values requires object casting, which can be taxing in the long run for games that constantly manipulate data. The solution would be to instead make GameBase store player data, with the PlayerData class being abstract instead, with the methods using System.Reflections to find properties that are explicitly marked with the GamePropertyAttribute. Keep in mind that marking properties with the GamePropertyAttribute is only really needed if the value from the game session is intended to be viewed outside of the GameBase class itself.

Have recipes be referenced by their resulting item ID

While recipes are in a good state, one of the smaller issues is that their ID can be a bit troublesome to copy/paste sometimes. A good solution would be to instead group up all recipes by their resulting item ID instead, so that whenever the recipe is searched, it will return all variations of that specific item.

Allow parameter references from a command

This should add methods to the CommandNode class that allows the referencing of parameters, so that it can be easier to display in several cases. This would be paired with #33 to properly display arguments.

Create loading screens for game sessions

The main reason for this is to allow a game session to load in all reactions to a message for games that require it to be initialized beforehand. The loading screens can then also randomly give tips and such for the current game while the reactions are added.

This would be handled as so:

  • The host of a server starts the game
  • The GameManage checks the GameBase to see if there are any inputs that require reactions to be added
  • If the GameManager finds one, The broadcast updates the primary server broadcast to a loading screen
  • Immediately right after, the GameManager iterates through all reaction inputs and adds them to the message body
  • Once all of the reaction inputs are placed on the message, the game now starts as normal

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.