Jump to content

Untested (Very Long) Plugins Guides (w/ Example)


gooby
 Share

Recommended Posts

IMPORTANT! You must build your apps from the most recent upstream/development branch in order to have all the fixes and usages shown in this guide so it runs properly. You must also follow all the nuances or else your plugin may not work, so I highly suggest you use the In-Depth guides first.

 

Introduction

Spoiler

This guide is made to help you get acquainted with the plugin system. I'll show you how to create, compile, and install plugins for your game. Although this is mostly a client-focused plugin walkthrough, it basically applies to the server, with the exception of it missing some callbacks (see Plugin Capabilities section below).

 

Plugins are made in the form of DLLs and go into the respective client or server resources/plugins folder (the folder may not exist, so just create it).  You may also see the Examples folder in the main directory of the development and prerelease branches for Panda's plugin examples.

 

Ideally, you should separate your Client and Server plugin scripts to avoid errors. This also prevents others from decompiling your Client plugin DLL's and seeing your Server plugin code. It's also unnecessary to try running Client plugin code on your Server. You may also need a third project that acts as the "Core" project with classes both the client and server need access to, such as packets (not handlers!).

 

For example, if you only want to make a client based plugin (like a main menu Discord button), you only need one project for the client. Same goes for a server only plugin, like a custom post-hook packet handler. However, if you want to add custom packets and handlers to communicate between client and server, you will need three new projects (for Core, Client, and Server DLLs).

 

FAQs

Spoiler

Q: How do I compile the example plugin?

A: I don't know, I couldn't get it to compile either...

 

 

Plugin Capabilities

Spoiler

What it CAN do

Spoiler
  • Can draw a Discord button and other custom GUI
  • Add custom network packets and handlers
  • Can capture custom inputs
  • See the Sample Plugins section for more...

 

What it CAN'T do

Spoiler
  • Server does not have a GameUpdate callback
  • Cannot draw any non-GUI sprites or text on client
  • Custom inputs are not easily customizable like they are in the options menu.

 

 

Plugin Overrides and Callbacks

Spoiler

Plugin Overrides

Spoiler

The base callbacks are OnBootstrap, OnStart, and OnStop and are available on both the client and server. See the script template below for more info as it is well-commented and provides some example code.

 

OnBootstrap

Spoiler

This method is called during application bootstrapping, before OnStart is called. This method is ideally used for registering custom packets and handlers.

 

OnStart

Spoiler

This method is called after basic initialization of the client. This is where you should assign any of your necessary variables, such as loading custom assets (explained later in the guide), and subscribe to Lifecycle callbacks.

 

OnStop

Spoiler

This method is called when the app is shutting down. I have yet to find a use for this.

 

 

Client Lifecycle

Spoiler

The Client lifecycle consists of several stages:

  • Intro - during the start of the application before the menu is loaded
  • Menu - when at the main menu
  • Loading - the time when loading into the game, and when exiting the game and loading the menu
  • InGame - when in the game
  • Error - internal use, we don't need this

 

Interface

Spoiler

Returns a reference to the currently loaded interface. This can be either the menu UI or the game UI. Later, I'll show you how to use this to draw your own GUI.

 

Drawing GUI

Spoiler

Drawing GUI requires you to add Gwen Controls to the current interface. You can add Gwen Controls to the current interface using context.Lifecycle.Interface.Create<Control>(). You can find a full list of base controls in the other project: "Intersect.Client.Framework/Gwen/Control".

 

The Create<> method will sometimes require parameters. This depends on the control you are creating and their constructor. You can ignore the first parameter of the constructor, which is always Base parent. The rest of the parameters are what you have to add.

 

For example, Button's constructor is public Button(Base parent, string name = ""), so you must pass a string for its name like so: context.Lifecycle.Interface.Create<Button>("ButtonName"). For controls like RadioButton, the constructor contains no extra parameters besides the (Base parent), so nothing needs to be passed.

 

Note that the interface will be null in OnStart. It can only be called when the main menu or the game is loaded, which ensures their respective interface has been created. Use the context.Lifecycle.LifecycleChangeState callback for that, then create your control.

 

The interface might still be null when you try to add a control to the main menu. For some reason unknown to me, the Menu ChangeState event gets called twice. The first time it's called, the interface will be null. So before adding your control, check: if (context.Lifecycle.Interface == null) return;

 

See the Drawing GUI section in detailed guide below for more information.

 

 

There are a few callbacks to subscribe to in OnStart to get more information about GameState changes and updates:

 

LifecycleChangeState

Spoiler

Invoked once whenever the GameState changes. For example, if you only want to draw something in the menu (like a Discord button), you would call the method to show the button if the args.State is GameStates.Menu.

 

GameUpdate

Spoiler

Invoked once per frame in any state. This callback is useful for getting inputs, keeping track of time, etc. It should be more useful in the future as more capabilities are added to the plugins.

 

 Capturing inputs

Spoiler

This is a bit more complicated and tedious than I'd like, but still totally doable.

 

In OnStart, you need to subscribe to the Intersect.Client.Core.Input events with two methods (one to handle key/mouse pressed and the other to handle key/mouse released) where both have only a Intersect.Client.Framework.GenericClasses.Keys parameter.

 

You will also need to keep track of the keys changed that frame when the events are invoked. I used a Dictionary<Keys, bool> in the example below that is indexed by the Key pressed and if it was pressed (false) or released (true) in that frame.

Optional: You may make your own KeyStates enum or add a reference to Microsoft.Xna.Framework.Input to get that enum.

 

Then in the LifecycleUpdate callback, you just need to check if the dictionary has the key you want and if it was up or down using YourDictionary.TryGetValueDon't forget to clear your dictionary at the end of the Update!

 

You may go further and only allow key inputs in a certain game stage, i.e. only in game to show custom in-game menus.

 

Here is an example script:

 

 

 

 

Server Lifecycle

Spoiler

coming later

 

(Currently contains nothing of use.)

 

 

Client Plugin Script Template

Spoiler

 Here is a Client plugin template I created if you want to get started quickly. You will just need to change your namespace and the class name, or just copy the contents of the class to yours.

(A server script will look very similar, you just wouldn't have the lifecycle callbacks.)

 

Last updated: 18 July 2021

 

Client Plugin Guide w/ Discord Example

Spoiler

TL;DR:

Spoiler
  1. Create a new branch from the latest upstream/development branch.
  2. Create a class library (DLL) project in the solution. Make sure to keep your client and server plugin projects separate.
  3. Create an appropriately named class in the folder that inherits from ClientPluginEntry or ServerPluginEntry. (Optionally, do this in a new folder in your plugin project.)
  4. Create another class for your Manifest. Copy and paste the example manifest (https://pastebin.com/KuhUQgND) and change the namespace and author information accordingly.
  5. Create another class for your Configuration that inherits from PluginConfiguration. Implement as many exposed properties as you wish. The app will automatically generate a JSON file when running your plugin. You can reference your config using: context.GetTypedConfiguration<YourConfig>()?.YourProperty.
  6. (Client plugin only) Subscribe to both context.Lifecycle events in OnStart.
  7. Add your custom images and other assets to your project, preferably in a separate folder. Make sure to set the "Properties > Build Option" to "Embedded Resource". You can reference them using: context.ContentManager.LoadEmbedded.
  8. Drawing GUI requires you to add Gwen Controls to the current interface. You can add Gwen Controls to the current interface using: context.Lifecycle.Interface.Create<Base>("ControlName"). (You can find a full list of base controls in: Intersect.Client.Framework/Gwen/Control.)
  9. Compile the plugin by cleaning then building your project/solution. Copy your DLL to your respective client or server's resources/plugins folder. If it doesn't exist, then make it. The project won't automatically create it. You must create another folder in this directory that has the exact same name as your DLL. Then, paste your DLL in the folder with the same name.
  10. Finally, run your application. It should automatically detect your plugin(s) and run them!

 

In-Depth Discord Button Example

This section is targeted more to beginners, but each step has a TL;DR that might be useful to follow for more informed users.

Spoiler

Creating a new DLL Project

TL;DR: Create a new project in VS2019 using the class library (DLL) template targeting the current project framework (currently .NET Framework 4.6.2).

Spoiler

Open Visual Studio 2019 and create a new project.

Spoiler

5088923411387e1d63f0515df8dc897a.png

 

Search 'dll' for the class library (DLL) template, select it, and press 'Next'.

Spoiler

7e4a65aa4eaa65b14511ac2be4dc882a.png

 

Name your project. Set your save path. Make sure the 'Framework' field is set to whatever Intersect's current target framework is (currently .NET Framework 4.6.2), then click 'Create'.

39519ecf70f2944909416f2d215d16b5.png

 

Installing Intersect's NuGet Packages

TL;DR: Add the client or server framework package via NuGet to automatically add all the dependencies you'll need. Just press 'OK' if the 'Preview Changes' window pops up.

Spoiler

After your project is created and opened, the first you'll want to do is install Intersect's framework dependencies. There are two options according to what plugin you want to make: server or client. (You can always make another project in this solution for the other one.)

 

Right-click your project and select 'Manage NuGet packages...'

Spoiler

d91aea17ef51689132a234794c98dbd1.png

 

Search for 'intersect' and the packages should show up. (If it doesn't, make sure your package source is 'nuget.org'.) Then, double-click and install the framework according to your plugin. We will use the Client framework for this guide. It should take a few minutes. If the 'Preview Changes' window pops up, just press 'OK'.

Spoiler

1d272e2e885d5f50fef0d3c67e806143.png

 

 

Setting the Build Target

Spoiler

The last bit of setup we need to do requires you to make a file so your plugin solution will build using the given dependency.

 

Navigate to your computer's home directory (on Windows: "C:\Users\<name>", Mac: "/Users/<name>", Linux: "/home/<name>"). Create a new text file and rename it, including the extension, with "intersect.developer.targets".

Spoiler

b015e671f0e44c666a59ee15a949a534.png

 

Open the file with a text editor and copy-paste these contents into it:

Spoiler




<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <IntersectDeveloperTargetsImported>true</IntersectDeveloperTargetsImported>
    <IntersectRepoPath Condition="$(OS) != 'Windows_NT'">$(HOME)/intersect/network-optimizations</IntersectRepoPath>
    <IntersectRepoPath Condition="$(OS) == 'Windows_NT'">$(USERPROFILE)\intersect\network-optimizations</IntersectRepoPath>
  </PropertyGroup>
  <Target Name="BeforeBuild">
    <Message Importance="High" Text="INTERSECT_REPO_PATH=$(INTERSECT_REPO_PATH)" />
    <Message Importance="High" Text="INTERSECT_PATH=$(INTERSECT_PATH)" />
    <Message Importance="High" Text="IntersectRepoPath=$(IntersectRepoPath)" />
    <Message Importance="High" Text="IntersectPath=$(IntersectPath)" />
  </Target>
</Project>

 

 

Change the corresponding path under 'PropertyGroup' (if Windows, change the one that says "OS == Windows", else change the other one) and the 'INTERSECT_REPO_PATH' to your Intersect repo's directory. Then, make sure to restart Visual Studio.

Here's mine for comparison:

Spoiler




<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <IntersectDeveloperTargetsImported>true</IntersectDeveloperTargetsImported>
    <IntersectRepoPath Condition="$(OS) != 'Windows_NT'">$(HOME)/intersect/network-optimizations</IntersectRepoPath>
    <IntersectRepoPath Condition="$(OS) == 'Windows_NT'">D:\GitHub\Intersect-Engine</IntersectRepoPath>
  </PropertyGroup>
  <Target Name="BeforeBuild">
    <Message Importance="High" Text="INTERSECT_REPO_PATH=$(D:\GitHub\Intersect-Engine)" />
    <Message Importance="High" Text="INTERSECT_PATH=$(INTERSECT_PATH)" />
    <Message Importance="High" Text="IntersectRepoPath=$(IntersectRepoPath)" />
    <Message Importance="High" Text="IntersectPath=$(IntersectPath)" />
  </Target>
</Project>

 

 

Note: If you still have issues building the plugin later on, try deleting the '.vs' folder in your plugin project's directory.

 

Organizing the DLL project

TL;DR: Create a new folder in your plugin project with a descriptive name. Create an appropriately named class in the folder that inherits from ClientPluginEntry.

Spoiler

Organization is important in getting the DLL to work.

(Optional: You may delete the Class1.cs file that's already in your project if you want.) 

 

Create a folder in your project and name it whatever you want, preferably to reflect what plugin you're making. I'll name mine "DiscordButton". If you have multiple plugins, folders are important.

Spoiler

1b101ff8ba58dc7d6b52f1b5471f8cf6.png

 

In that folder you can create a new class, preferably the same name as the folder. I'll name mine "DiscordButton.cs".

Spoiler

887a1fcc7033049ac9072db388191e8f.png

 

Creating your custom plugin class

Spoiler

Your custom class must inherit from 'ClientPluginEntry'.

Spoiler

e35bcdd29e53ed210103a9628d68e847.png

 

'ClientPluginEntry' will be underlined in red. All you need to do is add the

using Intersect.Client.Plugins;

statement at the top.

Spoiler

9f29ecc58892538e42ce2979cdf0f545.png

 

Now the base class name should be underlined in red. This is because we need to implement the base abstract class. To do this, select the class name, and click the little lightbulb icon on the left or press 'Alt + Enter' to bring up the 'Potential Fixes' menu. Then, select 'Implement abstract class'. It will automatically generate the methods you need: OnStart and OnStop.

Spoiler

f731288167de299201c49b136de2c355.png

 

You should also remove the exceptions to leave the methods empty so the process doesn't get stopped when running the DLL. Your class should now look like this:

Spoiler

a39cc1ff53cd21306773528af84cd84a.png

 


Defining a Manifest

TL;DR: Create another class adjacent to your custom plugin entry. Copy and paste the example manifest in this section and change the author information accordingly.

Spoiler

Another thing the plugins require is a manifest. The manifest is defined as another C# class with the author's information.

 

Create another class in your custom plugin folder so it's alongside your plugin entry class and name it something appropriate. Mine will be 'DiscordButtonManifest'.

Spoiler

69c0616212cc2a8a260058d7809d374b.png

 

Admittedly, I copied the code from the example and changed it to fit my needs. Here's Panda's original example manifest:

 

 Do not change the struct name just yet! 

 

You'll notice many errors in the document. Adding these using statements at the top should fix it:

Spoiler




using Intersect.Plugins.Interfaces;
using Intersect.Plugins.Manifests.Types;
using Intersect.Utilities;
using Semver;

 

 

(Optional) Finally, if you want to change the name, select the struct name and press 'Ctrl + R + R'. This will bring up the renaming menu for you to change. Also, make sure to change the 'Author' and 'Homepage' field information to your own profile/website.

 

Here is this example's manifest script for comparison:

 

 

Creating a Configuration File

TL;DR: Make another appropriately named class for your config that inherits from PluginConfiguration. Implement as many exposed properties as you wish. The app will automatically generate a JSON file when running your plugin.

Spoiler

Now, you can make a plugin with just the manifest and it'll work. It will generate an empty config file for you. So, you can skip this step if you don't want to do it right now, but I highly recommend coming back and adding properties to your config for modularity; so you don't always need to change the code in order to change the plugin values. Instead you would change your property values via a JSON file in your plugin's directory, like you'd do with the GUI layouts, for example.

 

That being said, make a new class in the same subfolder as your other scripts and call it something appropriate. I'll name mine 'DiscordButtonConfig'.

Spoiler

a54b8a49abdfabff45ef43136da7bcce.png

 

Your class must inherit from 'PluginConfiguration', which requires the 'using Intersect.Plugins;' using statement at the top.

Spoiler

0e106e618cbcef3bd59bc4e3872b1834.png

 

That's it for the config setup! Now, you just need to add properties you want to read from your plugin entry class. For this discord button example, I'm just going to add a string to the invite URL.

Spoiler

8f9b09ecaf07a3fa3493f2af1bfda587.png

 

Referencing your config file

You can reference your config file and its properties from your plugin entry script as such:




     var propertyRef = context.GetTypedConfiguration<YourConfig>()?.YourProperty;

where the 'context' is a reference to the client context (provided by the callback methods), 'YourConfig' is the name of your config script, and 'YourProperty' is the property or field you want to reference. See the provided example or keep reading for more details.

 

 Using the Client Lifecycle

TL;DR: Subscribe to both context.Lifecycle events in OnStart.

Spoiler

Please see the Client Plugin Overrides and Callbacks section or the script template for more info about the lifecycle.

 

You can get access to the Lifecycle from the context parameter. Make sure to include the "using Intersect.Client.General;" using statement at the top.

Spoiler

0586d8d7b89cf182d9255914a86c9f3a.png

 

You can open a switch statement for the args.State for both callback method to specify the GameState.

Make sure to include the "using Intersect.Client.General;" to get access to the GameStates enum.

Spoiler

a1924e25282e728477b9da7327289629.png

 

 

Adding custom assets

TL;DR: Add your custom images and other assets to your project, preferably in a separate folder. Make sure to set the 'Properties > Build Option' to 'Embedded Resource'. You can reference them using context.ContentManager.LoadEmbedded.

Spoiler

The plugin system is able to load embedded assets to be used in your plugin. For example, for a Discord button, you'll probably need an image that says "Join our Discord!" or something.

 

Make another subfolder in your plugin folder where all the scripts are, and call it "Assets" (you can name this whatever you want).

Spoiler

562467f9e04b1a491133c6fa3551ee0d.png

 

You can then right-click the folder, hit 'Add > Existing item' and choose the image, or just drag and drop it on the folder. (I'm stealing this from Panda's example as well. :P)

Spoiler

936631a27c9c9744a5966573c1037398.png

 

This part is crucial for loading the asset. Right click the file you added and select 'Properties'. Then change its "Build Action" to "Embedded Resource". 

Spoiler

a21d9b3a0b7a7ae536d89393dd73a30e.png

 

Referencing the asset

You can use the built-in Content Manager to load embedded resources in your DLL. Just make sure your subdirectory is correct. Here would be the example reference:




context.ContentManager.LoadEmbedded<GameTexture>(
    context, ContentTypes.Interface, "DiscordButton/Assets/join-our-discord.png"
);

 

 

Drawing GUI

TL;DR: You can add Gwen Controls to the current interface using context.Lifecycle.Interface.Create<Base>("ControlName"). You can find a full list of controls in the other project: "Intersect.Client.Framework/Gwen/Control".

Spoiler

The current Interface can be accessed from context.Lifecycle. You need to use this interface to add controls by using its Create function. You can create any Gwen base control, such as Button, ImagePanel, Label, etc. There is a full list of controls in Intersect.Client.Framework/Gwen/Control folder. 

 

These will require a "using Intersect.Client.Framework.Gwen.Control;" statement.

Creating a control also requires exactly ONE argument, which is the control's name. You can name this whatever you want. For example, the discord button will be created as such:




    var button = context.Lifecycle.Interface.Create<Button>("DiscordButton");

From here on you can change the settings of these controls like you normally would. 

 

(If you wanted more info about how to use these controls, well... it's out of the scope of this tutorial. You can see the full example script in the next step to get an idea, but Gwen controls are a different tutorial for a different day.)

 

Coding the actual plugin

TL;DR: This section is not that long dude.

Spoiler

After all the setup, we can finally program the plugin! This will depend on what you are doing. For this example, we will draw the GUI button in the bottom right corner of the main menu.

 

The script looks like this:

 

 

Compiling and Installing the Plugin

TL;DR: Compile the plugin by cleaning then building your project/solution. Copy your DLL to your respective client or server's resources/plugins folder. If the directory doesn't exist, then make it. The project won't automatically create it. You must create another folder in this directory that has the exact same name as your DLL. Then, paste your DLL in the folder with the same name.

Spoiler

To compile the plugin, simply right click your project and select "Clean", then right-click again and select "Build". (If you are having issues building, go back to the "Setting the Build Target" section.)

Spoiler

915f6efe2c8af533fc82ebe9c7b45472.png

 

The plugin will be created in your default directory in a folder under the same name.

Spoiler

dba60792b006d5dbf525116f39864dbc.png

 

Go into your folder and navigate to bin/debug/YourPluginName.dll. This will be the file you copy and paste into your client plugins folder.

Spoiler

b2875dee49a57f7e6cef0ba2dafaa51e.png

 

Go into your client (or server) folder, then navigate to resources/plugins. If the folder doesn't exist, create one.

Spoiler

15e2e10214a7023f175ce27080d3036b.png

 

This is an important step: you must create another folder that has the same name as your DLL. Mine would be "Client.Plugins". Then paste your DLL into that folder.

Spoiler

8d5732032eecee692c0fd8625fbcba21.png

 

And that's it! If you built your client with the proper development version, and everything went well, your plugin should now work!

Spoiler

6b029cf4241f86b34f58f2efe1c1819b.png

 

 

 

 

  Adding Custom Packets and Handlers

Spoiler

Note: You will need all three (Core, Client, and Server) plugin projects to make custom packets. See TL;DR above if you don't understand what this means. However, this section assumes you already went through the detailed example guide and know how to add references on your own (basically hit Alt+Enter on any errors and add the reference).

 

Setting up the Packet class

Spoiler

Packet classes must go into your Core project because both the Client and Server plugins will need to reference them. Create a new class that inherits from IntersectPacket in your Core project. Your Core plugin project will need to reference Intersect's Core project because it needs the MessagePack namespace.

 

MessagePack requires you to use the [MessagePackObject] attribute on your class. Each one of your declared fields (if any) must also have the [Key(#)] attribute, where # indicated a number. They need to be numbered in order starting from 0.

(MessagePack might also require a parameterless constructor to work. I've got it to work without one, but not always... so, if you create a constructor with parameters, I'd also create an empty one just to be safe. Needs confirmation.)

 

Example packet class:

Spoiler



using Intersect.Network;
using MessagePack;

namespace Core
{
    [MessagePackObject]
    public class ClientTestPacket : IntersectPacket
    {
        [Key(0)]
        public string Message;
    }
}

 

 

 

Setting up the PacketHandler class

Spoiler

Packet handler classes go into your respective Client or Server projects. Create a new class in the project that inherits from IPacketHandler<YourPacket>. This will require a project reference to your Core Plugins project. You will then need to implement the abstract class which will create two different Handle methods, both with two parameters.

 

The one with the generic "IPacket packet" parameter (likely the second one) just needs to call the other Handle method. Most of the time, it'll look like this:

Spoiler



public bool Handle(IPacketSender packetSender, IPacket packet)
{
    return Handle(packetSender, packet as YourPacket);
}

 

 

The other method just needs to handle the packet as you wish.

Spoiler



public bool Handle(IPacketSender packetSender, YourPacket packet)
{
    // Your packet handling logic here
    return true;
}

 

 

For this section's ongoing example, it'll just print the message sent and the class would look like this:

Spoiler



using System;
using Core;
using Intersect.Network;

namespace Server
{
    public class ClientTestPacketHandler : IPacketHandler<ClientTestPacket>
    {
        public bool Handle(IPacketSender packetSender, ClientTestPacket packet)
        {
            Console.WriteLine("Received client msg:" + packet.Message);
            return true;
        }

        public bool Handle(IPacketSender packetSender, IPacket packet)
        {
            return Handle(packetSender, packet as ClientTestPacket);
        }
    }
}

 

 

 

Registering Packets and Handlers

Spoiler

Registering packets and handlers is done in OnBootstrap because you need its context. You must register all of your custom packets that you will handle or send. Below is a simple example; ideally you should also log errors and close the app if the registry fails.

Spoiler



public override void OnBootstrap(IPluginBootstrapContext context)
{
    RegisterPackets(context);
    RegisterPacketHandlers(context);
}

void RegisterPackets(IPluginBootstrapContext context)
{
    context.Packet.TryRegisterPacketType<ClientTestPacket>();
    context.Packet.TryRegisterPacketType<ServerTestPacket>();
}

private void RegisterPacketHandlers(IPluginBootstrapContext context)
{
    context.Packet.TryRegisterPacketHandler<ServerTestPacketHandler, ServerTestPacket>(out _);
}

 

 

 

Sending packets

Spoiler

On the client:

The PacketSender can be referenced using the ClientContext provided by OnStart and Update methods. For example:

Spoiler



context.Network.PacketSender.Send(new ClientTestPacket 
{ 
    Message = "Hello server, I'm client" 
});

 

 

On the server:

Currently, the PacketSender is only available via packet handlers. For example, if we use the code above to send a message from the client to the server, the server can then send a message back in its ClientTestPacketHandler method:

Spoiler



public class ClientTestPacketHandler : IPacketHandler<ClientTestPacket>
{
    public bool Handle(IPacketSender packetSender, ClientTestPacket packet)
    {
        Console.WriteLine("\nReceived important Client msg:\n" + packet.Message +"\n");
        packetSender.Send(new ServerTestPacket { Message = "Hello client, am serv" });
        return true;
    }

    public bool Handle(IPacketSender packetSender, IPacket packet)
    {
        return Handle(packetSender, packet as ClientTestPacket);
    }
}

 

 

 

 

Conclusion

Spoiler

This guide should have helped you compile, create, and install your plugins successfully. You have a working Discord button plugin for your client at the very least. While this plugin system has lots of potential as it is, it still needs work, and it is still being worked on time to time.

 

If you have any questions or comments about plugins or how to improve this guide, please leave them below!

 

Link to comment
Share on other sites

this is amazing, way more convenient than work and release niche/game specific mods in .patch files (for the non-programmer users, may be as easy to drag n' drop the compiled plugins ! ) 
-> in the other hand, wouldn't it open the risk of sus/infected plugins being distributed in the future? convenience may often come with few cons, yet this is amazing, thanks for this guide!

Link to comment
Share on other sites

8 hours ago, Arufonsu said:

this is amazing, way more convenient than work and release niche/game specific mods in .patch files (for the non-programmer users, may be as easy to drag n' drop the compiled plugins ! ) 
-> in the other hand, wouldn't it open the risk of sus/infected plugins being distributed in the future? convenience may often come with few cons, yet this is amazing, thanks for this guide!

Yeah i suppose youre right... so dont download and install DLLs from strangers! :P 

Link to comment
Share on other sites

Dude you explained everything about plugins and explained how to create plugins and detailed how the discord button plugin works as if you were talking to monkeys and that was EXACTLY what I needed. Thank you so much for taking the time to create something so (not so anymore) complex. I'm learning C# (when I have time) so as soon as possible I'll follow your tutorial and get back to you if everything went well.

Link to comment
Share on other sites

9 hours ago, Arufonsu said:

this is amazing, way more convenient than work and release niche/game specific mods in .patch files (for the non-programmer users, may be as easy to drag n' drop the compiled plugins ! ) 
-> in the other hand, wouldn't it open the risk of sus/infected plugins being distributed in the future? convenience may often come with few cons, yet this is amazing, thanks for this guide!

I mean all of you downloaded Intersect for years before it was open source. :P If anything, the plugin system could open up an easier avenue for people to make cheats for games.

Link to comment
Share on other sites

On 7/20/2021 at 8:09 AM, panda said:

I mean all of you downloaded Intersect for years before it was open source. :P

Guess i joined in the party sort of late, it was already Open Source when i first found about you guys :3_grin:
The security risks are always going to be there anyway, not something we should ignore and simply let anyone release any .dll around forums without double checking that everything is safe!

Anyway, that was just a small offtopic that people tend to forget about :35_thinking:, didn't meant to bring down the party to anyone and i think myself that this right here is a big step into the moon for this game engine :77_alien: cheers u guys, and once again, thanks for this guide @gooby !

Link to comment
Share on other sites

@gooby I finished reading and writing your tutorial today, I loved it, I'm not a programmer and I barely know how to program, I only know very basic concepts and the way you explained I understood everything perfectly well, I could even put the button inside the game (if (lifecycleChangeStateArgs.State == GameStates.Menu || lifecycleChangeStateArgs.State == GameStates.InGame)) ( just to test if it would work and it did). Thanks for your time in doing this.

8f0f7ae2cbf7afa8a20cf72b45a37b46.png

 a29f5540d1f7cba51797712b3b42eabd.png

I would like to know (in case you want to add it in your tutorial in the future as an optional thing), how to generate those json files that are generated in the gui so we could change the position of the button through the json file, how does it work for the rest of the interface? It would be possible?

Link to comment
Share on other sites

8 minutes ago, Weylon Santana said:

I would like to know (in case you want to add it in your tutorial in the future as an optional thing), how to generate those json files that are generated in the gui so we could change the position of the button through the json file, how does it work for the rest of the interface? It would be possible?

 

Somewhere in the code for that button there will be a line to load the ui from json. If that json file is not found, it will be created with default/empty values automatically in which you can then modify. (So you don't need to worry about manually creating the json file)

Link to comment
Share on other sites

1 minute ago, jcsnider said:

 

Somewhere in the code for that button there will be a line to load the ui from json. If that json file is not found, it will be created with default/empty values automatically in which you can then modify. (So you don't need to worry about manually creating the json file)

Are you referring to this plugin code? https://pastebin.com/eQyTJHp1(At the end of the tutorial this is what the main script looks like) or to the official intersect plugin that panda made?

Link to comment
Share on other sites

3 hours ago, Weylon Santana said:

I would like to know (in case you want to add it in your tutorial in the future as an optional thing), how to generate those json files that are generated in the gui so we could change the position of the button through the json file, how does it work for the rest of the interface? It would be possible?

 

yeah what they said ^

 

you could also add those values to your config script and then people could just modify them through the JSON it generates. then, just load those values before drawing your button in the plugin script :) 

Link to comment
Share on other sites

4 hours ago, gooby said:

 

yeah what they said ^

 

you could also add those values to your config script and then people could just modify them through the JSON it generates. then, just load those values before drawing your button in the plugin script :) 

I like it, this is a good alternative, I will try to look at how the url property value is obtained and I will try to replicate for position and size, I will do that soon, can I call you in discord if I have any questions, if doesn't bother you?

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...