From 55f513c0715b1a0e7aaa5ed54be1259410c47663 Mon Sep 17 00:00:00 2001 From: AeonLucid Date: Sun, 25 Oct 2020 05:27:04 +0100 Subject: [PATCH] Added plugin documentation --- .github/ISSUE_TEMPLATE/api-invalid.md | 21 ++ .github/ISSUE_TEMPLATE/api-other.md | 4 + .github/ISSUE_TEMPLATE/api-suggestion.md | 22 ++ .github/ISSUE_TEMPLATE/api-unavailable.md | 16 ++ .github/ISSUE_TEMPLATE/feature-request.md | 2 +- docs/Writing-a-plugin.md | 244 ++++++++++++++++++++++ 6 files changed, 308 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/api-invalid.md create mode 100644 .github/ISSUE_TEMPLATE/api-other.md create mode 100644 .github/ISSUE_TEMPLATE/api-suggestion.md create mode 100644 .github/ISSUE_TEMPLATE/api-unavailable.md create mode 100644 docs/Writing-a-plugin.md diff --git a/.github/ISSUE_TEMPLATE/api-invalid.md b/.github/ISSUE_TEMPLATE/api-invalid.md new file mode 100644 index 0000000..2bf66f5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/api-invalid.md @@ -0,0 +1,21 @@ +--- +name: Api invalid data +about: To let us know about invalid data in the api +--- + +# Api missing data + +## Data + + +## Expectations + + +## Reproduce + diff --git a/.github/ISSUE_TEMPLATE/api-other.md b/.github/ISSUE_TEMPLATE/api-other.md new file mode 100644 index 0000000..4d461d3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/api-other.md @@ -0,0 +1,4 @@ +--- +name: Api other +about: For anything about the api that does not fit in the other issues +--- diff --git a/.github/ISSUE_TEMPLATE/api-suggestion.md b/.github/ISSUE_TEMPLATE/api-suggestion.md new file mode 100644 index 0000000..16ed0cb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/api-suggestion.md @@ -0,0 +1,22 @@ +--- +name: Api suggestion +about: To make suggestions for the plugin api +--- + +# Api Suggestion + +## Suggestion + + +## Use case + + +## Expected result + diff --git a/.github/ISSUE_TEMPLATE/api-unavailable.md b/.github/ISSUE_TEMPLATE/api-unavailable.md new file mode 100644 index 0000000..d71370d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/api-unavailable.md @@ -0,0 +1,16 @@ +--- +name: Api unavailable data +about: To let us know about unavailable data from the api that you would like to use +--- + +# Api missing data + +## Data + + +## Use-case + diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md index 87084b4..45341c0 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.md +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -1,5 +1,5 @@ --- -name: Feature Request +name: Feature request about: To ask and request new features with Impostor --- diff --git a/docs/Writing-a-plugin.md b/docs/Writing-a-plugin.md new file mode 100644 index 0000000..15afa6f --- /dev/null +++ b/docs/Writing-a-plugin.md @@ -0,0 +1,244 @@ +# Writing a plugin + +Impostor has support for plugins. This document will help you to setup a development environment for writing a plugin. + +- [1. Install .NET Core SDK](#1-install-net-core-sdk) +- [2. Create a C# project](#2-create-a-c-project) +- [3. Add the Impostor.Api library](#3-add-the-impostorapi-library) + - [Quick](#quick) + - [Visual Studio](#visual-studio) +- [4. The plugin class](#4-the-plugin-class) +- [5. Adding an event listener](#5-adding-an-event-listener) +- [6. Build and run your plugin](#6-build-and-run-your-plugin) +- [7. Extra](#7-extra) + - [Event listeners](#event-listeners) + - [Dependency injection](#dependency-injection) +- [8. Missing/invalid data or want more functions?](#8-missinginvalid-data-or-want-more-functions) + +## 1. Install .NET Core SDK + +Download and install the latest .NET Core SDK. + +https://dotnet.microsoft.com/download + +## 2. Create a C# project + +The first step is creating a new C# project, it must be a **Class Library (.NET Standard)**. The target framework can be any of those compatible with .NET 5, which includes: + +- .NET Standard 2.0 +- .NET Standard 2.1 +- .NET Core 3.1 +- .NET 5 + +For more information about compatibility, see https://docs.microsoft.com/en-us/dotnet/standard/net-standard. + +> At the moment of writing this document, I recommend you to use **.NET Standard 2.1** until .NET 5 is released officially. This should give you enough functionality. If not, upgrade to .NET Core 3.1. + +When the project has been created, you should have `Class.cs` and `Project.csproj` files. Your `Project.csproj` should look something like this. + +```xml + + + netstandard2.1 + + +``` + +## 3. Add the Impostor.Api library + +You only have to follow the instructions of one below. + +### Quick + +Install the `Impostor.Api` NuGet package. +Make sure to get a prerelease if you are writing a plugin for a dev release of the server. + +### Visual Studio + +1. Right click your project. +2. Click `Manage NuGet Packages`. +3. Click `Browse`. +4. Next to the search bar, enable `Include prerelease`. +5. Search for `Impostor.Api`. +6. Click the `Impostor.Api` result and press install on the right side. + +## 4. The plugin class + +Now the `Impostor.Api` is installed, you need to create a class for your plugin. A plugin **must** contain exactly one. See the code below for an example. + +```csharp +using System.Threading.Tasks; +using Impostor.Api.Events.Managers; +using Impostor.Api.Plugins; +using Microsoft.Extensions.Logging; + +namespace Impostor.Plugins.Example +{ + /// + /// The metadata information of your plugin, this is required. + /// + [ImpostorPlugin( + package: "gg.impostor.example", + name: "Example", + author: "AeonLucid", + version: "1.0.0")] + public class ExamplePlugin : PluginBase // This is also required ": PluginBase". + { + /// + /// A logger that works seamlessly with the server. + /// + private readonly ILogger _logger; + + /// + /// The constructor of the plugin. There are a few parameters you can add here and they + /// will be injected automatically by the server, two examples are used here. + /// + /// They are not necessary but very recommended. + /// + /// + /// A logger to write messages in the console. + /// + /// + /// An event manager to register event listeners. + /// Useful if you want your plugin to interact with the game. + /// + public ExamplePlugin(ILogger logger, IEventManager eventManager) + { + _logger = logger; + } + + /// + /// This is called when your plugin is enabled by the server. + /// + /// + public override ValueTask EnableAsync() + { + _logger.LogInformation("Example is being enabled."); + return default; + } + + /// + /// This is called when your plugin is disabled by the server. + /// Most likely because it is shutting down, this is the place to clean up any managed resources. + /// + /// + public override ValueTask DisableAsync() + { + _logger.LogInformation("Example is being disabled."); + return default; + } + } +} +``` + +## 5. Adding an event listener + +Currently you should have a plugin that loads and does nothing. In order to get some actual functionality, you need to add an event listener. + +Create a new class called `GameEventListener`. Example code: + +```csharp +using Impostor.Api.Events; +using Microsoft.Extensions.Logging; + +namespace Impostor.Plugins.Example.Handlers +{ + /// + /// A class that listens for two events. + /// It may be more but this is just an example. + /// + /// Make sure your class implements . + /// + public class GameEventListener : IEventListener + { + private readonly ILogger _logger; + + public GameEventListener(ILogger logger) + { + _logger = logger; + } + + /// + /// An example event listener. + /// + /// + /// The event you want to listen for. + /// + [EventListener] + public void OnGameStarted(GameStartedEvent e) + { + _logger.LogInformation($"Game is starting."); + + // This prints out for all players if they are impostor or crewmate. + foreach (var player in e.Game.Players) + { + var info = player.Character.PlayerInfo; + var isImpostor = info.IsImpostor; + if (isImpostor) + { + _logger.LogInformation($"- {info.PlayerName} is an impostor."); + } + else + { + _logger.LogInformation($"- {info.PlayerName} is a crewmate."); + } + } + } + + [EventListener] + public void OnGameEnded(GameEndedEvent e) + { + _logger.LogInformation($"Game has ended."); + } + + [EventListener] + public void OnPlayerChat(PlayerChatEvent e) + { + _logger.LogInformation($"{e.PlayerControl.PlayerInfo.PlayerName} said {e.Message}"); + } + } +} +``` + +## 6. Build and run your plugin + +Now your plugin is ready to be tested. + +1. Right click your project and press `Build`. +2. Right click your project and press `Open Folder in File Explorer`. +3. Go to `bin/Debug/netstandard2.1/`. +4. In this directory, you should find your plugin named `Project.dll`. +5. Copy the `Project.dll` to the `plugins` directory in your Impostor server directory. +6. (Re)start your Impostor server. +7. Open Among Us, create a game and send a chat message. In the console you should see your plugin being loaded and the messages from the example. + +## 7. Extra + +Some extra information that might be useful for those developing plugins. + +### Event listeners + +- You can have multiple event listener on the same event. +- An event listener can be given a priority `[EventListener(EventPriority.Normal)]` and is called in order. +- It is not recommended to block for a long time inside `EventListener` because the events are called from inside the packet handlers. Blocking too long causes the client to time out. You should create a new `Task` for operations that will take a lot of time. + +### Dependency injection + +- The main plugin class is constructed by the `IServiceProvider` of the server and can inject everything the server uses. A few examples are: + - `ILogger` + - `IEventManager` + - `IClientManager` + - `IOptions` + - `IOptions` +- You can add your own classes and `EventListener` implementation to the `IServiceProvider` by creating a new class and implementing `IPluginStartup`. Make sure to register them as a singleton `services.AddSingleton();`. + +## 8. Missing/invalid data or want more functions? + +The `Impostor.Api` is currently in beta. There are a lot of things still missing and we would like to hear from you what you need to develop a plugin. + +Create an issue: + +- [Suggest a function](https://github.com/Impostor/Impostor/issues/new?template=api-suggestion.md) +- [Data is invalid](https://github.com/Impostor/Impostor/issues/new?template=api-invalid.md) +- [Data is unavailable](https://github.com/Impostor/Impostor/issues/new?template=api-missing.md) +- [Other](https://github.com/Impostor/Impostor/issues/new?template=api-other.md) \ No newline at end of file -- 2.39.5