Skip to content

Commit

Permalink
Add GitHub action, improve logging throughout system + exception reco…
Browse files Browse the repository at this point in the history
…very
  • Loading branch information
Mooshua committed Aug 11, 2023
1 parent 3969756 commit 7b75c94
Show file tree
Hide file tree
Showing 13 changed files with 206 additions and 55 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: BitMod.Tests

on: [push, pull_request]

jobs:
test:

runs-on: ubuntu-latest
strategy:
matrix:
framework-version: [ 'net6.0' ]

steps:

- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: '7.0.x'
dotnet-quality: 'ga'

- name: Install dependencies
run: dotnet restore
- name: Build for ${{ matrix.framework-version }}
run: dotnet build tests\BitMod.Tests --framework ${{ matrix.framework-version }} --configuration Release --no-restore
- name: Test for ${{ matrix.framework-version }}
run: dotnet test tests\BitMod.Tests --framework ${{ matrix.framework-version }} --configuration Release --no-build --no-restore --verbosity normal
52 changes: 21 additions & 31 deletions .idea/.idea.BattleBit.Core/.idea/workspace.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 59 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,60 @@
# BitMod

An elegant BattleBit: Remastered modding framework designed to enable plugins of all kinds to operate
simultaneously on the same API server.

## Introduction

BitMod features four kinds of "callback" objects: **Events**, **Hooks**, **Producers**, and **Mutators**.
Each handles a different API call used by the BattleBit gameserver. BitMod chooses which event to use based
on a callback's first argument. Callbacks are implemented as [lilikoi containers](https://github.com/Mooshua/Lilikoi/blob/dev/Docs/containers.md).

**Events** are one-off alerts that do not require any form of response:
```cs
public class MyPlugin
{
[BitEvent]
public Task OnPlayerDied(PlayerDiedEvent ev)
{

return Task.CompletedTask;
}
}
```

**Hooks** expect a response of either *Allow*, *Disallow*, or *Neutral*. The first plugin to express
an opinion will have it's opinion selected. Plugins are executed in ascending order of priority (0 = highest, 255 = lowest).
The priority is specified by the plugin.

**Events** are one-off alerts that do not require any form of response:
```cs
public class MyPlugin
{
[BitHook(32)]
public async Task<Directive> OnPlayerChatted(PlayerTypedMessageEventArgs ev)
{
// No hate speech!
if (ev.Message.Contains("i hate you"))
return Directive.Disallow;

return Directive.Neutral;
}
}
```

**Producers** produce a value out of thin air. Similarly to hooks, they are executed in ascending order of priority.
A producer can choose to either produce a value or do nothing. If a producer produces a value, then the chain ends.

Producers are used for when data is expected to appear out of thin air--For example, when loading or saving
player stats.

**Mutators** mutate the object created by the producer. They can choose to modify whatever values they want,
but are critically **not responsible for originally producing that data**. Mutators, similarly to events, will
always run regardless of what a mutator before it does.

## Contributors

| Who | What |
|-----------|---------------------|
| @Mooshua | Core library design |
| @moddedmcplayer | Event Arg Classes |
6 changes: 6 additions & 0 deletions api/BitMod/Environment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace BitMod;

public static class Environment
{
public static bool DoNotCatchEventExceptions = false;
}
9 changes: 6 additions & 3 deletions api/BitMod/Internal/Contexts/HookEventContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,19 @@ internal class HookEventContext

private HookEventRegistry _currentRegistry;

public HookEventContext()
private ILogger _logger;

public HookEventContext(ILogger logger)
{
_currentRegistry = new HookEventRegistry(new List<HookEventHandler>());
_logger = logger;
_currentRegistry = new HookEventRegistry(new List<HookEventHandler>(), _logger);
}

private void Rebuild()
{
_currentRegistry = new HookEventRegistry(_handlers
.SelectMany(kv => kv.Value)
.ToList());
.ToList(), _logger);
}

public void Remove(string pluginName)
Expand Down
11 changes: 8 additions & 3 deletions api/BitMod/Internal/Contexts/ProducerEventContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
using Lilikoi.Context;
using Lilikoi.Scan;

using Serilog;

namespace BitMod.Internal.Contexts;

internal class ProducerEventContext
Expand All @@ -17,16 +19,19 @@ internal class ProducerEventContext

private ProducerEventRegistry _currentRegistry;

public ProducerEventContext()
private ILogger _logger;

public ProducerEventContext(ILogger logger)
{
_currentRegistry = new ProducerEventRegistry(new List<ProducerEventHandler>());
_logger = logger;
_currentRegistry = new ProducerEventRegistry(new List<ProducerEventHandler>(), _logger);
}

private void Rebuild()
{
_currentRegistry = new ProducerEventRegistry(_handlers
.SelectMany(kv => kv.Value)
.ToList());
.ToList(), _logger);
}

public void Remove(string pluginName)
Expand Down
9 changes: 6 additions & 3 deletions api/BitMod/Internal/Contexts/SimpleEventContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@ internal class SimpleEventContext

private SimpleEventRegistry _currentRegistry;

public SimpleEventContext()
private ILogger _logger;

public SimpleEventContext(ILogger logger)
{
_currentRegistry = new SimpleEventRegistry(new List<SimpleEventHandler>());
_logger = logger;
_currentRegistry = new SimpleEventRegistry(new List<SimpleEventHandler>(), _logger);
}

private void Rebuild()
{
_currentRegistry = new SimpleEventRegistry(_handlers
.SelectMany(kv => kv.Value)
.ToList());
.ToList(), _logger);
}

public void Remove(string pluginName)
Expand Down
10 changes: 7 additions & 3 deletions api/BitMod/Internal/Public/PluginContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,19 @@ public class PluginContext
public PluginContext(ILogger logger)
{
_logger = logger;
Hooks = new (() => new HookEventContext(_logger));
Producers = new(() => new ProducerEventContext(_logger));
Simple = new(() => new SimpleEventContext(_logger));
}

public Mount Global { get; } = new Mount();

internal Router< HookEventContext > Hooks { get; } = new ();
internal Router< HookEventContext > Hooks { get; }

internal Router< ProducerEventContext > Producers { get; } = new ();
internal Router< ProducerEventContext > Producers { get; }

internal Router< SimpleEventContext > Simple { get; }

internal Router< SimpleEventContext > Simple { get; } = new ();

public void Load(string name, MethodInfo method)
{
Expand Down
20 changes: 16 additions & 4 deletions api/BitMod/Internal/Registries/HookEventRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,34 @@ namespace BitMod.Internal.Registries;

internal class HookEventRegistry
{
public HookEventRegistry(List<HookEventHandler> children)
public HookEventRegistry(List<HookEventHandler> children, ILogger logger)
{
children.Sort((a,b) => a.Priority.CompareTo( b.Priority ));
Children = children;
_logger = logger;
}

private ILogger _logger;

public List<HookEventHandler> Children { get; }

public Directive Invoke(EventInput input)
{
foreach (HookEventHandler hookEvent in Children)
{
var hookResult = hookEvent.Invoke(input);
try
{
var hookResult = hookEvent.Invoke(input);

if (hookResult != Directive.Neutral)
return hookResult;
if (hookResult != Directive.Neutral)
return hookResult;
}
catch (Exception ex)
{
_logger.Error(ex, "Hook failed during execution!");
if (Environment.DoNotCatchEventExceptions)
throw;
}
}

// Entire chain is completely neutral.
Expand Down
22 changes: 18 additions & 4 deletions api/BitMod/Internal/Registries/ProducerEventRegistry.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,40 @@
using BitMod.Internal.Handlers;
using BitMod.Plugins.Events;

using Serilog;

namespace BitMod.Internal.Registries;

internal class ProducerEventRegistry
{
public ProducerEventRegistry(List<ProducerEventHandler> children)
public ProducerEventRegistry(List<ProducerEventHandler> children, ILogger logger)
{
children.Sort((a,b) => a.Priority.CompareTo( b.Priority ));
Children = children;
_logger = logger;
}

private ILogger _logger;

public IReadOnlyCollection<ProducerEventHandler> Children { get; }

public Product Invoke(EventInput input)
{
foreach (ProducerEventHandler producerEvent in Children)
{
var product = producerEvent.Invoke(input);
try
{
var product = producerEvent.Invoke(input);

if (product.Exists)
return product;
if (product.Exists)
return product;
}
catch (Exception ex)
{
_logger.Error(ex, "Producer failed during execution!");
if (Environment.DoNotCatchEventExceptions)
throw;
}
}

// Entire chain is useless and produced nothing.
Expand Down
Loading

0 comments on commit 7b75c94

Please sign in to comment.