Skip to content

Commit

Permalink
Discord Bot, chat to players in game from discord channels
Browse files Browse the repository at this point in the history
  • Loading branch information
LiamKenneth committed Apr 4, 2023
1 parent 995d68c commit be22ece
Show file tree
Hide file tree
Showing 16 changed files with 338 additions and 37 deletions.
7 changes: 7 additions & 0 deletions .run/ArchaicQuest-All.run.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="ArchaicQuest-All" type="CompoundRunConfigurationType">
<toRun name="ArchaicQuestII.API" type="LaunchSettings" />
<toRun name="ArchaicQuestII.DiscordBot" type="DotNetProject" />
<method v="2" />
</configuration>
</component>
2 changes: 2 additions & 0 deletions ArchaicQuestII.API/ArchaicQuestII.API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@

<ItemGroup>
<PackageReference Include="BCrypt.Net-Core" Version="1.6.0" />
<PackageReference Include="Discord.Net.WebSocket" Version="3.10.0" />
<PackageReference Include="Microsoft.AspNet.SignalR.Core" Version="2.4.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.4" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.4" />
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="6.0.8" />
Expand Down
175 changes: 175 additions & 0 deletions ArchaicQuestII.API/Bot.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
using System;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using ArchaicQuestII.API.Controllers.Discord;
using ArchaicQuestII.GameLogic.Client;
using ArchaicQuestII.GameLogic.Core;
using ArchaicQuestII.GameLogic.Utilities;
using Discord;
using Discord.WebSocket;
using Microsoft.AspNetCore.SignalR;
using Newtonsoft.Json;

namespace ArchaicQuestII.DiscordBot;

public class Bot
{
private static ICache _cache;
private static IHubContext<GameLogic.Hubs.GameHub> _hubContext;
private DiscordSocketClient _client;
private static readonly HttpClient httpClient = new HttpClient();
public Bot(ICache cache, IHubContext<GameLogic.Hubs.GameHub> hubContext, DiscordSocketClient client)
{
_cache = cache;
_hubContext = hubContext;
_client = client;
}

public async Task MainAsync()
{
var config = new DiscordSocketConfig
{
GatewayIntents = GatewayIntents.AllUnprivileged | GatewayIntents.MessageContent | GatewayIntents.All
};
_client = new DiscordSocketClient(config);
_client.Log += Log;

//TODO: Rename to Discord TOKEN here and in the admin project
var token = _cache.GetConfig().ChannelDiscordWebHookURL;

await _client.LoginAsync(TokenType.Bot, token);
await _client.StartAsync();

_client.Ready += async () =>
{
_client.MessageCommandExecuted += MessageCommandHandler;
_client.UserCommandExecuted += UserCommandHandler;
_client.MessageReceived += ClientOnMessageReceived;

};
// Block this task until the program is closed.
await Task.Delay(-1);
}
public async Task UserCommandHandler(SocketUserCommand arg)
{
Console.WriteLine("User command received!", arg.CommandName);
}

public async Task MessageCommandHandler(SocketMessageCommand arg)
{
Console.WriteLine("Message command received!", arg.CommandName);
}
private async Task ClientOnMessageReceived(SocketMessage socketMessage)
{
await Task.Run(async () =>
{
//Activity is not from a Bot.

if (!socketMessage.Author.IsBot)
{

var username = socketMessage.Author.Username;
var authorId = socketMessage.Author.Id;
var channelId = socketMessage.Channel.Id.ToString();
var messageId = socketMessage.Id;
var message = socketMessage.Content;

var channel = _client.GetChannel(Convert.ToUInt64(channelId));
var socketChannel = (ISocketMessageChannel)channel;

var discordBotdata = new DiscordBotData() { Channel = "", Message = message, Username = username};
if (socketChannel.Name == "newbie-chat")
{
discordBotdata.Channel = "newbie";
}

if (socketChannel.Name == "ooc-chat")
{
discordBotdata.Channel = "ooc";
}

if (socketChannel.Name == "gossip-chat")
{
discordBotdata.Channel = "gossip";
}

if (!string.IsNullOrEmpty(discordBotdata.Channel))
{
await PostToNewbieChannel(discordBotdata);
}
}
});
}

public async Task<string> PostDataAsync(string url, DiscordBotData data)
{

var jsonData = JsonConvert.SerializeObject(data);

// create a StringContent object with the JSON data
var content = new StringContent(jsonData, Encoding.UTF8, "application/json");

// send a POST request using the static HttpClient instance
var response = await httpClient.PostAsync(url, content);
var responseContent = await response.Content.ReadAsStringAsync();
return responseContent;
}

public async Task PostToNewbieChannel(DiscordBotData data)
{
var message = $"<p class='newbie'>[<span>Newbie</span>] {data.Username}: {data.Message}</p>";

if (data.Channel == "ooc")
{
message = $"<p class='ooc'>[<span>OOC</span>] {data.Username}: {data.Message}</p>";
}

if (data.Channel == "gossip")
{
message = $"<p class='gossip'>[<span>Gossip</span>] {data.Username}: {data.Message}</p>";
}

foreach (var pc in _cache.GetAllPlayers().Where(x => x.Config.NewbieChannel))
{
await SendMessageToClient(message, pc.ConnectionId);
await UpdateCommunicationAll(message, data.Channel, pc.ConnectionId);
}

}

private async Task SendMessageToClient(string message, string id)
{
try
{
await _hubContext.Clients.Client(id).SendAsync("SendMessage", message, "");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

public async Task UpdateCommunicationAll(string message, string type, string id)
{
if (string.IsNullOrEmpty(message))
{
return;
}
try
{
await _hubContext.Clients.Client(id).SendAsync("CommUpdate", message, type);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}

private Task Log(LogMessage msg)
{
Console.WriteLine(msg.ToString());
return Task.CompletedTask;
}
}
65 changes: 65 additions & 0 deletions ArchaicQuestII.API/Controllers/Discord/DiscordController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using ArchaicQuestII.DataAccess;
using ArchaicQuestII.GameLogic.Character;
using ArchaicQuestII.GameLogic.Character.Config;
using ArchaicQuestII.GameLogic.Client;
using ArchaicQuestII.GameLogic.Core;
using ArchaicQuestII.GameLogic.Hubs;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;

namespace ArchaicQuestII.API.Controllers.Discord;

public class DiscordBotData
{
public string Channel { get; set; }
public string Message { get; set; }
public string Username { get; set; }
}


public class DiscordController : Controller
{
//private IHubContext<GameHub> _gameHubContext;
private ICore Core { get; }
private ICache Cache { get; }
public DiscordController(ICore core, ICache cache)
{
Core = core;
Cache = cache;
}


[HttpPost]
[AllowAnonymous]
[Route("api/discord/updateChannel")]
public Task<IActionResult> Post([FromBody] DiscordBotData data)
{
if (ModelState.IsValid)
{
PostToNewbieChannel(data);

}

return Task.FromResult<IActionResult>(Ok());
}

public void PostToNewbieChannel(DiscordBotData data)
{
var message = $"<p class='newbie'>[<span>Newbie</span>] {data.Username}: {data.Message}</p>";

foreach (var pc in Core.Cache.GetAllPlayers().Where(x => x.Config.NewbieChannel))
{
Core.Writer.WriteLine(message, pc.ConnectionId);
Core.UpdateClient.UpdateCommunication(pc, message, data.Channel);
}

}


}
21 changes: 17 additions & 4 deletions ArchaicQuestII.API/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;
using ArchaicQuestII.DiscordBot;
using ArchaicQuestII.GameLogic.Client;
using Discord.WebSocket;

namespace ArchaicQuestII.API
{
public class Startup
{
private IDataBase _db;
private ICache _cache;

private IHubContext<GameHub> _hubContext;
public Startup(IConfiguration configuration)
{
Expand Down Expand Up @@ -66,11 +67,13 @@ public void ConfigureServices(IServiceCollection services)

services.AddSingleton<IDataBase, DataBase>();
services.AddSingleton<IPlayerDataBase>(new PlayerDataBase(new LiteDatabase(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "AQ-PLAYERS.db"))));

services.AddSingleton<IWriteToClient, WriteToClient>((factory) =>
new WriteToClient(_hubContext, TelnetHub.Instance));
new WriteToClient(_hubContext, TelnetHub.Instance, _cache));

services.AddSingleton<IDataBase, DataBase>();

services.AddGameLogic();
services.AddGameLogic();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
Expand Down Expand Up @@ -110,6 +113,7 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IDataBas
});

_hubContext = app.ApplicationServices.GetService<IHubContext<GameHub>>();

app.StartLoops();

var watch = System.Diagnostics.Stopwatch.StartNew();
Expand All @@ -135,6 +139,15 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IDataBas

Console.WriteLine($"Start up completed in {elapsedMs}");
GameLogic.Utilities.Helpers.PostToDiscord($"Start up completed in {Math.Ceiling((decimal)elapsedMs / 1000)} seconds", "event", _cache.GetConfig());

try
{
new Bot(_cache, _hubContext, new DiscordSocketClient()).MainAsync();
}
catch (Exception ex)
{

}
}
}
}
3 changes: 3 additions & 0 deletions ArchaicQuestII.DiscordBot/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"DiscordToken": ""
}
1 change: 1 addition & 0 deletions ArchaicQuestII.GameLogic/ArchaicQuestII.GameLogic.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Discord.Net.Rest" Version="3.10.0" />
<PackageReference Include="Markdig" Version="0.30.2" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Core" Version="1.1.0" />
<PackageReference Include="MoonSharp" Version="2.0.0" />
Expand Down
1 change: 0 additions & 1 deletion ArchaicQuestII.GameLogic/Client/IUpdateClientUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ public interface IUpdateClientUI

void UpdateScore(Player player);
void UpdateCommunication(Player player, string message, string type);

void GetMap(Player player, string rooms);
void UpdateQuest(Player player);

Expand Down
2 changes: 2 additions & 0 deletions ArchaicQuestII.GameLogic/Client/IWriteToClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@ public interface IWriteToClient
void WriteLine(string message);
void WriteLineRoom(string message, string id, int delay);
void WriteToOthersInRoom(string message, Room room, Player player);
void WriteToOthersInGame(string message, Player player);
void WriteToOthersInGame(string message, string type);
}
}
6 changes: 1 addition & 5 deletions ArchaicQuestII.GameLogic/Client/UpdateClientUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,10 @@ public async void UpdateScore(Player player)

public async void UpdateCommunication(Player player, string message, string type)
{
if (string.IsNullOrEmpty(player.ConnectionId) && !player.IsTelnet)
{
return;
}

try
{
await _hubContext.Clients.Client(player.ConnectionId).SendAsync("CommUpdate", message, type);

}
catch (Exception ex)
{
Expand Down
Loading

0 comments on commit be22ece

Please sign in to comment.