mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-24 21:46:52 +01:00
Chat Refactor (#79) [TGSDeploy]
* Chat refactor: Service changes * Settings migration * First pass at implementing the commandline * WIP irc modes * Wip * Fix it * Working * Fix dickscord * Some readme updates * Fixes * PMs are admin etc * Compiling * Final touches * Version bump to 3.0.86.0
This commit is contained in:
@@ -19,7 +19,7 @@ Requires python 2.7/3.6 to be installed for changelog generation
|
||||
1. Go to the `Repository` Tab and set the remote address and branch of the git you with to track
|
||||
1. Hit the clone button
|
||||
1. While waiting go to the BYOND tab and install the BYOND version you wish
|
||||
1. You may also configure an IRC or discord bot for the server on the chat tab
|
||||
1. You may also configure an IRC and/or discord bot for the server on the chat tab
|
||||
1. Once the clone is complete you may set up a committer identity, user name, and password on the `Repository` tab for pushing changelog updates
|
||||
1. Go to the `Server` tab and click the `Initialize Game Folders` button
|
||||
1. Optionally change the `Project Path` Setting from tgstation to wherever the dme/dmb pair are in your repository
|
||||
@@ -31,20 +31,34 @@ This process is identical to the above steps in command line mode. You can alway
|
||||
1. Launch TGCommandLine.exe (running with no parameters puts you in interactive mode)
|
||||
1. `config move-server D:\tgstation`
|
||||
1. `repo setup https://github.com/tgstation/tgstation master`
|
||||
1. `byond update 511.1382`
|
||||
1. `chat set-provider irc`
|
||||
1. `byond update 511.1385`
|
||||
1. `irc nick TGS3Test`
|
||||
1. `irc set-auth-mode channel-mode`
|
||||
1. `irc set-auth-level %`
|
||||
1. `irc setup-auth NickServ "id hunter2"` Yes this is the real password, please use it only for testing
|
||||
1. `chat enable`
|
||||
1. `irc join coderbus dev`
|
||||
1. `irc join devbus dev`
|
||||
1. `irc join adminbus admin`
|
||||
1. `irc join adminbus wd`
|
||||
1. `irc join tgstation13 game`
|
||||
1. `irc enable`
|
||||
1. `discord set-token Rjfa93jlksjfj934jlkjasf8a08wfl.asdjfj08e44` See https://discordapp.com/developers/docs/topics/oauth2#bots
|
||||
1. `discord set-auth-mode role-id`
|
||||
1. `discord addmin 192837419273409` See how to get a role id: https://www.reddit.com/r/discordapp/comments/5bezg2/role_id/. Note that if you `discord set-auth-mode user-id` you'll need to use user ids (Enable developer mode, right click user, `Copy ID`)
|
||||
1. `discord join 12341234453235 dev` This is a channel id (Enable developer mode, right click channel, `Copy ID`)
|
||||
1. `discord join 34563456344245 dev`
|
||||
1. `discord join 23452362574456 admin`
|
||||
1. `discord join 23452362574456 wd`
|
||||
1. `discord join 53457345736788 game`
|
||||
1. `discord enable`
|
||||
1. `repo set-name tgstation-server` These two lines specify the changelog's committer identity. They are not mirrored in the GUI
|
||||
1. `repo set-email tgstation-server@tgstation13.org`
|
||||
1. `repo set-credentials` And follow the prompts
|
||||
1. `dm project-name tgstation`
|
||||
1. `repo python-path C:\Python27`
|
||||
1. `dd autostart on`
|
||||
1. Use `repo status` To check the clone job status
|
||||
1. `repo status` To check the clone job status
|
||||
1. `dm initialize --wait`
|
||||
1. `dm compile --wait`
|
||||
1. `dd start`
|
||||
|
||||
## Updating
|
||||
|
||||
+407
-195
@@ -4,78 +4,30 @@ using TGServiceInterface;
|
||||
|
||||
namespace TGCommandLine
|
||||
{
|
||||
class ChatCommand : RootCommand
|
||||
{
|
||||
public ChatCommand()
|
||||
{
|
||||
Keyword = "chat";
|
||||
Children = new Command[] { new ChatAnnounceCommand(), new ChatStatusCommand(), new ChatSetAdminChannelCommand(), new ChatEnableCommand(), new ChatDisableCommand(), new ChatReconnectCommand(), new ChatListAdminsCommand(), new ChatAddminCommand(), new ChatDeadminCommand(), new ChatSetProviderCommand(), new ChatJoinCommand(), new ChatPartCommand() };
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Manages general chat settings";
|
||||
}
|
||||
}
|
||||
class ChatSetProviderCommand : Command {
|
||||
public ChatSetProviderCommand()
|
||||
{
|
||||
Keyword = "set-provider";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Set the chat provider";
|
||||
}
|
||||
protected override string GetArgumentString()
|
||||
{
|
||||
return "<irc|discord> [if discord, add the bot token]";
|
||||
}
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var Chat = Server.GetComponent<ITGChat>();
|
||||
string res;
|
||||
switch (parameters[0].ToLower())
|
||||
{
|
||||
case "irc":
|
||||
res = Chat.SetProviderInfo(new TGIRCSetupInfo());
|
||||
break;
|
||||
case "discord":
|
||||
if(parameters.Count < 2)
|
||||
{
|
||||
Console.WriteLine("Missing discord bot token!");
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
res = Chat.SetProviderInfo(new TGDiscordSetupInfo() { BotToken = parameters[1] });
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("Invalid provider!");
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
Console.WriteLine(res ?? "Success!");
|
||||
return res == null ? ExitCode.Normal : ExitCode.ServerError;
|
||||
}
|
||||
}
|
||||
class IRCCommand : RootCommand
|
||||
{
|
||||
public IRCCommand()
|
||||
{
|
||||
Keyword = "irc";
|
||||
Children = new Command[] { new IRCNickCommand(), new IRCAuthCommand(), new IRCDisableAuthCommand(), new IRCServerCommand() };
|
||||
}
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
if (Server.GetComponent<ITGChat>().ProviderInfo().Provider != TGChatProvider.IRC)
|
||||
{
|
||||
Console.WriteLine("The current provider is not IRC. Please switch providers first!");
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
return base.Run(parameters);
|
||||
Children = new Command[] { new IRCNickCommand(), new IRCAuthCommand(), new IRCDisableAuthCommand(), new IRCServerCommand(), new ChatJoinCommand(TGChatProvider.IRC), new ChatPartCommand(TGChatProvider.IRC), new ChatListAdminsCommand(TGChatProvider.IRC), new ChatReconnectCommand(TGChatProvider.IRC), new ChatAddminCommand(TGChatProvider.IRC), new ChatDeadminCommand(TGChatProvider.IRC), new ChatEnableCommand(TGChatProvider.IRC), new ChatDisableCommand(TGChatProvider.IRC), new ChatStatusCommand(TGChatProvider.IRC), new IRCAuthModeCommand(), new IRCAuthLevelCommand() };
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Manages the IRC bot";
|
||||
}
|
||||
}
|
||||
class DiscordCommand : RootCommand
|
||||
{
|
||||
public DiscordCommand()
|
||||
{
|
||||
Keyword = "discord";
|
||||
Children = new Command[] { new DiscordSetTokenCommand(), new ChatJoinCommand(TGChatProvider.Discord), new ChatPartCommand(TGChatProvider.Discord), new ChatListAdminsCommand(TGChatProvider.Discord), new ChatReconnectCommand(TGChatProvider.Discord), new ChatAddminCommand(TGChatProvider.Discord), new ChatDeadminCommand(TGChatProvider.Discord), new ChatEnableCommand(TGChatProvider.Discord), new ChatDisableCommand(TGChatProvider.Discord), new ChatStatusCommand(TGChatProvider.Discord) , new DiscordAuthModeCommand() };
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Manages the Discord bot";
|
||||
}
|
||||
}
|
||||
class IRCNickCommand : Command
|
||||
{
|
||||
public IRCNickCommand()
|
||||
@@ -96,7 +48,7 @@ namespace TGCommandLine
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var Chat = Server.GetComponent<ITGChat>();
|
||||
Chat.SetProviderInfo(new TGIRCSetupInfo(Chat.ProviderInfo())
|
||||
Chat.SetProviderInfo(new TGIRCSetupInfo(Chat.ProviderInfos()[(int)TGChatProvider.IRC])
|
||||
{
|
||||
Nickname = parameters[0],
|
||||
});
|
||||
@@ -106,25 +58,48 @@ namespace TGCommandLine
|
||||
|
||||
class ChatJoinCommand : Command
|
||||
{
|
||||
public ChatJoinCommand()
|
||||
readonly int providerIndex;
|
||||
public ChatJoinCommand(TGChatProvider pI)
|
||||
{
|
||||
Keyword = "join";
|
||||
RequiredParameters = 1;
|
||||
RequiredParameters = 2;
|
||||
providerIndex = (int)pI;
|
||||
}
|
||||
|
||||
protected override string GetArgumentString()
|
||||
{
|
||||
return "<channel>";
|
||||
return "<channel> <dev|wd|game|admin>";
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Joins a channel for listening and broadcasting";
|
||||
return "Joins a channel for listening and broadcasting of the specified message type (Developer, Watchdog, Game, Admin)";
|
||||
}
|
||||
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var IRC = Server.GetComponent<ITGChat>();
|
||||
var channels = IRC.Channels();
|
||||
var info = IRC.ProviderInfos()[providerIndex];
|
||||
IList<string> channels;
|
||||
|
||||
switch (parameters[1].ToLower())
|
||||
{
|
||||
case "dev":
|
||||
channels = info.DevChannels;
|
||||
break;
|
||||
case "wd":
|
||||
channels = info.WatchdogChannels;
|
||||
break;
|
||||
case "game":
|
||||
channels = info.GameChannels;
|
||||
break;
|
||||
case "admin":
|
||||
channels = info.AdminChannels;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("Invalid parameter: " + parameters[1]);
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
|
||||
var lowerParam = parameters[0].ToLower();
|
||||
foreach (var I in channels)
|
||||
{
|
||||
@@ -134,74 +109,97 @@ namespace TGCommandLine
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
}
|
||||
Array.Resize(ref channels, channels.Length + 1);
|
||||
channels[channels.Length - 1] = parameters[0];
|
||||
IRC.SetChannels(channels, null);
|
||||
channels.Add(parameters[0]);
|
||||
switch (parameters[1].ToLower())
|
||||
{
|
||||
case "dev":
|
||||
info.DevChannels = channels;
|
||||
break;
|
||||
case "wd":
|
||||
info.WatchdogChannels = channels;
|
||||
break;
|
||||
case "game":
|
||||
info.GameChannels = channels;
|
||||
break;
|
||||
case "admin":
|
||||
info.AdminChannels = channels;
|
||||
break;
|
||||
}
|
||||
var res = IRC.SetProviderInfo(info);
|
||||
if(res != null)
|
||||
{
|
||||
Console.WriteLine(res);
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
|
||||
class ChatPartCommand : Command
|
||||
{
|
||||
public ChatPartCommand()
|
||||
readonly int providerIndex;
|
||||
public ChatPartCommand(TGChatProvider pI)
|
||||
{
|
||||
Keyword = "part";
|
||||
RequiredParameters = 1;
|
||||
RequiredParameters = 2;
|
||||
providerIndex = (int)pI;
|
||||
}
|
||||
|
||||
protected override string GetArgumentString()
|
||||
{
|
||||
return "<channel>";
|
||||
return "<channel> <dev|wd|game|admin>";
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Stops listening and broadcasting on a channel";
|
||||
return "Stops listening and broadcasting on a channel for the specified message type (Developer, Watchdog, Game, Admin)";
|
||||
}
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var IRC = Server.GetComponent<ITGChat>();
|
||||
var channels = IRC.Channels();
|
||||
var lowerParam = parameters[0].ToLower();
|
||||
if (lowerParam[0] != '#')
|
||||
lowerParam = "#" + lowerParam;
|
||||
var new_channels = new List<string>();
|
||||
foreach (var I in channels)
|
||||
{
|
||||
if (I.ToLower() == lowerParam)
|
||||
continue;
|
||||
new_channels.Add(I);
|
||||
}
|
||||
if (new_channels.Count == 0)
|
||||
{
|
||||
Console.WriteLine("Error: Cannot part from the last channel!");
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
IRC.SetChannels(new_channels.ToArray(), null);
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
class ChatAnnounceCommand : Command
|
||||
{
|
||||
public ChatAnnounceCommand()
|
||||
{
|
||||
Keyword = "announce";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
protected override string GetArgumentString()
|
||||
{
|
||||
return "<message>";
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Sends a message to all connected channels";
|
||||
}
|
||||
var info = IRC.ProviderInfos()[providerIndex];
|
||||
IList<string> channels;
|
||||
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var res = Server.GetComponent<ITGChat>().SendMessage("SCP: " + parameters[0]);
|
||||
switch (parameters[1].ToLower())
|
||||
{
|
||||
case "dev":
|
||||
channels = info.DevChannels;
|
||||
break;
|
||||
case "wd":
|
||||
channels = info.WatchdogChannels;
|
||||
break;
|
||||
case "game":
|
||||
channels = info.GameChannels;
|
||||
break;
|
||||
case "admin":
|
||||
channels = info.AdminChannels;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("Invalid parameter: " + parameters[1]);
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
var lowerParam = parameters[0].ToLower();
|
||||
if ((TGChatProvider)providerIndex == TGChatProvider.IRC && lowerParam[0] != '#')
|
||||
lowerParam = "#" + lowerParam;
|
||||
channels.Remove(lowerParam);
|
||||
switch (parameters[1].ToLower())
|
||||
{
|
||||
case "dev":
|
||||
info.DevChannels = channels;
|
||||
break;
|
||||
case "wd":
|
||||
info.WatchdogChannels = channels;
|
||||
break;
|
||||
case "game":
|
||||
info.GameChannels = channels;
|
||||
break;
|
||||
case "admin":
|
||||
info.AdminChannels = channels;
|
||||
break;
|
||||
}
|
||||
var res = IRC.SetProviderInfo(info);
|
||||
if (res != null)
|
||||
{
|
||||
Console.WriteLine("Error: " + res);
|
||||
Console.WriteLine(res);
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
@@ -209,9 +207,11 @@ namespace TGCommandLine
|
||||
}
|
||||
class ChatListAdminsCommand : Command
|
||||
{
|
||||
public ChatListAdminsCommand()
|
||||
readonly int providerIndex;
|
||||
public ChatListAdminsCommand(TGChatProvider pI)
|
||||
{
|
||||
Keyword = "list-admins";
|
||||
providerIndex = (int)pI;
|
||||
}
|
||||
|
||||
protected override string GetHelpText()
|
||||
@@ -221,17 +221,56 @@ namespace TGCommandLine
|
||||
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var res = Server.GetComponent<ITGChat>().ListAdmins();
|
||||
foreach (var I in res)
|
||||
Console.WriteLine(I);
|
||||
var info = Server.GetComponent<ITGChat>().ProviderInfos()[providerIndex];
|
||||
string authType;
|
||||
switch ((TGChatProvider)providerIndex)
|
||||
{
|
||||
case TGChatProvider.IRC:
|
||||
if (info.AdminsAreSpecial)
|
||||
authType = "Mode:";
|
||||
else
|
||||
authType = "Nicknames:";
|
||||
break;
|
||||
case TGChatProvider.Discord:
|
||||
if (info.AdminsAreSpecial)
|
||||
authType = "Role IDs:";
|
||||
else
|
||||
authType = "User IDs:";
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine(String.Format("Invalid provider: {0}!", providerIndex));
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
Console.WriteLine("Authorized " + authType);
|
||||
if (info.AdminsAreSpecial && (TGChatProvider)providerIndex == TGChatProvider.IRC)
|
||||
switch(new TGIRCSetupInfo(info).AuthLevel)
|
||||
{
|
||||
case IRCMode.Voice:
|
||||
Console.WriteLine("+");
|
||||
break;
|
||||
case IRCMode.Halfop:
|
||||
Console.WriteLine("%");
|
||||
break;
|
||||
case IRCMode.Op:
|
||||
Console.WriteLine("@");
|
||||
break;
|
||||
case IRCMode.Owner:
|
||||
Console.WriteLine("~");
|
||||
break;
|
||||
}
|
||||
else
|
||||
foreach (var I in info.AdminList)
|
||||
Console.WriteLine(I);
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
class ChatReconnectCommand : Command
|
||||
{
|
||||
public ChatReconnectCommand()
|
||||
readonly TGChatProvider providerIndex;
|
||||
public ChatReconnectCommand(TGChatProvider pI)
|
||||
{
|
||||
Keyword = "reconnect";
|
||||
providerIndex = pI;
|
||||
}
|
||||
|
||||
protected override string GetHelpText()
|
||||
@@ -241,7 +280,7 @@ namespace TGCommandLine
|
||||
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var res = Server.GetComponent<ITGChat>().Reconnect();
|
||||
var res = Server.GetComponent<ITGChat>().Reconnect(providerIndex);
|
||||
if (res != null)
|
||||
{
|
||||
Console.WriteLine("Error: " + res);
|
||||
@@ -252,68 +291,221 @@ namespace TGCommandLine
|
||||
}
|
||||
class ChatAddminCommand : Command
|
||||
{
|
||||
public ChatAddminCommand()
|
||||
readonly int providerIndex;
|
||||
public ChatAddminCommand(TGChatProvider pI)
|
||||
{
|
||||
Keyword = "addmin";
|
||||
RequiredParameters = 1;
|
||||
providerIndex = (int)pI;
|
||||
}
|
||||
|
||||
|
||||
protected override string GetArgumentString()
|
||||
{
|
||||
return "[nick]";
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Add a user which can use restricted commands in the admin channel";
|
||||
return "Add a user which can use restricted commands in the admin channels";
|
||||
}
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var IRC = Server.GetComponent<ITGChat>();
|
||||
var mins = new List<string>(IRC.ListAdmins());
|
||||
var newmin = parameters[0];
|
||||
var info = IRC.ProviderInfos()[providerIndex];
|
||||
var newmin = parameters[0].ToLower();
|
||||
|
||||
foreach (var I in mins)
|
||||
if (I.ToLower() == newmin.ToLower())
|
||||
{
|
||||
Console.WriteLine(newmin + " is already an admin!");
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
if (info.AdminsAreSpecial && (TGChatProvider)providerIndex == TGChatProvider.IRC)
|
||||
{
|
||||
Console.WriteLine("Invalid auth mode for this command!");
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
|
||||
mins.Add(newmin);
|
||||
IRC.SetAdmins(mins.ToArray());
|
||||
if (info.AdminList.Contains(newmin))
|
||||
{
|
||||
Console.WriteLine(parameters[0] + " is already an admin!");
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
var al = info.AdminList;
|
||||
al.Add(newmin);
|
||||
info.AdminList = al;
|
||||
var res = IRC.SetProviderInfo(info);
|
||||
if (res != null)
|
||||
{
|
||||
Console.WriteLine(res);
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
class IRCAuthModeCommand : Command
|
||||
{
|
||||
public IRCAuthModeCommand()
|
||||
{
|
||||
Keyword = "set-auth-mode";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
protected override string GetArgumentString()
|
||||
{
|
||||
return "<channel-mode|nickname>";
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Switch between admin command authorization via user channel mode or nicknames";
|
||||
}
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var IRC = Server.GetComponent<ITGChat>();
|
||||
var info = IRC.ProviderInfos()[(int)TGChatProvider.IRC];
|
||||
var lowerparam = parameters[0].ToLower();
|
||||
if (lowerparam == "channel-mode")
|
||||
info.AdminsAreSpecial = true;
|
||||
else if (lowerparam == "nickname")
|
||||
info.AdminsAreSpecial = false;
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid parameter: " + parameters[0]);
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
var res = IRC.SetProviderInfo(info);
|
||||
if (res != null)
|
||||
{
|
||||
Console.WriteLine(res);
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
class DiscordAuthModeCommand : Command
|
||||
{
|
||||
public DiscordAuthModeCommand()
|
||||
{
|
||||
Keyword = "set-auth-mode";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
protected override string GetArgumentString()
|
||||
{
|
||||
return "<role-id|user-id>";
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Switch between admin command authorization via user roles or individual users";
|
||||
}
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var IRC = Server.GetComponent<ITGChat>();
|
||||
var info = IRC.ProviderInfos()[(int)TGChatProvider.Discord];
|
||||
var lowerparam = parameters[0].ToLower();
|
||||
if (lowerparam == "role-id")
|
||||
info.AdminsAreSpecial = true;
|
||||
else if (lowerparam == "user-id")
|
||||
info.AdminsAreSpecial = false;
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid parameter: " + parameters[0]);
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
var res = IRC.SetProviderInfo(info);
|
||||
if (res != null)
|
||||
{
|
||||
Console.WriteLine(res);
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
class IRCAuthLevelCommand : Command
|
||||
{
|
||||
public IRCAuthLevelCommand()
|
||||
{
|
||||
Keyword = "set-auth-level";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
|
||||
protected override string GetArgumentString()
|
||||
{
|
||||
return "<+|%|@|~>";
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Set the required channel mode for users to use admin commands";
|
||||
}
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var IRC = Server.GetComponent<ITGChat>();
|
||||
var info = new TGIRCSetupInfo(IRC.ProviderInfos()[(int)TGChatProvider.IRC]);
|
||||
switch (parameters[0])
|
||||
{
|
||||
case "+":
|
||||
info.AuthLevel = IRCMode.Voice;
|
||||
break;
|
||||
case "%":
|
||||
info.AuthLevel = IRCMode.Halfop;
|
||||
break;
|
||||
case "@":
|
||||
info.AuthLevel = IRCMode.Op;
|
||||
break;
|
||||
case "~":
|
||||
info.AuthLevel = IRCMode.Owner;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine("Invalid parameter: " + parameters[0]);
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
|
||||
var res = IRC.SetProviderInfo(info);
|
||||
if (res != null)
|
||||
{
|
||||
Console.WriteLine(res);
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
class ChatDeadminCommand : Command
|
||||
{
|
||||
public ChatDeadminCommand()
|
||||
readonly int providerIndex;
|
||||
public ChatDeadminCommand(TGChatProvider pI)
|
||||
{
|
||||
Keyword = "deadmin";
|
||||
RequiredParameters = 1;
|
||||
providerIndex = (int)pI;
|
||||
}
|
||||
protected override string GetArgumentString()
|
||||
{
|
||||
return "[nick]";
|
||||
return "<nick>";
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Remove a user which can use restricted commands in the admin channel";
|
||||
return "Remove a user which can use restricted commands in the admin channels";
|
||||
}
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var IRC = Server.GetComponent<ITGChat>();
|
||||
var mins = new List<string>(IRC.ListAdmins());
|
||||
var deadmin = parameters[0];
|
||||
var info = IRC.ProviderInfos()[providerIndex];
|
||||
var newmin = parameters[0].ToLower();
|
||||
|
||||
if (info.AdminsAreSpecial && (TGChatProvider)providerIndex == TGChatProvider.IRC)
|
||||
{
|
||||
Console.WriteLine("Invalid auth mode for this command!");
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
|
||||
if (!info.AdminList.Contains(newmin))
|
||||
{
|
||||
Console.WriteLine(parameters[0] + " is not an admin!");
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
|
||||
foreach (var I in mins)
|
||||
if (I.ToLower() == deadmin.ToLower())
|
||||
{
|
||||
mins.Remove(I);
|
||||
IRC.SetAdmins(mins.ToArray());
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
|
||||
Console.WriteLine(deadmin + " is not an admin!");
|
||||
var al = info.AdminList;
|
||||
al.Remove(newmin);
|
||||
info.AdminList = al;
|
||||
var res = IRC.SetProviderInfo(info);
|
||||
if (res != null)
|
||||
{
|
||||
Console.WriteLine(res);
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
@@ -337,7 +529,7 @@ namespace TGCommandLine
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var IRC = Server.GetComponent<ITGChat>();
|
||||
IRC.SetProviderInfo(new TGIRCSetupInfo(IRC.ProviderInfo())
|
||||
IRC.SetProviderInfo(new TGIRCSetupInfo(IRC.ProviderInfos()[(int)TGChatProvider.IRC])
|
||||
{
|
||||
AuthTarget = parameters[0],
|
||||
AuthMessage = parameters[1]
|
||||
@@ -359,7 +551,7 @@ namespace TGCommandLine
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var IRC = Server.GetComponent<ITGChat>();
|
||||
IRC.SetProviderInfo(new TGIRCSetupInfo(IRC.ProviderInfo())
|
||||
IRC.SetProviderInfo(new TGIRCSetupInfo(IRC.ProviderInfos()[(int)TGChatProvider.IRC])
|
||||
{
|
||||
AuthTarget = null,
|
||||
AuthMessage = null,
|
||||
@@ -370,9 +562,11 @@ namespace TGCommandLine
|
||||
|
||||
class ChatStatusCommand : Command
|
||||
{
|
||||
public ChatStatusCommand()
|
||||
readonly int providerIndex;
|
||||
public ChatStatusCommand(TGChatProvider pI)
|
||||
{
|
||||
Keyword = "status";
|
||||
providerIndex = (int)pI;
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
@@ -381,56 +575,33 @@ namespace TGCommandLine
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var IRC = Server.GetComponent<ITGChat>();
|
||||
Console.WriteLine("Currently configured broadcast channels:");
|
||||
Console.WriteLine("\tAdmin Channel: " + IRC.AdminChannel());
|
||||
foreach (var I in IRC.Channels())
|
||||
var info = IRC.ProviderInfos()[providerIndex];
|
||||
Console.WriteLine("Currently configured channels:");
|
||||
Console.WriteLine("Admin:");
|
||||
foreach (var I in info.AdminChannels)
|
||||
Console.WriteLine("\t" + I);
|
||||
string provider;
|
||||
switch (IRC.ProviderInfo().Provider)
|
||||
{
|
||||
case TGChatProvider.Discord:
|
||||
provider = "Discord";
|
||||
break;
|
||||
case TGChatProvider.IRC:
|
||||
provider = "IRC";
|
||||
break;
|
||||
default:
|
||||
provider = "Unknown";
|
||||
break;
|
||||
}
|
||||
Console.WriteLine("Provider: " + provider);
|
||||
Console.WriteLine("Chat bot is: " + (!IRC.Enabled() ? "Disabled" : IRC.Connected() ? "Connected" : "Disconnected"));
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
class ChatSetAdminChannelCommand : Command
|
||||
{
|
||||
public ChatSetAdminChannelCommand()
|
||||
{
|
||||
Keyword = "set-admin-channel";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
protected override string GetArgumentString()
|
||||
{
|
||||
return "<channel>";
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Sets the admin chat channel";
|
||||
}
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
Server.GetComponent<ITGChat>().SetChannels(null, parameters[0]);
|
||||
Console.WriteLine("Watchdog:");
|
||||
foreach (var I in info.WatchdogChannels)
|
||||
Console.WriteLine("\t" + I);
|
||||
Console.WriteLine("Game:");
|
||||
foreach (var I in info.GameChannels)
|
||||
Console.WriteLine("\t" + I);
|
||||
Console.WriteLine("Developer:");
|
||||
foreach (var I in info.DevChannels)
|
||||
Console.WriteLine("\t" + I);
|
||||
Console.WriteLine("Chat bot is: " + (!info.Enabled ? "Disabled" : IRC.Connected(info.Provider) ? "Connected" : "Disconnected"));
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
class ChatEnableCommand : Command
|
||||
{
|
||||
public ChatEnableCommand()
|
||||
readonly int providerIndex;
|
||||
public ChatEnableCommand(TGChatProvider pI)
|
||||
{
|
||||
Keyword = "enable";
|
||||
providerIndex = (int)pI;
|
||||
}
|
||||
|
||||
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Enables the chat bot";
|
||||
@@ -438,17 +609,27 @@ namespace TGCommandLine
|
||||
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
Server.GetComponent<ITGChat>().SetEnabled(true);
|
||||
var Chat = Server.GetComponent<ITGChat>();
|
||||
var info = Chat.ProviderInfos()[providerIndex];
|
||||
info.Enabled = true;
|
||||
var res = Chat.SetProviderInfo(info);
|
||||
if (res != null)
|
||||
{
|
||||
Console.WriteLine(res);
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
class ChatDisableCommand : Command
|
||||
{
|
||||
public ChatDisableCommand()
|
||||
readonly int providerIndex;
|
||||
public ChatDisableCommand(TGChatProvider pI)
|
||||
{
|
||||
Keyword = "disable";
|
||||
providerIndex = (int)pI;
|
||||
}
|
||||
|
||||
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Disables the chat bot";
|
||||
@@ -456,7 +637,15 @@ namespace TGCommandLine
|
||||
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
Server.GetComponent<ITGChat>().SetEnabled(true);
|
||||
var Chat = Server.GetComponent<ITGChat>();
|
||||
var info = Chat.ProviderInfos()[providerIndex];
|
||||
info.Enabled = false;
|
||||
var res = Chat.SetProviderInfo(info);
|
||||
if (res != null)
|
||||
{
|
||||
Console.WriteLine(res);
|
||||
return ExitCode.ServerError;
|
||||
}
|
||||
return ExitCode.Normal;
|
||||
}
|
||||
}
|
||||
@@ -486,7 +675,7 @@ namespace TGCommandLine
|
||||
return ExitCode.BadCommand;
|
||||
}
|
||||
var Chat = Server.GetComponent<ITGChat>();
|
||||
var PI = new TGIRCSetupInfo(Chat.ProviderInfo())
|
||||
var PI = new TGIRCSetupInfo(Chat.ProviderInfos()[(int)TGChatProvider.IRC])
|
||||
{
|
||||
URL = splits[0]
|
||||
};
|
||||
@@ -504,6 +693,29 @@ namespace TGCommandLine
|
||||
Console.WriteLine(res ?? "Success");
|
||||
return res == null ? ExitCode.Normal : ExitCode.ServerError;
|
||||
}
|
||||
}
|
||||
|
||||
class DiscordSetTokenCommand : Command
|
||||
{
|
||||
public DiscordSetTokenCommand()
|
||||
{
|
||||
Keyword = "set-token";
|
||||
RequiredParameters = 1;
|
||||
}
|
||||
protected override string GetArgumentString()
|
||||
{
|
||||
return "<bot-token>";
|
||||
}
|
||||
protected override string GetHelpText()
|
||||
{
|
||||
return "Sets the discord API bot token";
|
||||
}
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
var Chat = Server.GetComponent<ITGChat>();
|
||||
var res = Chat.SetProviderInfo(new TGDiscordSetupInfo(Chat.ProviderInfos()[(int)TGChatProvider.Discord]) { BotToken = parameters[0] });
|
||||
Console.WriteLine(res ?? "Success");
|
||||
return res == null ? ExitCode.Normal : ExitCode.ServerError;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,5 +22,5 @@ using System.Runtime.InteropServices;
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
[assembly: AssemblyVersion("3.0.85.4")]
|
||||
[assembly: AssemblyFileVersion("3.0.85.4")]
|
||||
[assembly: AssemblyVersion("3.0.86.0")]
|
||||
[assembly: AssemblyFileVersion("3.0.86.0")]
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace TGCommandLine
|
||||
public RootCommand()
|
||||
{
|
||||
if (IsRealRoot()) //stack overflows
|
||||
Children = new Command[] { new UpdateCommand(), new TestmergeCommand(), new IRCCommand(), new RepoCommand(), new BYONDCommand(), new DMCommand(), new DDCommand(), new ConfigCommand(), new ChatCommand() };
|
||||
Children = new Command[] { new UpdateCommand(), new TestmergeCommand(), new RepoCommand(), new BYONDCommand(), new DMCommand(), new DDCommand(), new ConfigCommand(), new IRCCommand(), new DiscordCommand() };
|
||||
}
|
||||
public override ExitCode Run(IList<string> parameters)
|
||||
{
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
<setting name="UpgradeRequired" serializeAs="String">
|
||||
<value>True</value>
|
||||
</setting>
|
||||
<setting name="LastChatProvider" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
</TGControlPanel.Properties.Settings>
|
||||
<TGControlPanel.Properties.Settings1>
|
||||
<setting name="LastPageIndex" serializeAs="String">
|
||||
|
||||
+90
-42
@@ -1,8 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using TGServiceInterface;
|
||||
|
||||
@@ -10,16 +7,22 @@ namespace TGControlPanel
|
||||
{
|
||||
partial class Main
|
||||
{
|
||||
TGChatProvider modifyingProvider;
|
||||
bool updatingChat = false;
|
||||
|
||||
TGChatProvider ModifyingProvider
|
||||
{
|
||||
get { return (TGChatProvider)Properties.Settings.Default.LastChatProvider; }
|
||||
set { Properties.Settings.Default.LastChatProvider = (int)value; }
|
||||
}
|
||||
|
||||
void LoadChatPage()
|
||||
{
|
||||
updatingChat = true;
|
||||
var Chat = Server.GetComponent<ITGChat>();
|
||||
var PI = Chat.ProviderInfo();
|
||||
modifyingProvider = PI.Provider;
|
||||
switch (modifyingProvider)
|
||||
var PI = Chat.ProviderInfos()[(int)ModifyingProvider];
|
||||
ChatAdminsTextBox.Visible = true;
|
||||
IRCModesComboBox.Visible = false;
|
||||
switch (ModifyingProvider)
|
||||
{
|
||||
case TGChatProvider.Discord:
|
||||
var DPI = new TGDiscordSetupInfo(PI);
|
||||
@@ -34,6 +37,11 @@ namespace TGControlPanel
|
||||
ChatPortTitle.Visible = false;
|
||||
ChatNicknameText.Visible = false;
|
||||
ChatNicknameTitle.Visible = false;
|
||||
|
||||
ChatAdminsTitle.Text = String.Format("Admin {0} IDs:", DPI.AdminsAreSpecial ? "Role" : "User");
|
||||
ChannelsTitle.Text = "Broadcast/Listening Channel IDs:";
|
||||
AdminModeNormal.Text = "User IDs";
|
||||
AdminModeSpecial.Text = "Role IDs";
|
||||
break;
|
||||
case TGChatProvider.IRC:
|
||||
var IRC = new TGIRCSetupInfo(PI);
|
||||
@@ -53,36 +61,49 @@ namespace TGControlPanel
|
||||
ChatNicknameText.Visible = true;
|
||||
ChatNicknameTitle.Visible = true;
|
||||
ChatNicknameText.Text = IRC.Nickname;
|
||||
ChatAdminsTitle.Text = String.Format("Admin {0}:", IRC.AdminsAreSpecial ? "Req Mode" : "Nicknames");
|
||||
ChannelsTitle.Text = "Broadcast/Listening Channels:";
|
||||
AdminModeNormal.Text = "Nicknames";
|
||||
AdminModeSpecial.Text = "Channel Mode";
|
||||
if (IRC.AdminsAreSpecial)
|
||||
{
|
||||
ChatAdminsTextBox.Visible = false;
|
||||
IRCModesComboBox.Visible = true;
|
||||
IRCModesComboBox.SelectedIndex = (int)IRC.AuthLevel;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MessageBox.Show("This is a bug, I'll try and recover. Provider was " + modifyingProvider.ToString());
|
||||
MessageBox.Show(Chat.SetProviderInfo(new TGIRCSetupInfo()) ?? "Success!");
|
||||
Properties.Settings.Default.LastChatProvider = (int)TGChatProvider.IRC;
|
||||
LoadChatPage();
|
||||
return;
|
||||
}
|
||||
|
||||
var Enabled = Chat.Enabled();
|
||||
ChatEnabledCheckbox.Checked = Enabled;
|
||||
if (!Enabled)
|
||||
AdminModeNormal.Checked = !PI.AdminsAreSpecial;
|
||||
AdminModeSpecial.Checked = PI.AdminsAreSpecial;
|
||||
ChatEnabledCheckbox.Checked = PI.Enabled;
|
||||
if (!PI.Enabled)
|
||||
ChatStatusLabel.Text = "Disabled";
|
||||
else if (Chat.Connected())
|
||||
else if (Chat.Connected(ModifyingProvider))
|
||||
ChatStatusLabel.Text = "Connected";
|
||||
else
|
||||
ChatStatusLabel.Text = "Disconnected";
|
||||
ChatReconnectButton.Enabled = Enabled;
|
||||
ChatReconnectButton.Enabled = PI.Enabled;
|
||||
|
||||
AdminChannelText.Text = Chat.AdminChannel();
|
||||
|
||||
ChatAdminsTextBox.Text = "";
|
||||
foreach (var I in Chat.ListAdmins())
|
||||
ChatAdminsTextBox.Text += I + "\r\n";
|
||||
|
||||
ChatChannelsTextBox.Text = "";
|
||||
foreach (var I in Chat.Channels())
|
||||
ChatChannelsTextBox.Text += I + "\r\n";
|
||||
AssignListToTextbox(PI.AdminList, ChatAdminsTextBox);
|
||||
AssignListToTextbox(PI.WatchdogChannels, WDChannelsTextbox);
|
||||
AssignListToTextbox(PI.AdminChannels, AdminChannelsTextbox);
|
||||
AssignListToTextbox(PI.DevChannels, DevChannelsTextbox);
|
||||
AssignListToTextbox(PI.GameChannels, GameChannelsTextbox);
|
||||
updatingChat = false;
|
||||
}
|
||||
|
||||
static void AssignListToTextbox(IList<string> a, TextBox b)
|
||||
{
|
||||
b.Text = "";
|
||||
foreach (var I in a)
|
||||
b.Text += I + Environment.NewLine;
|
||||
}
|
||||
|
||||
private void ChatRefreshButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
LoadChatPage();
|
||||
@@ -90,7 +111,7 @@ namespace TGControlPanel
|
||||
|
||||
private void ChatReconnectButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
Server.GetComponent<ITGChat>().Reconnect();
|
||||
Server.GetComponent<ITGChat>().Reconnect(ModifyingProvider);
|
||||
LoadChatPage();
|
||||
}
|
||||
|
||||
@@ -112,9 +133,7 @@ namespace TGControlPanel
|
||||
{
|
||||
if (!updatingChat && DiscordProviderSwitch.Checked)
|
||||
{
|
||||
var res = Server.GetComponent<ITGChat>().SetProviderInfo(new TGDiscordSetupInfo());
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
ModifyingProvider = TGChatProvider.Discord;
|
||||
LoadChatPage();
|
||||
}
|
||||
}
|
||||
@@ -123,44 +142,73 @@ namespace TGControlPanel
|
||||
{
|
||||
if (!updatingChat && IRCProviderSwitch.Checked)
|
||||
{
|
||||
var res = Server.GetComponent<ITGChat>().SetProviderInfo(new TGIRCSetupInfo());
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
ModifyingProvider = TGChatProvider.IRC;
|
||||
LoadChatPage();
|
||||
}
|
||||
}
|
||||
void SetAdminsAreSpecial(bool value)
|
||||
{
|
||||
var Chat = Server.GetComponent<ITGChat>();
|
||||
var PI = Chat.ProviderInfos()[(int)ModifyingProvider];
|
||||
PI.AdminsAreSpecial = value;
|
||||
var res = Chat.SetProviderInfo(PI);
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
LoadChatPage();
|
||||
}
|
||||
|
||||
private void AdminModeNormal_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (!updatingChat && AdminModeNormal.Checked)
|
||||
SetAdminsAreSpecial(false);
|
||||
}
|
||||
|
||||
private void AdminModeSpecial_CheckedChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (!updatingChat && AdminModeSpecial.Checked)
|
||||
SetAdminsAreSpecial(true);
|
||||
}
|
||||
|
||||
private void ChatApplyButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var Chat = Server.GetComponent<ITGChat>();
|
||||
|
||||
string res;
|
||||
switch (modifyingProvider)
|
||||
string res = null;
|
||||
TGChatSetupInfo wip = null;
|
||||
switch (ModifyingProvider)
|
||||
{
|
||||
case TGChatProvider.Discord:
|
||||
res = Chat.SetProviderInfo(new TGDiscordSetupInfo() { BotToken = AuthField1.Text });
|
||||
wip = new TGDiscordSetupInfo()
|
||||
{
|
||||
BotToken = AuthField1.Text
|
||||
};
|
||||
break;
|
||||
case TGChatProvider.IRC:
|
||||
res = Chat.SetProviderInfo(new TGIRCSetupInfo() {
|
||||
wip = new TGIRCSetupInfo()
|
||||
{
|
||||
AuthMessage = AuthField2.Text,
|
||||
AuthTarget = AuthField1.Text,
|
||||
Nickname = ChatNicknameText.Text,
|
||||
URL = ChatServerText.Text,
|
||||
Port = (ushort)ChatPortSelector.Value,
|
||||
});
|
||||
AuthLevel = (IRCMode)IRCModesComboBox.SelectedIndex,
|
||||
};
|
||||
break;
|
||||
default:
|
||||
res = "You really shouldn't be able to read this.";
|
||||
break;
|
||||
}
|
||||
|
||||
if (res == null)
|
||||
{
|
||||
wip.AdminChannels = new List<string>(AdminChannelsTextbox.Text.Split('\n'));
|
||||
wip.WatchdogChannels = new List<string>(WDChannelsTextbox.Text.Split('\n'));
|
||||
wip.DevChannels = new List<string>(DevChannelsTextbox.Text.Split('\n'));
|
||||
wip.GameChannels = new List<string>(GameChannelsTextbox.Text.Split('\n'));
|
||||
wip.Enabled = ChatEnabledCheckbox.Checked;
|
||||
|
||||
res = Server.GetComponent<ITGChat>().SetProviderInfo(wip);
|
||||
}
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
|
||||
Chat.SetChannels(SplitByLine(ChatChannelsTextBox), AdminChannelText.Text);
|
||||
Chat.SetAdmins(SplitByLine(ChatAdminsTextBox));
|
||||
Chat.SetEnabled(ChatEnabledCheckbox.Checked);
|
||||
|
||||
LoadChatPage();
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+188
-41
@@ -105,6 +105,16 @@
|
||||
this.ServerStatusLabel = new System.Windows.Forms.Label();
|
||||
this.ServerStatusTitle = new System.Windows.Forms.Label();
|
||||
this.ChatPanel = new System.Windows.Forms.TabPage();
|
||||
this.label5 = new System.Windows.Forms.Label();
|
||||
this.label4 = new System.Windows.Forms.Label();
|
||||
this.label3 = new System.Windows.Forms.Label();
|
||||
this.label2 = new System.Windows.Forms.Label();
|
||||
this.IRCModesComboBox = new System.Windows.Forms.ComboBox();
|
||||
this.label1 = new System.Windows.Forms.Label();
|
||||
this.AdminChannelsTextbox = new System.Windows.Forms.TextBox();
|
||||
this.WDChannelsTextbox = new System.Windows.Forms.TextBox();
|
||||
this.GameChannelsTextbox = new System.Windows.Forms.TextBox();
|
||||
this.DevChannelsTextbox = new System.Windows.Forms.TextBox();
|
||||
this.ChatRefreshButton = new System.Windows.Forms.Button();
|
||||
this.ChatNicknameText = new System.Windows.Forms.TextBox();
|
||||
this.ChatNicknameTitle = new System.Windows.Forms.Label();
|
||||
@@ -117,8 +127,6 @@
|
||||
this.AuthField1Title = new System.Windows.Forms.Label();
|
||||
this.AuthField2 = new System.Windows.Forms.TextBox();
|
||||
this.AuthField1 = new System.Windows.Forms.TextBox();
|
||||
this.AdminChannelTitle = new System.Windows.Forms.Label();
|
||||
this.AdminChannelText = new System.Windows.Forms.TextBox();
|
||||
this.ChatReconnectButton = new System.Windows.Forms.Button();
|
||||
this.ChatStatusLabel = new System.Windows.Forms.Label();
|
||||
this.ChatStatusTitle = new System.Windows.Forms.Label();
|
||||
@@ -130,7 +138,9 @@
|
||||
this.ChannelsTitle = new System.Windows.Forms.Label();
|
||||
this.ChatAdminsTextBox = new System.Windows.Forms.TextBox();
|
||||
this.ChatAdminsTitle = new System.Windows.Forms.Label();
|
||||
this.ChatChannelsTextBox = new System.Windows.Forms.TextBox();
|
||||
this.panel1 = new System.Windows.Forms.Panel();
|
||||
this.AdminModeSpecial = new System.Windows.Forms.RadioButton();
|
||||
this.AdminModeNormal = new System.Windows.Forms.RadioButton();
|
||||
this.ConfigPanel = new System.Windows.Forms.TabPage();
|
||||
this.ConfigApply = new System.Windows.Forms.Button();
|
||||
this.ConfigDownloadRepo = new System.Windows.Forms.Button();
|
||||
@@ -180,6 +190,7 @@
|
||||
this.ChatPanel.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)(this.ChatPortSelector)).BeginInit();
|
||||
this.ChatProviderSelectorPanel.SuspendLayout();
|
||||
this.panel1.SuspendLayout();
|
||||
this.ConfigPanel.SuspendLayout();
|
||||
this.ConfigPanels.SuspendLayout();
|
||||
this.AdminsPanel.SuspendLayout();
|
||||
@@ -1170,6 +1181,16 @@
|
||||
// ChatPanel
|
||||
//
|
||||
this.ChatPanel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(39)))), ((int)(((byte)(40)))), ((int)(((byte)(34)))));
|
||||
this.ChatPanel.Controls.Add(this.label5);
|
||||
this.ChatPanel.Controls.Add(this.label4);
|
||||
this.ChatPanel.Controls.Add(this.label3);
|
||||
this.ChatPanel.Controls.Add(this.label2);
|
||||
this.ChatPanel.Controls.Add(this.IRCModesComboBox);
|
||||
this.ChatPanel.Controls.Add(this.label1);
|
||||
this.ChatPanel.Controls.Add(this.AdminChannelsTextbox);
|
||||
this.ChatPanel.Controls.Add(this.WDChannelsTextbox);
|
||||
this.ChatPanel.Controls.Add(this.GameChannelsTextbox);
|
||||
this.ChatPanel.Controls.Add(this.DevChannelsTextbox);
|
||||
this.ChatPanel.Controls.Add(this.ChatRefreshButton);
|
||||
this.ChatPanel.Controls.Add(this.ChatNicknameText);
|
||||
this.ChatPanel.Controls.Add(this.ChatNicknameTitle);
|
||||
@@ -1182,8 +1203,6 @@
|
||||
this.ChatPanel.Controls.Add(this.AuthField1Title);
|
||||
this.ChatPanel.Controls.Add(this.AuthField2);
|
||||
this.ChatPanel.Controls.Add(this.AuthField1);
|
||||
this.ChatPanel.Controls.Add(this.AdminChannelTitle);
|
||||
this.ChatPanel.Controls.Add(this.AdminChannelText);
|
||||
this.ChatPanel.Controls.Add(this.ChatReconnectButton);
|
||||
this.ChatPanel.Controls.Add(this.ChatStatusLabel);
|
||||
this.ChatPanel.Controls.Add(this.ChatStatusTitle);
|
||||
@@ -1193,7 +1212,7 @@
|
||||
this.ChatPanel.Controls.Add(this.ChannelsTitle);
|
||||
this.ChatPanel.Controls.Add(this.ChatAdminsTextBox);
|
||||
this.ChatPanel.Controls.Add(this.ChatAdminsTitle);
|
||||
this.ChatPanel.Controls.Add(this.ChatChannelsTextBox);
|
||||
this.ChatPanel.Controls.Add(this.panel1);
|
||||
this.ChatPanel.Location = new System.Drawing.Point(4, 22);
|
||||
this.ChatPanel.Name = "ChatPanel";
|
||||
this.ChatPanel.Padding = new System.Windows.Forms.Padding(3);
|
||||
@@ -1201,6 +1220,117 @@
|
||||
this.ChatPanel.TabIndex = 4;
|
||||
this.ChatPanel.Text = "Chat";
|
||||
//
|
||||
// label5
|
||||
//
|
||||
this.label5.AutoSize = true;
|
||||
this.label5.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.label5.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242)))));
|
||||
this.label5.Location = new System.Drawing.Point(686, 219);
|
||||
this.label5.Name = "label5";
|
||||
this.label5.Size = new System.Drawing.Size(148, 18);
|
||||
this.label5.TabIndex = 43;
|
||||
this.label5.Text = "Game Messages:";
|
||||
this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// label4
|
||||
//
|
||||
this.label4.AutoSize = true;
|
||||
this.label4.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.label4.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242)))));
|
||||
this.label4.Location = new System.Drawing.Point(516, 219);
|
||||
this.label4.Name = "label4";
|
||||
this.label4.Size = new System.Drawing.Size(136, 18);
|
||||
this.label4.TabIndex = 42;
|
||||
this.label4.Text = "Developer Info:";
|
||||
this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// label3
|
||||
//
|
||||
this.label3.AutoSize = true;
|
||||
this.label3.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.label3.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242)))));
|
||||
this.label3.Location = new System.Drawing.Point(686, 61);
|
||||
this.label3.Name = "label3";
|
||||
this.label3.Size = new System.Drawing.Size(135, 18);
|
||||
this.label3.TabIndex = 41;
|
||||
this.label3.Text = "Administration:";
|
||||
this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// label2
|
||||
//
|
||||
this.label2.AutoSize = true;
|
||||
this.label2.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.label2.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242)))));
|
||||
this.label2.Location = new System.Drawing.Point(516, 61);
|
||||
this.label2.Name = "label2";
|
||||
this.label2.Size = new System.Drawing.Size(153, 18);
|
||||
this.label2.TabIndex = 40;
|
||||
this.label2.Text = "Server Watchdog:";
|
||||
this.label2.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// IRCModesComboBox
|
||||
//
|
||||
this.IRCModesComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
this.IRCModesComboBox.FormattingEnabled = true;
|
||||
this.IRCModesComboBox.Items.AddRange(new object[] {
|
||||
"Voice - +",
|
||||
"Halfop - %",
|
||||
"Op - @",
|
||||
"Owner - ~"});
|
||||
this.IRCModesComboBox.Location = new System.Drawing.Point(369, 170);
|
||||
this.IRCModesComboBox.Name = "IRCModesComboBox";
|
||||
this.IRCModesComboBox.Size = new System.Drawing.Size(141, 21);
|
||||
this.IRCModesComboBox.TabIndex = 38;
|
||||
this.IRCModesComboBox.Visible = false;
|
||||
//
|
||||
// label1
|
||||
//
|
||||
this.label1.AutoSize = true;
|
||||
this.label1.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.label1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242)))));
|
||||
this.label1.Location = new System.Drawing.Point(30, 174);
|
||||
this.label1.Name = "label1";
|
||||
this.label1.Size = new System.Drawing.Size(110, 18);
|
||||
this.label1.TabIndex = 39;
|
||||
this.label1.Text = "Admin Auth:";
|
||||
this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// AdminChannelsTextbox
|
||||
//
|
||||
this.AdminChannelsTextbox.Location = new System.Drawing.Point(689, 82);
|
||||
this.AdminChannelsTextbox.Multiline = true;
|
||||
this.AdminChannelsTextbox.Name = "AdminChannelsTextbox";
|
||||
this.AdminChannelsTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||
this.AdminChannelsTextbox.Size = new System.Drawing.Size(167, 120);
|
||||
this.AdminChannelsTextbox.TabIndex = 37;
|
||||
//
|
||||
// WDChannelsTextbox
|
||||
//
|
||||
this.WDChannelsTextbox.Location = new System.Drawing.Point(516, 82);
|
||||
this.WDChannelsTextbox.Multiline = true;
|
||||
this.WDChannelsTextbox.Name = "WDChannelsTextbox";
|
||||
this.WDChannelsTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||
this.WDChannelsTextbox.Size = new System.Drawing.Size(167, 120);
|
||||
this.WDChannelsTextbox.TabIndex = 36;
|
||||
//
|
||||
// GameChannelsTextbox
|
||||
//
|
||||
this.GameChannelsTextbox.Location = new System.Drawing.Point(689, 240);
|
||||
this.GameChannelsTextbox.Multiline = true;
|
||||
this.GameChannelsTextbox.Name = "GameChannelsTextbox";
|
||||
this.GameChannelsTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||
this.GameChannelsTextbox.Size = new System.Drawing.Size(167, 120);
|
||||
this.GameChannelsTextbox.TabIndex = 35;
|
||||
//
|
||||
// DevChannelsTextbox
|
||||
//
|
||||
this.DevChannelsTextbox.Location = new System.Drawing.Point(516, 240);
|
||||
this.DevChannelsTextbox.Multiline = true;
|
||||
this.DevChannelsTextbox.Name = "DevChannelsTextbox";
|
||||
this.DevChannelsTextbox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||
this.DevChannelsTextbox.Size = new System.Drawing.Size(167, 120);
|
||||
this.DevChannelsTextbox.TabIndex = 34;
|
||||
//
|
||||
// ChatRefreshButton
|
||||
//
|
||||
this.ChatRefreshButton.Location = new System.Drawing.Point(174, 335);
|
||||
@@ -1323,7 +1453,6 @@
|
||||
this.AuthField2.Name = "AuthField2";
|
||||
this.AuthField2.Size = new System.Drawing.Size(151, 20);
|
||||
this.AuthField2.TabIndex = 22;
|
||||
this.AuthField2.UseSystemPasswordChar = true;
|
||||
//
|
||||
// AuthField1
|
||||
//
|
||||
@@ -1331,26 +1460,6 @@
|
||||
this.AuthField1.Name = "AuthField1";
|
||||
this.AuthField1.Size = new System.Drawing.Size(151, 20);
|
||||
this.AuthField1.TabIndex = 21;
|
||||
this.AuthField1.UseSystemPasswordChar = true;
|
||||
//
|
||||
// AdminChannelTitle
|
||||
//
|
||||
this.AdminChannelTitle.AutoSize = true;
|
||||
this.AdminChannelTitle.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.AdminChannelTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242)))));
|
||||
this.AdminChannelTitle.Location = new System.Drawing.Point(30, 174);
|
||||
this.AdminChannelTitle.Name = "AdminChannelTitle";
|
||||
this.AdminChannelTitle.Size = new System.Drawing.Size(138, 18);
|
||||
this.AdminChannelTitle.TabIndex = 20;
|
||||
this.AdminChannelTitle.Text = "Admin Channel:";
|
||||
this.AdminChannelTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// AdminChannelText
|
||||
//
|
||||
this.AdminChannelText.Location = new System.Drawing.Point(174, 172);
|
||||
this.AdminChannelText.Name = "AdminChannelText";
|
||||
this.AdminChannelText.Size = new System.Drawing.Size(149, 20);
|
||||
this.AdminChannelText.TabIndex = 19;
|
||||
//
|
||||
// ChatReconnectButton
|
||||
//
|
||||
@@ -1441,9 +1550,9 @@
|
||||
this.ChatProviderTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242)))));
|
||||
this.ChatProviderTitle.Location = new System.Drawing.Point(20, 15);
|
||||
this.ChatProviderTitle.Name = "ChatProviderTitle";
|
||||
this.ChatProviderTitle.Size = new System.Drawing.Size(125, 18);
|
||||
this.ChatProviderTitle.Size = new System.Drawing.Size(144, 18);
|
||||
this.ChatProviderTitle.TabIndex = 13;
|
||||
this.ChatProviderTitle.Text = "Chat Provider:";
|
||||
this.ChatProviderTitle.Text = "Editing Provider:";
|
||||
this.ChatProviderTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// ChannelsTitle
|
||||
@@ -1451,7 +1560,7 @@
|
||||
this.ChannelsTitle.AutoSize = true;
|
||||
this.ChannelsTitle.Font = new System.Drawing.Font("Verdana", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
|
||||
this.ChannelsTitle.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242)))));
|
||||
this.ChannelsTitle.Location = new System.Drawing.Point(628, 15);
|
||||
this.ChannelsTitle.Location = new System.Drawing.Point(565, 15);
|
||||
this.ChannelsTitle.Name = "ChannelsTitle";
|
||||
this.ChannelsTitle.Size = new System.Drawing.Size(234, 18);
|
||||
this.ChannelsTitle.TabIndex = 11;
|
||||
@@ -1464,7 +1573,7 @@
|
||||
this.ChatAdminsTextBox.Multiline = true;
|
||||
this.ChatAdminsTextBox.Name = "ChatAdminsTextBox";
|
||||
this.ChatAdminsTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||
this.ChatAdminsTextBox.Size = new System.Drawing.Size(231, 311);
|
||||
this.ChatAdminsTextBox.Size = new System.Drawing.Size(141, 311);
|
||||
this.ChatAdminsTextBox.TabIndex = 10;
|
||||
//
|
||||
// ChatAdminsTitle
|
||||
@@ -1479,14 +1588,40 @@
|
||||
this.ChatAdminsTitle.Text = "Admins:";
|
||||
this.ChatAdminsTitle.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// ChatChannelsTextBox
|
||||
// panel1
|
||||
//
|
||||
this.ChatChannelsTextBox.Location = new System.Drawing.Point(631, 49);
|
||||
this.ChatChannelsTextBox.Multiline = true;
|
||||
this.ChatChannelsTextBox.Name = "ChatChannelsTextBox";
|
||||
this.ChatChannelsTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
|
||||
this.ChatChannelsTextBox.Size = new System.Drawing.Size(231, 311);
|
||||
this.ChatChannelsTextBox.TabIndex = 0;
|
||||
this.panel1.Controls.Add(this.AdminModeSpecial);
|
||||
this.panel1.Controls.Add(this.AdminModeNormal);
|
||||
this.panel1.Location = new System.Drawing.Point(174, 168);
|
||||
this.panel1.Name = "panel1";
|
||||
this.panel1.Size = new System.Drawing.Size(202, 25);
|
||||
this.panel1.TabIndex = 15;
|
||||
//
|
||||
// AdminModeSpecial
|
||||
//
|
||||
this.AdminModeSpecial.AutoSize = true;
|
||||
this.AdminModeSpecial.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242)))));
|
||||
this.AdminModeSpecial.Location = new System.Drawing.Point(87, 8);
|
||||
this.AdminModeSpecial.Name = "AdminModeSpecial";
|
||||
this.AdminModeSpecial.Size = new System.Drawing.Size(94, 17);
|
||||
this.AdminModeSpecial.TabIndex = 13;
|
||||
this.AdminModeSpecial.TabStop = true;
|
||||
this.AdminModeSpecial.Text = "Channel Mode";
|
||||
this.AdminModeSpecial.UseVisualStyleBackColor = true;
|
||||
this.AdminModeNormal.CheckedChanged += new System.EventHandler(this.AdminModeSpecial_CheckedChanged);
|
||||
//
|
||||
// AdminModeNormal
|
||||
//
|
||||
this.AdminModeNormal.AutoSize = true;
|
||||
this.AdminModeNormal.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(248)))), ((int)(((byte)(248)))), ((int)(((byte)(242)))));
|
||||
this.AdminModeNormal.Location = new System.Drawing.Point(3, 8);
|
||||
this.AdminModeNormal.Name = "AdminModeNormal";
|
||||
this.AdminModeNormal.Size = new System.Drawing.Size(78, 17);
|
||||
this.AdminModeNormal.TabIndex = 12;
|
||||
this.AdminModeNormal.TabStop = true;
|
||||
this.AdminModeNormal.Text = "Nicknames";
|
||||
this.AdminModeNormal.UseVisualStyleBackColor = true;
|
||||
this.AdminModeNormal.CheckedChanged += new System.EventHandler(this.AdminModeNormal_CheckedChanged);
|
||||
//
|
||||
// ConfigPanel
|
||||
//
|
||||
@@ -1881,6 +2016,8 @@
|
||||
((System.ComponentModel.ISupportInitialize)(this.ChatPortSelector)).EndInit();
|
||||
this.ChatProviderSelectorPanel.ResumeLayout(false);
|
||||
this.ChatProviderSelectorPanel.PerformLayout();
|
||||
this.panel1.ResumeLayout(false);
|
||||
this.panel1.PerformLayout();
|
||||
this.ConfigPanel.ResumeLayout(false);
|
||||
this.ConfigPanel.PerformLayout();
|
||||
this.ConfigPanels.ResumeLayout(false);
|
||||
@@ -1950,7 +2087,6 @@
|
||||
private System.Windows.Forms.TextBox ServerPathTextbox;
|
||||
private System.Windows.Forms.Label LatestVersionLabel;
|
||||
private System.Windows.Forms.Label LatestVersionTitle;
|
||||
private System.Windows.Forms.TextBox ChatChannelsTextBox;
|
||||
private System.Windows.Forms.Label ChannelsTitle;
|
||||
private System.Windows.Forms.TextBox ChatAdminsTextBox;
|
||||
private System.Windows.Forms.Label ChatAdminsTitle;
|
||||
@@ -1962,8 +2098,6 @@
|
||||
private System.Windows.Forms.RadioButton IRCProviderSwitch;
|
||||
private System.Windows.Forms.Label ChatProviderTitle;
|
||||
private System.Windows.Forms.Button ChatReconnectButton;
|
||||
private System.Windows.Forms.Label AdminChannelTitle;
|
||||
private System.Windows.Forms.TextBox AdminChannelText;
|
||||
private System.Windows.Forms.Label AuthField2Title;
|
||||
private System.Windows.Forms.Label AuthField1Title;
|
||||
private System.Windows.Forms.TextBox AuthField2;
|
||||
@@ -2028,5 +2162,18 @@
|
||||
private System.Windows.Forms.ComboBox VisibilitySelector;
|
||||
private System.ComponentModel.BackgroundWorker ServerStartBGW;
|
||||
private System.Windows.Forms.Button RepoRefreshButton;
|
||||
private System.Windows.Forms.ComboBox IRCModesComboBox;
|
||||
private System.Windows.Forms.TextBox AdminChannelsTextbox;
|
||||
private System.Windows.Forms.TextBox WDChannelsTextbox;
|
||||
private System.Windows.Forms.TextBox GameChannelsTextbox;
|
||||
private System.Windows.Forms.TextBox DevChannelsTextbox;
|
||||
private System.Windows.Forms.Panel panel1;
|
||||
private System.Windows.Forms.RadioButton AdminModeSpecial;
|
||||
private System.Windows.Forms.RadioButton AdminModeNormal;
|
||||
private System.Windows.Forms.Label label5;
|
||||
private System.Windows.Forms.Label label4;
|
||||
private System.Windows.Forms.Label label3;
|
||||
private System.Windows.Forms.Label label2;
|
||||
private System.Windows.Forms.Label label1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,5 +25,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("3.0.85.4")]
|
||||
[assembly: AssemblyFileVersion("3.0.85.4")]
|
||||
[assembly: AssemblyVersion("3.0.86.0")]
|
||||
[assembly: AssemblyFileVersion("3.0.86.0")]
|
||||
|
||||
+12
@@ -58,5 +58,17 @@ namespace TGControlPanel.Properties {
|
||||
this["UpgradeRequired"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("0")]
|
||||
public int LastChatProvider {
|
||||
get {
|
||||
return ((int)(this["LastChatProvider"]));
|
||||
}
|
||||
set {
|
||||
this["LastChatProvider"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,5 +11,8 @@
|
||||
<Setting Name="UpgradeRequired" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
</Setting>
|
||||
<Setting Name="LastChatProvider" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
@@ -25,5 +25,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("3.0.85.4")]
|
||||
[assembly: AssemblyFileVersion("3.0.85.4")]
|
||||
[assembly: AssemblyVersion("3.0.86.0")]
|
||||
[assembly: AssemblyFileVersion("3.0.86.0")]
|
||||
|
||||
@@ -34,42 +34,17 @@
|
||||
<setting name="ServerVisiblity" serializeAs="String">
|
||||
<value>2</value>
|
||||
</setting>
|
||||
<setting name="ChatEnabled" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="DDAutoStart" serializeAs="String">
|
||||
<value>False</value>
|
||||
</setting>
|
||||
<setting name="PythonPath" serializeAs="String">
|
||||
<value>C:\Python27</value>
|
||||
</setting>
|
||||
<setting name="ChatProvider" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="ChatProviderData" serializeAs="String">
|
||||
<value>NEEDS INITIALIZING</value>
|
||||
</setting>
|
||||
<setting name="ChatAdmins" serializeAs="Xml">
|
||||
<value>
|
||||
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<string>theghostofwhibyl1</string>
|
||||
</ArrayOfString>
|
||||
</value>
|
||||
</setting>
|
||||
<setting name="ChatChannels" serializeAs="Xml">
|
||||
<value>
|
||||
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<string>#botbus</string>
|
||||
</ArrayOfString>
|
||||
</value>
|
||||
</setting>
|
||||
<setting name="ChatAdminChannel" serializeAs="String">
|
||||
<value>#botbus</value>
|
||||
</setting>
|
||||
<setting name="ChatProviderEntropy" serializeAs="String">
|
||||
<value>John Madden</value>
|
||||
<value />
|
||||
</setting>
|
||||
<setting name="UpgradeRequired" serializeAs="String">
|
||||
<value>True</value>
|
||||
@@ -83,6 +58,9 @@
|
||||
<setting name="ReattachPort" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
<setting name="SettingsVersion" serializeAs="String">
|
||||
<value>0</value>
|
||||
</setting>
|
||||
</TGServerService.Properties.Settings>
|
||||
</userSettings>
|
||||
</configuration>
|
||||
|
||||
@@ -163,7 +163,7 @@ namespace TGServerService
|
||||
var vi = (VersionInfo)param;
|
||||
using (var client = new WebClient())
|
||||
{
|
||||
SendMessage(String.Format("BYOND: Updating to version {0}.{1}...", vi.major, vi.minor));
|
||||
SendMessage(String.Format("BYOND: Updating to version {0}.{1}...", vi.major, vi.minor), ChatMessageType.DeveloperInfo);
|
||||
|
||||
//DOWNLOADING
|
||||
|
||||
@@ -173,7 +173,7 @@ namespace TGServerService
|
||||
}
|
||||
catch
|
||||
{
|
||||
SendMessage("BYOND: Update download failed. Does the specified version exist?");
|
||||
SendMessage("BYOND: Update download failed. Does the specified version exist?", ChatMessageType.DeveloperInfo);
|
||||
lastError = String.Format("Download of BYOND version {0}.{1} failed! Does it exist?", vi.major, vi.minor);
|
||||
TGServerService.WriteWarning(String.Format("Failed to update BYOND to version {0}.{1}!", vi.major, vi.minor), TGServerService.EventID.BYONDUpdateFail);
|
||||
lock (ByondLock)
|
||||
@@ -216,7 +216,7 @@ namespace TGServerService
|
||||
default:
|
||||
RequestRestart();
|
||||
lastError = "Update staged. Awaiting server restart...";
|
||||
SendMessage(String.Format("BYOND: Staging complete. Awaiting server restart...", vi.major, vi.minor));
|
||||
SendMessage(String.Format("BYOND: Staging complete. Awaiting server restart...", vi.major, vi.minor), ChatMessageType.DeveloperInfo);
|
||||
TGServerService.WriteInfo(String.Format("BYOND update {0}.{1} staged", vi.major, vi.minor), TGServerService.EventID.BYONDUpdateStaged);
|
||||
break;
|
||||
}
|
||||
@@ -273,14 +273,14 @@ namespace TGServerService
|
||||
Directory.Move(StagingDirectoryInner, ByondDirectory);
|
||||
Program.DeleteDirectory(StagingDirectory);
|
||||
lastError = null;
|
||||
SendMessage("BYOND: Update completed!");
|
||||
SendMessage("BYOND: Update completed!", ChatMessageType.DeveloperInfo);
|
||||
TGServerService.WriteInfo(String.Format("BYOND update {0} completed!", GetVersion(TGByondVersion.Installed)), TGServerService.EventID.BYONDUpdateComplete);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
lastError = e.ToString();
|
||||
SendMessage("BYOND: Update failed!");
|
||||
SendMessage("BYOND: Update failed!", ChatMessageType.DeveloperInfo);
|
||||
TGServerService.WriteError("BYOND update failed!", TGServerService.EventID.BYONDUpdateFail);
|
||||
return false;
|
||||
}
|
||||
|
||||
+149
-234
@@ -1,26 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Web.Script.Serialization;
|
||||
using TGServiceInterface;
|
||||
|
||||
namespace TGServerService
|
||||
{
|
||||
interface ITGChatProvider : ITGChatBase, IDisposable
|
||||
/// <summary>
|
||||
/// Type of chat message, these may be OR'd together
|
||||
/// </summary>
|
||||
[Flags]
|
||||
enum ChatMessageType
|
||||
{
|
||||
AdminInfo = 1,
|
||||
GameInfo = 2,
|
||||
WatchdogInfo = 4,
|
||||
DeveloperInfo = 8,
|
||||
}
|
||||
interface ITGChatProvider : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Sets info for the provider
|
||||
/// </summary>
|
||||
/// <param name="info">The info to set</param>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
string SetProviderInfo(TGChatSetupInfo info);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the info of the provider
|
||||
/// </summary>
|
||||
/// <returns>The info for the chat provider</returns>
|
||||
TGChatSetupInfo ProviderInfo();
|
||||
|
||||
/// <summary>
|
||||
/// Called with chat message info
|
||||
/// </summary>
|
||||
event OnChatMessage OnChatMessage;
|
||||
|
||||
/// <summary>
|
||||
/// Connects the chat provider
|
||||
/// Connects the chat provider if it's enabled
|
||||
/// </summary>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
string Connect();
|
||||
/// <summary>
|
||||
/// Forces a reconnection of the chat provider if it's enabled
|
||||
/// </summary>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
string Reconnect();
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the chat provider is connected
|
||||
/// </summary>
|
||||
/// <returns>true if the provider is connected, false otherwise</returns>
|
||||
bool Connected();
|
||||
|
||||
/// <summary>
|
||||
/// Disconnects the chat provider
|
||||
@@ -34,72 +66,70 @@ namespace TGServerService
|
||||
/// <param name="channel">The channel to send to</param>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
string SendMessageDirect(string message, string channel);
|
||||
|
||||
/// <summary>
|
||||
/// Broadcast a message to appropriate channels based on the message type
|
||||
/// </summary>
|
||||
/// <param name="msg">The message to send</param>
|
||||
/// <param name="mt">The message type</param>
|
||||
void SendMessage(string msg, ChatMessageType mt);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Callback for the chat provider recieving a message
|
||||
/// </summary>
|
||||
/// <param name="ChatProvider">The chat provider the message came from</param>
|
||||
/// <param name="speaker">The username of the speaker</param>
|
||||
/// <param name="channel">The name of the channel</param>
|
||||
/// <param name="message">The message text</param>
|
||||
/// <param name="tagged">true if the bot was mentioned in the first word, false otherwise</param>
|
||||
public delegate void OnChatMessage(string speaker, string channel, string message, bool tagged);
|
||||
delegate void OnChatMessage(ITGChatProvider ChatProvider, string speaker, string channel, string message, bool isAdmin, bool isAdminChannel);
|
||||
|
||||
partial class TGStationServer : ITGChat
|
||||
{
|
||||
ITGChatProvider ChatProvider;
|
||||
TGChatProvider currentProvider;
|
||||
|
||||
IList<ITGChatProvider> ChatProviders;
|
||||
object ChatLock = new object();
|
||||
|
||||
public void InitChat(TGChatSetupInfo info = null)
|
||||
public void InitChat()
|
||||
{
|
||||
if (info == null)
|
||||
info = ProviderInfo();
|
||||
currentProvider = info.Provider;
|
||||
try
|
||||
var infos = InitProviderInfos();
|
||||
ChatProviders = new List<ITGChatProvider>(infos.Count);
|
||||
foreach (var info in infos)
|
||||
{
|
||||
switch (info.Provider)
|
||||
ITGChatProvider ChatProvider;
|
||||
try
|
||||
{
|
||||
case TGChatProvider.Discord:
|
||||
ChatProvider = new TGDiscordChatProvider(info);
|
||||
break;
|
||||
case TGChatProvider.IRC:
|
||||
ChatProvider = new TGIRCChatProvider(info);
|
||||
break;
|
||||
default:
|
||||
TGServerService.WriteError(String.Format("Invalid chat provider: {0}", info.Provider), TGServerService.EventID.InvalidChatProvider);
|
||||
break;
|
||||
switch (info.Provider)
|
||||
{
|
||||
case TGChatProvider.Discord:
|
||||
ChatProvider = new TGDiscordChatProvider(info);
|
||||
break;
|
||||
case TGChatProvider.IRC:
|
||||
ChatProvider = new TGIRCChatProvider(info);
|
||||
break;
|
||||
default:
|
||||
TGServerService.WriteError(String.Format("Invalid chat provider: {0}", info.Provider), TGServerService.EventID.InvalidChatProvider);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
TGServerService.WriteError(String.Format("Failed to start chat provider {0}! Error: {1}", info.Provider, e.ToString()), TGServerService.EventID.ChatProviderStartFail);
|
||||
return;
|
||||
}
|
||||
ChatProvider.OnChatMessage += ChatProvider_OnChatMessage;
|
||||
if (Properties.Settings.Default.ChatEnabled)
|
||||
{
|
||||
catch (Exception e)
|
||||
{
|
||||
TGServerService.WriteError(String.Format("Failed to start chat provider {0}! Error: {1}", info.Provider, e.ToString()), TGServerService.EventID.ChatProviderStartFail);
|
||||
continue;
|
||||
}
|
||||
ChatProvider.OnChatMessage += ChatProvider_OnChatMessage;
|
||||
var res = ChatProvider.Connect();
|
||||
if (res != null)
|
||||
TGServerService.WriteWarning(String.Format("Unable to connect to chat! Provider {0}, Error: {1}", ChatProvider.GetType().ToString(), res), TGServerService.EventID.ChatConnectFail);
|
||||
ChatProviders.Add(ChatProvider);
|
||||
}
|
||||
}
|
||||
|
||||
private void ChatProvider_OnChatMessage(string speaker, string channel, string message, bool tagged)
|
||||
private void ChatProvider_OnChatMessage(ITGChatProvider ChatProvider, string speaker, string channel, string message, bool isAdmin, bool isAdminChannel)
|
||||
{
|
||||
var splits = message.Trim().Split(' ');
|
||||
|
||||
var s0l = splits[0].ToLower();
|
||||
|
||||
if (s0l == "!check")
|
||||
{
|
||||
ChatProvider.SendMessageDirect(StatusString(HasChatAdmin(speaker, channel) == null), channel);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!tagged)
|
||||
return;
|
||||
|
||||
|
||||
if (splits.Length == 1 && splits[0] == "")
|
||||
{
|
||||
ChatProvider.SendMessageDirect("Hi!", channel);
|
||||
@@ -110,37 +140,48 @@ namespace TGServerService
|
||||
var command = asList[0].ToLower();
|
||||
asList.RemoveAt(0);
|
||||
|
||||
ChatProvider.SendMessageDirect(ChatCommand(command, speaker, channel, asList), channel);
|
||||
ChatProvider.SendMessageDirect(ChatCommand(command, speaker, channel, asList, isAdmin, isAdminChannel), channel);
|
||||
}
|
||||
|
||||
string HasChatAdmin(string speaker, string channel)
|
||||
string HasChatAdmin(bool isAdmin, bool isAdminChannel)
|
||||
{
|
||||
var Config = Properties.Settings.Default;
|
||||
if (!Config.ChatAdmins.Contains(speaker.ToLower()))
|
||||
if (!isAdmin)
|
||||
return "You are not authorized to use that command!";
|
||||
if (channel.ToLower() != Config.ChatAdminChannel.ToLower())
|
||||
return "Use this command in the admin channel!";
|
||||
if (!isAdminChannel)
|
||||
return "Use this command in an admin channel!";
|
||||
return null;
|
||||
}
|
||||
|
||||
//cleanup
|
||||
//cleanup and save
|
||||
void DisposeChat()
|
||||
{
|
||||
if (ChatProvider != null)
|
||||
var infosList = new List<IList<string>>();
|
||||
|
||||
foreach (var ChatProvider in ChatProviders)
|
||||
{
|
||||
infosList.Add(ChatProvider.ProviderInfo().DataFields);
|
||||
ChatProvider.Dispose();
|
||||
ChatProvider = null;
|
||||
}
|
||||
ChatProviders = null;
|
||||
|
||||
var rawdata = new JavaScriptSerializer().Serialize(infosList);
|
||||
var Config = Properties.Settings.Default;
|
||||
|
||||
byte[] plaintext = Encoding.UTF8.GetBytes(rawdata);
|
||||
|
||||
Config.ChatProviderData = Program.EncryptData(plaintext, out string entrp);
|
||||
Config.ChatProviderEntropy = entrp;
|
||||
}
|
||||
|
||||
//Do stuff with words that were spoken to us
|
||||
string ChatCommand(string command, string speaker, string channel, IList<string> parameters)
|
||||
string ChatCommand(string command, string speaker, string channel, IList<string> parameters, bool isAdmin, bool isAdminChannel)
|
||||
{
|
||||
TGServerService.WriteInfo(String.Format("Chat Command from {0}: {1} {2}", speaker, command, String.Join(" ", parameters)), TGServerService.EventID.ChatCommand);
|
||||
var adminmessage = HasChatAdmin(isAdmin, isAdminChannel);
|
||||
switch (command)
|
||||
{
|
||||
case "check":
|
||||
return StatusString(HasChatAdmin(speaker, channel) == null);
|
||||
return StatusString(adminmessage == null);
|
||||
case "byond":
|
||||
if (parameters.Count > 0)
|
||||
if (parameters[0].ToLower() == "--staged")
|
||||
@@ -149,27 +190,25 @@ namespace TGServerService
|
||||
return GetVersion(TGByondVersion.Latest) ?? "Unknown";
|
||||
return GetVersion(TGByondVersion.Staged) ?? "Uninstalled";
|
||||
case "status":
|
||||
return HasChatAdmin(speaker, channel) ?? SendCommand(SCIRCStatus);
|
||||
return adminmessage ?? SendCommand(SCIRCStatus);
|
||||
case "adminwho":
|
||||
return HasChatAdmin(speaker, channel) ?? SendCommand(SCAdminWho);
|
||||
return adminmessage ?? SendCommand(SCAdminWho);
|
||||
case "ahelp":
|
||||
var res = HasChatAdmin(speaker, channel);
|
||||
if (res != null)
|
||||
return res;
|
||||
if (adminmessage != null)
|
||||
return adminmessage;
|
||||
if (parameters.Count < 2)
|
||||
return "Usage: ahelp <ckey> <message>";
|
||||
var ckey = parameters[0];
|
||||
parameters.RemoveAt(0);
|
||||
return SendPM(ckey, speaker, String.Join(" ", parameters));
|
||||
case "namecheck":
|
||||
res = HasChatAdmin(speaker, channel);
|
||||
if (res != null)
|
||||
return res;
|
||||
if (adminmessage != null)
|
||||
return adminmessage;
|
||||
if (parameters.Count < 1)
|
||||
return "Usage: namecheck <target>";
|
||||
return NameCheck(parameters[0], speaker);
|
||||
case "prs":
|
||||
var PRs = MergedPullRequests(out res);
|
||||
var PRs = MergedPullRequests(out string res);
|
||||
if (PRs == null)
|
||||
return res;
|
||||
if (PRs.Count == 0)
|
||||
@@ -186,100 +225,34 @@ namespace TGServerService
|
||||
return "Unknown command: " + command;
|
||||
}
|
||||
|
||||
//public api
|
||||
public string SetEnabled(bool enable)
|
||||
public IList<TGChatSetupInfo> ProviderInfos()
|
||||
{
|
||||
lock (ChatLock)
|
||||
{
|
||||
Properties.Settings.Default.ChatEnabled = enable;
|
||||
if (!enable && Connected())
|
||||
ChatProvider.Disconnect();
|
||||
else if (enable && !Connected())
|
||||
return ChatProvider != null ? ChatProvider.Connect() : "Null chat provider!";
|
||||
return null;
|
||||
}
|
||||
var infosList = new List<TGChatSetupInfo>();
|
||||
foreach (var ChatProvider in ChatProviders)
|
||||
infosList.Add(ChatProvider.ProviderInfo());
|
||||
return infosList;
|
||||
}
|
||||
|
||||
//public api
|
||||
public string[] Channels()
|
||||
{
|
||||
lock (ChatLock)
|
||||
{
|
||||
return CollectionToArray(Properties.Settings.Default.ChatChannels);
|
||||
}
|
||||
}
|
||||
|
||||
//what it says on the tin
|
||||
string[] CollectionToArray(StringCollection sc)
|
||||
{
|
||||
string[] strArray = new string[sc.Count];
|
||||
sc.CopyTo(strArray, 0);
|
||||
return strArray;
|
||||
}
|
||||
//public api
|
||||
public string AdminChannel()
|
||||
{
|
||||
lock (ChatLock)
|
||||
{
|
||||
return Properties.Settings.Default.ChatAdminChannel;
|
||||
}
|
||||
}
|
||||
//public api
|
||||
public bool Enabled()
|
||||
{
|
||||
lock (ChatLock)
|
||||
{
|
||||
return Properties.Settings.Default.ChatEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
//public api
|
||||
public string[] ListAdmins()
|
||||
{
|
||||
lock (ChatLock)
|
||||
{
|
||||
return CollectionToArray(Properties.Settings.Default.ChatAdmins);
|
||||
}
|
||||
}
|
||||
|
||||
//public api
|
||||
public void SetAdmins(string[] admins)
|
||||
{
|
||||
var si = new StringCollection();
|
||||
foreach (var I in admins)
|
||||
si.Add(I.Trim().ToLower());
|
||||
lock (ChatLock)
|
||||
{
|
||||
Properties.Settings.Default.ChatAdmins = si;
|
||||
}
|
||||
}
|
||||
|
||||
//public api
|
||||
public TGChatSetupInfo ProviderInfo()
|
||||
IList<TGChatSetupInfo> InitProviderInfos()
|
||||
{
|
||||
lock (ChatLock)
|
||||
{
|
||||
var Config = Properties.Settings.Default;
|
||||
var rawdata = Config.ChatProviderData;
|
||||
if (rawdata == "NEEDS INITIALIZING")
|
||||
switch ((TGChatProvider)Config.ChatProvider)
|
||||
{
|
||||
case TGChatProvider.Discord:
|
||||
return new TGDiscordSetupInfo();
|
||||
case TGChatProvider.IRC:
|
||||
return new TGIRCSetupInfo();
|
||||
default:
|
||||
TGServerService.WriteError("Invalid chat provider: " + Config.ChatProvider.ToString(), TGServerService.EventID.InvalidChatProvider);
|
||||
return null;
|
||||
}
|
||||
return new List<TGChatSetupInfo>() { new TGIRCSetupInfo(), new TGDiscordSetupInfo() };
|
||||
|
||||
byte[] plaintext;
|
||||
try
|
||||
{
|
||||
plaintext = ProtectedData.Unprotect(Convert.FromBase64String(Config.ChatProviderData), Convert.FromBase64String(Config.ChatProviderEntropy), DataProtectionScope.CurrentUser);
|
||||
|
||||
var Deserializer = new JavaScriptSerializer();
|
||||
return new TGChatSetupInfo(Deserializer.Deserialize<List<string>>(Encoding.UTF8.GetString(plaintext)), (TGChatProvider)Config.ChatProvider);
|
||||
plaintext = Program.DecryptData(rawdata, Config.ChatProviderEntropy);
|
||||
|
||||
var lists = new JavaScriptSerializer().Deserialize<List<List<string>>>(Encoding.UTF8.GetString(plaintext));
|
||||
var output = new List<TGChatSetupInfo>(lists.Count);
|
||||
foreach (var l in lists)
|
||||
output.Add(new TGChatSetupInfo(l));
|
||||
return output;
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -287,7 +260,7 @@ namespace TGServerService
|
||||
}
|
||||
}
|
||||
//if we get here we want to retry
|
||||
return ProviderInfo();
|
||||
return InitProviderInfos();
|
||||
}
|
||||
|
||||
//public api
|
||||
@@ -297,34 +270,10 @@ namespace TGServerService
|
||||
{
|
||||
lock (ChatLock)
|
||||
{
|
||||
var Serializer = new JavaScriptSerializer();
|
||||
var rawdata = Serializer.Serialize(info.DataFields);
|
||||
var Config = Properties.Settings.Default;
|
||||
Config.ChatProvider = (int)info.Provider;
|
||||
Config.ChatProviderData = rawdata;
|
||||
|
||||
byte[] plaintext = Encoding.UTF8.GetBytes(rawdata);
|
||||
|
||||
// Generate additional entropy (will be used as the Initialization vector)
|
||||
byte[] entropy = new byte[20];
|
||||
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
|
||||
{
|
||||
rng.GetBytes(entropy);
|
||||
}
|
||||
|
||||
byte[] ciphertext = ProtectedData.Protect(plaintext, entropy, DataProtectionScope.CurrentUser);
|
||||
|
||||
Config.ChatProviderEntropy = Convert.ToBase64String(entropy, 0, entropy.Length);
|
||||
Config.ChatProviderData = Convert.ToBase64String(ciphertext, 0, ciphertext.Length);
|
||||
|
||||
if (ChatProvider != null && info.Provider == currentProvider)
|
||||
return ChatProvider.SetProviderInfo(info);
|
||||
else
|
||||
{
|
||||
DisposeChat();
|
||||
InitChat(info);
|
||||
return null;
|
||||
}
|
||||
foreach (var ChatProvider in ChatProviders)
|
||||
if (info.Provider == ChatProvider.ProviderInfo().Provider)
|
||||
return ChatProvider.SetProviderInfo(info);
|
||||
return "Error: Invalid provider: " + info.Provider.ToString();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -333,75 +282,41 @@ namespace TGServerService
|
||||
}
|
||||
}
|
||||
|
||||
//trims and adds the leading #
|
||||
string SanitizeChannelName(string working)
|
||||
//public api
|
||||
public bool Connected(TGChatProvider providerType)
|
||||
{
|
||||
if (String.IsNullOrWhiteSpace(working))
|
||||
return null;
|
||||
working = working.Trim();
|
||||
if (working[0] != '#')
|
||||
return "#" + working;
|
||||
return working;
|
||||
foreach (var I in ChatProviders)
|
||||
if (I.ProviderInfo().Provider == providerType)
|
||||
return I.Connected();
|
||||
return false;
|
||||
}
|
||||
|
||||
//public api
|
||||
public void SetChannels(string[] channels = null, string adminchannel = null)
|
||||
public string Reconnect(TGChatProvider providerType)
|
||||
{
|
||||
foreach (var I in ChatProviders)
|
||||
if (I.ProviderInfo().Provider == providerType)
|
||||
return I.Reconnect();
|
||||
return "Could not find specified provider!";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Broadcast a message to appropriate channels based on the message type
|
||||
/// </summary>
|
||||
/// <param name="msg">The message to send</param>
|
||||
/// <param name="mt">The message type</param>
|
||||
public void SendMessage(string msg, ChatMessageType mt)
|
||||
{
|
||||
var Config = Properties.Settings.Default;
|
||||
lock (ChatLock)
|
||||
{
|
||||
if (channels != null)
|
||||
{
|
||||
var oldchannels = Config.ChatChannels;
|
||||
var si = new StringCollection();
|
||||
foreach (var c in channels)
|
||||
foreach (var ChatProvider in ChatProviders)
|
||||
try
|
||||
{
|
||||
var Res = SanitizeChannelName(c);
|
||||
if (Res != null)
|
||||
si.Add(Res);
|
||||
ChatProvider.SendMessage(msg, mt);
|
||||
}catch(Exception e)
|
||||
{
|
||||
TGServerService.WriteWarning(String.Format("Chat broadcast failed (Provider: {3}) (Flags: {0}) (Message: {1}): {2}", mt, msg, e.ToString(), ChatProvider.ProviderInfo().Provider), TGServerService.EventID.ChatBroadcastFail);
|
||||
}
|
||||
if (!si.Contains(Config.ChatAdminChannel))
|
||||
si.Add(Config.ChatAdminChannel);
|
||||
Config.ChatChannels = si;
|
||||
}
|
||||
adminchannel = SanitizeChannelName(adminchannel);
|
||||
if (adminchannel != null)
|
||||
{
|
||||
Config.ChatAdminChannel = adminchannel;
|
||||
if (!Config.ChatChannels.Contains(adminchannel))
|
||||
Config.ChatChannels.Add(adminchannel);
|
||||
}
|
||||
if (channels != null && Connected())
|
||||
ChatProvider.SetChannels(CollectionToArray(Config.ChatChannels), Config.ChatAdminChannel);
|
||||
}
|
||||
}
|
||||
|
||||
//public api
|
||||
public bool Connected()
|
||||
{
|
||||
lock (ChatLock)
|
||||
{
|
||||
return ChatProvider != null ? ChatProvider.Connected() : false;
|
||||
}
|
||||
}
|
||||
|
||||
//public api
|
||||
public string Reconnect()
|
||||
{
|
||||
lock (ChatLock)
|
||||
{
|
||||
if (!Properties.Settings.Default.ChatEnabled)
|
||||
return "Chat is disabled!";
|
||||
return ChatProvider != null ? ChatProvider.Reconnect() : "Null chat provider!";
|
||||
}
|
||||
}
|
||||
|
||||
//public api
|
||||
public string SendMessage(string msg, bool adminOnly = false)
|
||||
{
|
||||
lock (ChatLock)
|
||||
{
|
||||
return ChatProvider != null ? ChatProvider.SendMessage(msg, adminOnly) : "Null chat provider!";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +179,7 @@ namespace TGServerService
|
||||
}
|
||||
try
|
||||
{
|
||||
SendMessage("DM: Setting up symlinks...");
|
||||
SendMessage("DM: Setting up symlinks...", ChatMessageType.DeveloperInfo);
|
||||
CleanGameFolder();
|
||||
Program.DeleteDirectory(GameDir);
|
||||
|
||||
@@ -211,7 +211,7 @@ namespace TGServerService
|
||||
{
|
||||
lock (CompilerLock)
|
||||
{
|
||||
SendMessage("DM: Setup failed!");
|
||||
SendMessage("DM: Setup failed!", ChatMessageType.DeveloperInfo);
|
||||
lastCompilerError = e.ToString();
|
||||
compilerCurrentStatus = TGCompilerStatus.Uninitialized;
|
||||
return;
|
||||
@@ -301,7 +301,7 @@ namespace TGServerService
|
||||
}
|
||||
|
||||
if(!silent)
|
||||
SendMessage("DM: Compiling...");
|
||||
SendMessage("DM: Compiling...", ChatMessageType.DeveloperInfo);
|
||||
|
||||
var resurrectee = GetStagingDir();
|
||||
|
||||
@@ -331,7 +331,7 @@ namespace TGServerService
|
||||
|
||||
if (repobusy_check)
|
||||
{
|
||||
SendMessage("DM: Copy aborted, repo locked!");
|
||||
SendMessage("DM: Copy aborted, repo locked!", ChatMessageType.DeveloperInfo);
|
||||
lock (CompilerLock)
|
||||
{
|
||||
lastCompilerError = "The repo could not be locked for copying";
|
||||
@@ -368,7 +368,7 @@ namespace TGServerService
|
||||
if (!File.Exists(dmePath))
|
||||
{
|
||||
var errorMsg = String.Format("Could not find {0}!", dmeName);
|
||||
SendMessage("DM: " + errorMsg);
|
||||
SendMessage("DM: " + errorMsg, ChatMessageType.DeveloperInfo);
|
||||
TGServerService.WriteError(errorMsg, TGServerService.EventID.DMCompileCrash);
|
||||
lock (CompilerLock)
|
||||
{
|
||||
@@ -464,7 +464,7 @@ namespace TGServerService
|
||||
}
|
||||
var staged = DaemonStatus() != TGDreamDaemonStatus.Offline;
|
||||
var msg = String.Format("Compile complete!{0}", !staged ? "" : " Server will update next round.");
|
||||
SendMessage("DM: " + msg);
|
||||
SendMessage("DM: " + msg, ChatMessageType.DeveloperInfo);
|
||||
TGServerService.WriteInfo(msg, TGServerService.EventID.DMCompileSuccess);
|
||||
lock (CompilerLock)
|
||||
{
|
||||
@@ -476,7 +476,7 @@ namespace TGServerService
|
||||
}
|
||||
else
|
||||
{
|
||||
SendMessage("DM: Compile failed!"); //Also happens for warnings
|
||||
SendMessage("DM: Compile failed!", ChatMessageType.DeveloperInfo); //Also happens for warnings
|
||||
TGServerService.WriteWarning("Compile error: " + OutputList.ToString(), TGServerService.EventID.DMCompileError);
|
||||
lock (CompilerLock)
|
||||
{
|
||||
@@ -493,7 +493,7 @@ namespace TGServerService
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SendMessage("DM: Compiler thread crashed!");
|
||||
SendMessage("DM: Compiler thread crashed!", ChatMessageType.DeveloperInfo);
|
||||
TGServerService.WriteError("Compile manager errror: " + e.ToString(), TGServerService.EventID.DMCompileCrash);
|
||||
lock (CompilerLock)
|
||||
{
|
||||
@@ -510,7 +510,7 @@ namespace TGServerService
|
||||
{
|
||||
compilerCurrentStatus = TGCompilerStatus.Initialized;
|
||||
compilationCancellationRequestation = false;
|
||||
SendMessage("DM: Compile cancelled!");
|
||||
SendMessage("DM: Compile cancelled!", ChatMessageType.DeveloperInfo);
|
||||
TGServerService.WriteInfo("Compilation cancelled", TGServerService.EventID.DMCompileCancel);
|
||||
}
|
||||
}
|
||||
|
||||
+77
-45
@@ -1,6 +1,7 @@
|
||||
using Discord;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TGServiceInterface;
|
||||
|
||||
@@ -20,6 +21,11 @@ namespace TGServerService
|
||||
Init(info);
|
||||
}
|
||||
|
||||
public TGChatSetupInfo ProviderInfo()
|
||||
{
|
||||
return DiscordConfig;
|
||||
}
|
||||
|
||||
void Init(TGChatSetupInfo info)
|
||||
{
|
||||
DiscordConfig = new TGDiscordSetupInfo(info);
|
||||
@@ -27,29 +33,50 @@ namespace TGServerService
|
||||
client.MessageReceived += Client_MessageReceived;
|
||||
}
|
||||
|
||||
private bool CheckAdmin(User u)
|
||||
{
|
||||
if (!DiscordConfig.AdminsAreSpecial)
|
||||
return DiscordConfig.AdminList.Contains(u.Id.ToString());
|
||||
foreach (var I in u.Roles)
|
||||
if (DiscordConfig.AdminList.Contains(I.Id.ToString()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void Client_MessageReceived(object sender, MessageEventArgs e)
|
||||
{
|
||||
var isValidChannel = Properties.Settings.Default.ChatChannels.Contains("#" + e.Channel.Name) || e.Channel.IsPrivate;
|
||||
if (!isValidChannel)
|
||||
return;
|
||||
|
||||
var tagged = e.Channel.IsPrivate && e.User.Id != client.CurrentUser.Id;
|
||||
if (tagged && !SeenPrivateChannels.ContainsKey(e.Channel.Id))
|
||||
var pm = e.Channel.IsPrivate && e.User.Id != client.CurrentUser.Id;
|
||||
|
||||
if (pm && !SeenPrivateChannels.ContainsKey(e.Channel.Id))
|
||||
SeenPrivateChannels.Add(e.Channel.Id, e.Channel);
|
||||
|
||||
var splits = new List<string>(e.Message.Text.Trim().Split(' '));
|
||||
if (splits[0] == "@" + client.CurrentUser.Name)
|
||||
{
|
||||
splits.RemoveAt(0);
|
||||
tagged = true;
|
||||
}
|
||||
OnChatMessage(e.User.Id.ToString(), e.Channel.Id.ToString(), String.Join(" ", splits), tagged);
|
||||
bool found = false;
|
||||
|
||||
var formattedMessage = e.Message.RawText;
|
||||
foreach (var u in e.Message.MentionedUsers)
|
||||
if(u.Id == client.CurrentUser.Id)
|
||||
{
|
||||
found = true;
|
||||
formattedMessage = formattedMessage.Replace(u.Mention, "");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!found && !pm)
|
||||
return;
|
||||
|
||||
formattedMessage = formattedMessage.Trim();
|
||||
|
||||
var cid = e.Channel.Id.ToString();
|
||||
|
||||
OnChatMessage(this, e.User.Id.ToString(), cid, formattedMessage, CheckAdmin(e.User), pm || DiscordConfig.AdminChannels.Contains(cid));
|
||||
}
|
||||
|
||||
public string Connect()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Connected() || !DiscordConfig.Enabled)
|
||||
return null;
|
||||
lock (DiscordLock)
|
||||
{
|
||||
SeenPrivateChannels.Clear();
|
||||
@@ -105,35 +132,36 @@ namespace TGServerService
|
||||
}
|
||||
}
|
||||
|
||||
public string SendMessage(string msg, bool adminOnly = false)
|
||||
public void SendMessage(string msg, ChatMessageType mt)
|
||||
{
|
||||
try
|
||||
if (!Connected())
|
||||
return;
|
||||
lock (DiscordLock)
|
||||
{
|
||||
lock (DiscordLock)
|
||||
{
|
||||
var tasks = new List<Task>();
|
||||
var Config = Properties.Settings.Default;
|
||||
foreach (var I in client.Servers)
|
||||
foreach (var J in I.TextChannels)
|
||||
{
|
||||
var SendToThisChannel = adminOnly ? ("#" + J.Name) == Config.ChatAdminChannel : Config.ChatChannels.Contains("#" + J.Name);
|
||||
if (SendToThisChannel)
|
||||
tasks.Add(J.SendMessage(msg));
|
||||
}
|
||||
foreach (var I in tasks)
|
||||
I.Wait();
|
||||
TGServerService.WriteInfo(String.Format("Discord Send{0}: {1}", adminOnly ? " (ADMIN)" : "", msg), adminOnly ? TGServerService.EventID.ChatAdminBroadcast : TGServerService.EventID.ChatBroadcast);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return e.ToString();
|
||||
var tasks = new List<Task>();
|
||||
var Config = Properties.Settings.Default;
|
||||
foreach (var I in client.Servers)
|
||||
foreach (var J in I.TextChannels)
|
||||
{
|
||||
var cid = J.Id.ToString();
|
||||
var wdc = DiscordConfig.WatchdogChannels;
|
||||
bool SendToThisChannel = (mt.HasFlag(ChatMessageType.AdminInfo) && DiscordConfig.AdminChannels.Contains(cid))
|
||||
|| (mt.HasFlag(ChatMessageType.DeveloperInfo) && DiscordConfig.DevChannels.Contains(cid))
|
||||
|| (mt.HasFlag(ChatMessageType.GameInfo) && DiscordConfig.GameChannels.Contains(cid))
|
||||
|| (mt.HasFlag(ChatMessageType.WatchdogInfo) && DiscordConfig.WatchdogChannels.Contains(cid));
|
||||
|
||||
if (SendToThisChannel)
|
||||
tasks.Add(J.SendMessage(msg));
|
||||
}
|
||||
foreach (var I in tasks)
|
||||
I.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
public string SendMessageDirect(string message, string channelname)
|
||||
{
|
||||
if (!Connected())
|
||||
return "Disconnected.";
|
||||
try
|
||||
{
|
||||
lock (DiscordLock)
|
||||
@@ -157,12 +185,6 @@ namespace TGServerService
|
||||
return e.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public void SetChannels(string[] channels = null, string adminchannel = null)
|
||||
{
|
||||
//noop
|
||||
}
|
||||
|
||||
void DisconnectAndDispose()
|
||||
{
|
||||
try
|
||||
@@ -181,10 +203,20 @@ namespace TGServerService
|
||||
{
|
||||
lock (DiscordLock)
|
||||
{
|
||||
DisconnectAndDispose();
|
||||
Init(info);
|
||||
if (Properties.Settings.Default.ChatEnabled)
|
||||
Connect();
|
||||
var odc = DiscordConfig;
|
||||
DiscordConfig = new TGDiscordSetupInfo(info);
|
||||
if (DiscordConfig.BotToken != odc.BotToken)
|
||||
{
|
||||
DisconnectAndDispose();
|
||||
Init(info);
|
||||
}
|
||||
if (DiscordConfig.Enabled)
|
||||
{
|
||||
if (!Connected())
|
||||
return Reconnect();
|
||||
}
|
||||
else
|
||||
Disconnect();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace TGServerService
|
||||
if (Proc == null)
|
||||
throw new Exception("GetProcessById returned null!");
|
||||
TGServerService.WriteInfo("Reattached to running DD process!", TGServerService.EventID.DDReattachSuccess);
|
||||
SendMessage("DD: Update complete. Watch dog reactivated...");
|
||||
SendMessage("DD: Update complete. Watch dog reactivated...", ChatMessageType.WatchdogInfo);
|
||||
|
||||
//start wd
|
||||
InitInterop();
|
||||
@@ -93,7 +93,7 @@ namespace TGServerService
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
else
|
||||
SendMessage("DD: Detaching watch dog for update!");
|
||||
SendMessage("DD: Detaching watch dog for update!", ChatMessageType.WatchdogInfo);
|
||||
}
|
||||
else if (Detach)
|
||||
{
|
||||
@@ -184,7 +184,7 @@ namespace TGServerService
|
||||
return "Restart already in progress";
|
||||
try
|
||||
{
|
||||
SendMessage("DD: Hard restart triggered");
|
||||
SendMessage("DD: Hard restart triggered", ChatMessageType.WatchdogInfo);
|
||||
RestartInProgress = true;
|
||||
Stop();
|
||||
var res = Start();
|
||||
@@ -206,7 +206,7 @@ namespace TGServerService
|
||||
{
|
||||
if (!RestartInProgress)
|
||||
{
|
||||
SendMessage("DD: Server started, watchdog active...");
|
||||
SendMessage("DD: Server started, watchdog active...", ChatMessageType.WatchdogInfo);
|
||||
TGServerService.WriteInfo("Watchdog started", TGServerService.EventID.DDWatchdogStarted);
|
||||
}
|
||||
else
|
||||
@@ -242,14 +242,14 @@ namespace TGServerService
|
||||
{
|
||||
++retries;
|
||||
var sleep_time = (int)Math.Min(Math.Pow(2, retries), 3600); //max of one hour
|
||||
SendMessage(String.Format("DD: Watchdog server startup failed! Retrying in {0} seconds...", sleep_time));
|
||||
SendMessage(String.Format("DD: Watchdog server startup failed! Retrying in {0} seconds...", sleep_time), ChatMessageType.WatchdogInfo);
|
||||
Thread.Sleep(sleep_time * 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
retries = 0;
|
||||
var msg = "DD: DreamDaemon crashed! Watchdog rebooting DD...";
|
||||
SendMessage(msg);
|
||||
SendMessage(msg, ChatMessageType.WatchdogInfo);
|
||||
TGServerService.WriteWarning(msg, TGServerService.EventID.DDWatchdogRebootingServer);
|
||||
}
|
||||
}
|
||||
@@ -280,7 +280,7 @@ namespace TGServerService
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SendMessage("DD: Watchdog thread crashed!");
|
||||
SendMessage("DD: Watchdog thread crashed!", ChatMessageType.WatchdogInfo);
|
||||
TGServerService.WriteError("Watch dog thread crashed: " + e.ToString(), TGServerService.EventID.DDWatchdogCrash);
|
||||
}
|
||||
finally
|
||||
@@ -292,7 +292,7 @@ namespace TGServerService
|
||||
AwaitingShutdown = ShutdownRequestPhase.None;
|
||||
if (!RestartInProgress)
|
||||
{
|
||||
SendMessage("DD: Server stopped, watchdog exiting...");
|
||||
SendMessage("DD: Server stopped, watchdog exiting...", ChatMessageType.WatchdogInfo);
|
||||
TGServerService.WriteInfo("Watch dog exited", TGServerService.EventID.DDWatchdogExit);
|
||||
}
|
||||
else
|
||||
|
||||
+96
-54
@@ -11,7 +11,6 @@ namespace TGServerService
|
||||
{
|
||||
const string PrivateMessageMarker = "---PRIVATE-MSG---";
|
||||
IrcFeatures irc;
|
||||
int reconnectAttempt = 0;
|
||||
|
||||
object IRCLock = new object();
|
||||
|
||||
@@ -19,15 +18,30 @@ namespace TGServerService
|
||||
|
||||
public event OnChatMessage OnChatMessage;
|
||||
|
||||
public TGChatSetupInfo ProviderInfo()
|
||||
{
|
||||
return IRCConfig;
|
||||
}
|
||||
|
||||
public TGIRCChatProvider(TGChatSetupInfo info)
|
||||
{
|
||||
IRCConfig = new TGIRCSetupInfo(info);
|
||||
irc = new IrcFeatures() { SupportNonRfc = true };
|
||||
irc = new IrcFeatures()
|
||||
{
|
||||
SupportNonRfc = true,
|
||||
CtcpUserInfo = TGServerService.Version,
|
||||
AutoRejoin = true,
|
||||
AutoRejoinOnKick = true,
|
||||
AutoRelogin = true,
|
||||
AutoRetry = true,
|
||||
AutoRetryLimit = 5,
|
||||
AutoRetryDelay = 5,
|
||||
ActiveChannelSyncing = true,
|
||||
};
|
||||
irc.OnChannelMessage += Irc_OnChannelMessage;
|
||||
irc.OnQueryMessage += Irc_OnQueryMessage;
|
||||
irc.CtcpUserInfo = TGServerService.Version;
|
||||
}
|
||||
|
||||
|
||||
//public api
|
||||
public string SendMessageDirect(string message, string channel)
|
||||
{
|
||||
@@ -55,32 +69,62 @@ namespace TGServerService
|
||||
var convertedInfo = (TGIRCSetupInfo)info;
|
||||
var serverChange = convertedInfo.URL != IRCConfig.URL || convertedInfo.Port != IRCConfig.Port;
|
||||
IRCConfig = convertedInfo;
|
||||
if (serverChange)
|
||||
if (!IRCConfig.Enabled)
|
||||
{
|
||||
Disconnect();
|
||||
return null;
|
||||
}
|
||||
else if (serverChange || !Connected())
|
||||
return Reconnect();
|
||||
else if (convertedInfo.Nickname != irc.Nickname)
|
||||
|
||||
if (IRCConfig.Nickname != irc.Nickname)
|
||||
irc.RfcNick(convertedInfo.Nickname);
|
||||
Login();
|
||||
JoinChannels();
|
||||
return null;
|
||||
}
|
||||
|
||||
public void SetChannels(string[] channels = null, string adminchannel = null)
|
||||
private bool CheckAdmin(IrcMessageData e)
|
||||
{
|
||||
lock (IRCLock) {
|
||||
var channelsList = new List<string>(channels);
|
||||
var Config = Properties.Settings.Default;
|
||||
foreach (var I in irc.JoinedChannels)
|
||||
if (!channelsList.Contains(I))
|
||||
irc.RfcPart(I);
|
||||
foreach (var I in channelsList)
|
||||
if (!irc.JoinedChannels.Contains(I))
|
||||
irc.RfcJoin(I);
|
||||
if (IRCConfig.AdminsAreSpecial)
|
||||
{
|
||||
var Chan = irc.GetChannel(e.Channel);
|
||||
var user = (NonRfcChannelUser)irc.GetChannelUser(e.Channel, e.Nick);
|
||||
if (user != null)
|
||||
switch (IRCConfig.AuthLevel)
|
||||
{
|
||||
case IRCMode.Voice:
|
||||
if (user.IsVoice)
|
||||
return true;
|
||||
goto case IRCMode.Halfop;
|
||||
case IRCMode.Halfop:
|
||||
if (user.IsHalfop)
|
||||
return true;
|
||||
goto case IRCMode.Op;
|
||||
case IRCMode.Op:
|
||||
if (user.IsOp)
|
||||
return true;
|
||||
goto case IRCMode.Owner;
|
||||
case IRCMode.Owner:
|
||||
if (user.IsOwner)
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var lowerNick = e.Nick.ToLower();
|
||||
foreach (var I in IRCConfig.AdminList)
|
||||
if (lowerNick == I.ToLower())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//private message
|
||||
private void Irc_OnQueryMessage(object sender, IrcEventArgs e)
|
||||
{
|
||||
OnChatMessage(e.Data.Nick, e.Data.Nick + PrivateMessageMarker, e.Data.Message, true);
|
||||
OnChatMessage(this, e.Data.Nick, e.Data.Nick + PrivateMessageMarker, e.Data.Message, CheckAdmin(e.Data), true);
|
||||
}
|
||||
|
||||
private void Irc_OnChannelMessage(object sender, IrcEventArgs e)
|
||||
@@ -91,20 +135,33 @@ namespace TGServerService
|
||||
var test = splits[0];
|
||||
if (test.Length > 1 && test[test.Length - 1] == ':')
|
||||
test = test.Substring(0, test.Length - 1);
|
||||
var tagged = test.ToLower() == irc.Nickname.ToLower();
|
||||
if (test.ToLower() != irc.Nickname.ToLower())
|
||||
return;
|
||||
|
||||
if (tagged)
|
||||
{
|
||||
splits.RemoveAt(0);
|
||||
formattedMessage = String.Join(" ", splits);
|
||||
}
|
||||
splits.RemoveAt(0);
|
||||
formattedMessage = String.Join(" ", splits);
|
||||
|
||||
OnChatMessage(e.Data.Nick, e.Data.Channel, formattedMessage, tagged);
|
||||
OnChatMessage(this, e.Data.Nick, e.Data.Channel, formattedMessage, CheckAdmin(e.Data), IRCConfig.AdminChannels.Contains(e.Data.Channel.ToLower()));
|
||||
}
|
||||
//Joins configured channels
|
||||
void JoinChannels()
|
||||
{
|
||||
foreach (var I in Properties.Settings.Default.ChatChannels)
|
||||
var hs = new HashSet<string>(); //for unique inserts
|
||||
foreach (var I in IRCConfig.AdminChannels)
|
||||
hs.Add(I);
|
||||
foreach (var I in IRCConfig.DevChannels)
|
||||
hs.Add(I);
|
||||
foreach (var I in IRCConfig.GameChannels)
|
||||
hs.Add(I);
|
||||
foreach (var I in IRCConfig.WatchdogChannels)
|
||||
hs.Add(I);
|
||||
var ToPart = new List<string>();
|
||||
foreach (var I in irc.JoinedChannels)
|
||||
if (!hs.Remove(I))
|
||||
ToPart.Add(I);
|
||||
foreach (var I in ToPart)
|
||||
irc.RfcPart(I);
|
||||
foreach (var I in hs)
|
||||
irc.RfcJoin(I);
|
||||
}
|
||||
//runs the login command
|
||||
@@ -119,7 +176,7 @@ namespace TGServerService
|
||||
//public api
|
||||
public string Connect()
|
||||
{
|
||||
if (Connected())
|
||||
if (Connected() || !IRCConfig.Enabled)
|
||||
return null;
|
||||
lock (IRCLock)
|
||||
{
|
||||
@@ -128,20 +185,10 @@ namespace TGServerService
|
||||
try
|
||||
{
|
||||
irc.Connect(IRCConfig.URL, IRCConfig.Port);
|
||||
reconnectAttempt = 0;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
reconnectAttempt++;
|
||||
if (reconnectAttempt <= 5)
|
||||
{
|
||||
Thread.Sleep(5000); //Reconnecting after 5 seconds.
|
||||
return Connect();
|
||||
}
|
||||
else
|
||||
{
|
||||
return "IRC server unreachable: " + e.ToString();
|
||||
}
|
||||
return "IRC server unreachable: " + e.ToString();
|
||||
}
|
||||
|
||||
try
|
||||
@@ -154,6 +201,7 @@ namespace TGServerService
|
||||
}
|
||||
Login();
|
||||
JoinChannels();
|
||||
|
||||
new Thread(new ThreadStart(IRCListen)) { IsBackground = true }.Start();
|
||||
return null;
|
||||
}
|
||||
@@ -210,27 +258,21 @@ namespace TGServerService
|
||||
}
|
||||
}
|
||||
//public api
|
||||
public string SendMessage(string message, bool adminOnly)
|
||||
public void SendMessage(string message, ChatMessageType mt)
|
||||
{
|
||||
try
|
||||
if (!Connected())
|
||||
return;
|
||||
lock (IRCLock)
|
||||
{
|
||||
if (!Connected())
|
||||
return "Disconnected.";
|
||||
lock (IRCLock)
|
||||
foreach (var cid in irc.JoinedChannels)
|
||||
{
|
||||
var Config = Properties.Settings.Default;
|
||||
if (adminOnly)
|
||||
irc.SendMessage(SendType.Message, Config.ChatAdminChannel, message);
|
||||
else
|
||||
foreach (var I in Config.ChatChannels)
|
||||
irc.SendMessage(SendType.Message, I, message);
|
||||
bool SendToThisChannel = (mt.HasFlag(ChatMessageType.AdminInfo) && IRCConfig.AdminChannels.Contains(cid))
|
||||
|| (mt.HasFlag(ChatMessageType.DeveloperInfo) && IRCConfig.DevChannels.Contains(cid))
|
||||
|| (mt.HasFlag(ChatMessageType.GameInfo) && IRCConfig.GameChannels.Contains(cid))
|
||||
|| (mt.HasFlag(ChatMessageType.WatchdogInfo) && IRCConfig.WatchdogChannels.Contains(cid));
|
||||
if (SendToThisChannel)
|
||||
irc.SendMessage(SendType.Message, cid, message);
|
||||
}
|
||||
TGServerService.WriteInfo(String.Format("IRC Send{0}: {1}", adminOnly ? " (ADMIN)" : "", message), adminOnly ? TGServerService.EventID.ChatAdminBroadcast : TGServerService.EventID.ChatBroadcast);
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return e.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,13 +45,13 @@ namespace TGServerService
|
||||
switch (cmd)
|
||||
{
|
||||
case SRIRCBroadcast:
|
||||
SendMessage("GAME: " + String.Join(" ", splits));
|
||||
SendMessage("GAME: " + String.Join(" ", splits), ChatMessageType.GameInfo);
|
||||
break;
|
||||
case SRKillProcess:
|
||||
KillMe();
|
||||
break;
|
||||
case SRIRCAdminChannelMessage:
|
||||
SendMessage("RELAY: " + String.Join(" ", splits), true);
|
||||
SendMessage("RELAY: " + String.Join(" ", splits), ChatMessageType.AdminInfo);
|
||||
break;
|
||||
case SRWorldReboot:
|
||||
TGServerService.WriteInfo("World Rebooted", TGServerService.EventID.WorldReboot);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace TGServerService
|
||||
{
|
||||
@@ -45,6 +47,24 @@ namespace TGServerService
|
||||
}
|
||||
}
|
||||
|
||||
public static string EncryptData(byte[] data, out string sentropy)
|
||||
{
|
||||
// Generate additional entropy (will be used as the Initialization vector)
|
||||
byte[] entropy = new byte[20];
|
||||
using (var rng = new RNGCryptoServiceProvider())
|
||||
rng.GetBytes(entropy);
|
||||
|
||||
byte[] ciphertext = ProtectedData.Protect(data, entropy, DataProtectionScope.CurrentUser);
|
||||
|
||||
sentropy = Convert.ToBase64String(entropy, 0, entropy.Length);
|
||||
return Convert.ToBase64String(ciphertext, 0, ciphertext.Length);
|
||||
}
|
||||
|
||||
public static byte[] DecryptData(string data, string entropy)
|
||||
{
|
||||
return ProtectedData.Unprotect(Convert.FromBase64String(data), Convert.FromBase64String(entropy), DataProtectionScope.CurrentUser);
|
||||
}
|
||||
|
||||
public static void CopyDirectory(string sourceDirName, string destDirName, IList<string> ignore = null, bool ignoreIfNotExists = false)
|
||||
{
|
||||
// If the destination directory doesn't exist, create it.
|
||||
|
||||
@@ -25,5 +25,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("3.0.85.4")]
|
||||
[assembly: AssemblyFileVersion("3.0.85.4")]
|
||||
[assembly: AssemblyVersion("3.0.86.0")]
|
||||
[assembly: AssemblyFileVersion("3.0.86.0")]
|
||||
|
||||
+13
-65
@@ -119,18 +119,6 @@ namespace TGServerService.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
public bool ChatEnabled {
|
||||
get {
|
||||
return ((bool)(this["ChatEnabled"]));
|
||||
}
|
||||
set {
|
||||
this["ChatEnabled"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("False")]
|
||||
@@ -155,18 +143,6 @@ namespace TGServerService.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("0")]
|
||||
public int ChatProvider {
|
||||
get {
|
||||
return ((int)(this["ChatProvider"]));
|
||||
}
|
||||
set {
|
||||
this["ChatProvider"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("NEEDS INITIALIZING")]
|
||||
@@ -181,47 +157,7 @@ namespace TGServerService.Properties {
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<ArrayOfString xmlns:xsi=\"http://www.w3." +
|
||||
"org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n <s" +
|
||||
"tring>theghostofwhibyl1</string>\r\n</ArrayOfString>")]
|
||||
public global::System.Collections.Specialized.StringCollection ChatAdmins {
|
||||
get {
|
||||
return ((global::System.Collections.Specialized.StringCollection)(this["ChatAdmins"]));
|
||||
}
|
||||
set {
|
||||
this["ChatAdmins"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("<?xml version=\"1.0\" encoding=\"utf-16\"?>\r\n<ArrayOfString xmlns:xsi=\"http://www.w3." +
|
||||
"org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\r\n <s" +
|
||||
"tring>#botbus</string>\r\n</ArrayOfString>")]
|
||||
public global::System.Collections.Specialized.StringCollection ChatChannels {
|
||||
get {
|
||||
return ((global::System.Collections.Specialized.StringCollection)(this["ChatChannels"]));
|
||||
}
|
||||
set {
|
||||
this["ChatChannels"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("#botbus")]
|
||||
public string ChatAdminChannel {
|
||||
get {
|
||||
return ((string)(this["ChatAdminChannel"]));
|
||||
}
|
||||
set {
|
||||
this["ChatAdminChannel"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("John Madden")]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("")]
|
||||
public string ChatProviderEntropy {
|
||||
get {
|
||||
return ((string)(this["ChatProviderEntropy"]));
|
||||
@@ -278,5 +214,17 @@ namespace TGServerService.Properties {
|
||||
this["ReattachPort"] = value;
|
||||
}
|
||||
}
|
||||
|
||||
[global::System.Configuration.UserScopedSettingAttribute()]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Configuration.DefaultSettingValueAttribute("0")]
|
||||
public int SettingsVersion {
|
||||
get {
|
||||
return ((int)(this["SettingsVersion"]));
|
||||
}
|
||||
set {
|
||||
this["SettingsVersion"] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,38 +26,17 @@
|
||||
<Setting Name="ServerVisiblity" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">2</Value>
|
||||
</Setting>
|
||||
<Setting Name="ChatEnabled" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="DDAutoStart" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">False</Value>
|
||||
</Setting>
|
||||
<Setting Name="PythonPath" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">C:\Python27</Value>
|
||||
</Setting>
|
||||
<Setting Name="ChatProvider" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="ChatProviderData" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">NEEDS INITIALIZING</Value>
|
||||
</Setting>
|
||||
<Setting Name="ChatAdmins" Type="System.Collections.Specialized.StringCollection" Scope="User">
|
||||
<Value Profile="(Default)"><?xml version="1.0" encoding="utf-16"?>
|
||||
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<string>theghostofwhibyl1</string>
|
||||
</ArrayOfString></Value>
|
||||
</Setting>
|
||||
<Setting Name="ChatChannels" Type="System.Collections.Specialized.StringCollection" Scope="User">
|
||||
<Value Profile="(Default)"><?xml version="1.0" encoding="utf-16"?>
|
||||
<ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
<string>#botbus</string>
|
||||
</ArrayOfString></Value>
|
||||
</Setting>
|
||||
<Setting Name="ChatAdminChannel" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">#botbus</Value>
|
||||
</Setting>
|
||||
<Setting Name="ChatProviderEntropy" Type="System.String" Scope="User">
|
||||
<Value Profile="(Default)">John Madden</Value>
|
||||
<Value Profile="(Default)" />
|
||||
</Setting>
|
||||
<Setting Name="UpgradeRequired" Type="System.Boolean" Scope="User">
|
||||
<Value Profile="(Default)">True</Value>
|
||||
@@ -71,5 +50,8 @@
|
||||
<Setting Name="ReattachPort" Type="System.UInt16" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
<Setting Name="SettingsVersion" Type="System.Int32" Scope="User">
|
||||
<Value Profile="(Default)">0</Value>
|
||||
</Setting>
|
||||
</Settings>
|
||||
</SettingsFile>
|
||||
@@ -113,7 +113,7 @@ namespace TGServerService
|
||||
var BranchName = ts.b;
|
||||
try
|
||||
{
|
||||
SendMessage(String.Format("REPO: {2} started: Cloning {0} branch of {1} ...", BranchName, RepoURL, Repository.IsValid(RepoPath) ? "Full reset" : "Setup"));
|
||||
SendMessage(String.Format("REPO: {2} started: Cloning {0} branch of {1} ...", BranchName, RepoURL, Repository.IsValid(RepoPath) ? "Full reset" : "Setup"), ChatMessageType.DeveloperInfo);
|
||||
try
|
||||
{
|
||||
DisposeRepo();
|
||||
@@ -161,7 +161,7 @@ namespace TGServerService
|
||||
}
|
||||
Program.CopyDirectory(RepoData, StaticDataDir, null, true);
|
||||
File.Copy(RepoPath + LibMySQLFile, StaticDirs + LibMySQLFile, true);
|
||||
SendMessage("REPO: Clone complete!");
|
||||
SendMessage("REPO: Clone complete!", ChatMessageType.DeveloperInfo);
|
||||
TGServerService.WriteInfo("Repository {0}:{1} successfully cloned", TGServerService.EventID.RepoClone);
|
||||
}
|
||||
finally
|
||||
@@ -172,7 +172,7 @@ namespace TGServerService
|
||||
catch(Exception e)
|
||||
|
||||
{
|
||||
SendMessage("REPO: Setup failed!");
|
||||
SendMessage("REPO: Setup failed!", ChatMessageType.DeveloperInfo);
|
||||
TGServerService.WriteWarning(String.Format("Failed to clone {2}:{0}: {1}", BranchName, e.ToString(), RepoURL), TGServerService.EventID.RepoCloneFail);
|
||||
}
|
||||
finally
|
||||
@@ -297,7 +297,7 @@ namespace TGServerService
|
||||
var result = LoadRepo();
|
||||
if (result != null)
|
||||
return result;
|
||||
SendMessage("REPO: Checking out object: " + sha);
|
||||
SendMessage("REPO: Checking out object: " + sha, ChatMessageType.DeveloperInfo);
|
||||
try
|
||||
{
|
||||
var Opts = new CheckoutOptions()
|
||||
@@ -307,13 +307,13 @@ namespace TGServerService
|
||||
};
|
||||
Commands.Checkout(Repo, sha, Opts);
|
||||
var res = ResetNoLock(null);
|
||||
SendMessage("REPO: Checkout complete!");
|
||||
SendMessage("REPO: Checkout complete!", ChatMessageType.DeveloperInfo);
|
||||
TGServerService.WriteInfo("Repo checked out " + sha, TGServerService.EventID.RepoCheckout);
|
||||
return res;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SendMessage("REPO: Checkout failed!");
|
||||
SendMessage("REPO: Checkout failed!", ChatMessageType.DeveloperInfo);
|
||||
TGServerService.WriteWarning(String.Format("Repo checkout of {0} failed: {1}", sha, e.ToString()), TGServerService.EventID.RepoCheckoutFail);
|
||||
return e.ToString();
|
||||
}
|
||||
@@ -333,7 +333,7 @@ namespace TGServerService
|
||||
{
|
||||
case MergeStatus.Conflicts:
|
||||
ResetNoLock(null);
|
||||
SendMessage("REPO: Merge conflicted, aborted.");
|
||||
SendMessage("REPO: Merge conflicted, aborted.", ChatMessageType.DeveloperInfo);
|
||||
return "Merge conflict occurred.";
|
||||
case MergeStatus.UpToDate:
|
||||
return RepoErrorUpToDate;
|
||||
@@ -349,7 +349,7 @@ namespace TGServerService
|
||||
var result = LoadRepo();
|
||||
if (result != null)
|
||||
return result;
|
||||
SendMessage(String.Format("REPO: Updating origin branch...({0})", reset ? "Hard Reset" : "Merge"));
|
||||
SendMessage(String.Format("REPO: Updating origin branch...({0})", reset ? "Hard Reset" : "Merge"), ChatMessageType.DeveloperInfo);
|
||||
try
|
||||
{
|
||||
if (Repo.Head == null || !Repo.Head.IsTracking)
|
||||
@@ -383,7 +383,7 @@ namespace TGServerService
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
SendMessage("REPO: Update failed!");
|
||||
SendMessage("REPO: Update failed!", ChatMessageType.DeveloperInfo);
|
||||
TGServerService.WriteWarning(String.Format("Repo{0} update failed", reset ? " hard" : ""), reset ? TGServerService.EventID.RepoHardUpdateFail : TGServerService.EventID.RepoMergeUpdateFail);
|
||||
return E.ToString();
|
||||
}
|
||||
@@ -456,7 +456,7 @@ namespace TGServerService
|
||||
var res = LoadRepo() ?? ResetNoLock(trackedBranch ? (Repo.Head.TrackedBranch ?? Repo.Head) : Repo.Head);
|
||||
if (res == null)
|
||||
{
|
||||
SendMessage(String.Format("REPO: Hard reset to {0}branch", trackedBranch ? "tracked " : ""));
|
||||
SendMessage(String.Format("REPO: Hard reset to {0}branch", trackedBranch ? "tracked " : ""), ChatMessageType.DeveloperInfo);
|
||||
if (trackedBranch)
|
||||
DeletePRList();
|
||||
TGServerService.WriteInfo(String.Format("Repo branch reset{0}", trackedBranch ? " to tracked branch" : ""), trackedBranch ? TGServerService.EventID.RepoResetTracked : TGServerService.EventID.RepoReset);
|
||||
@@ -518,7 +518,7 @@ namespace TGServerService
|
||||
var result = LoadRepo();
|
||||
if (result != null)
|
||||
return result;
|
||||
SendMessage(String.Format("REPO: {2}erging PR #{0}...", PRNumber, impliedUpdate ? "Test m" : "M"));
|
||||
SendMessage(String.Format("REPO: {2}erging PR #{0}...", PRNumber, impliedUpdate ? "Test m" : "M"), ChatMessageType.DeveloperInfo);
|
||||
try
|
||||
{
|
||||
//only supported with github
|
||||
@@ -550,7 +550,7 @@ namespace TGServerService
|
||||
branch = Repo.Branches[LocalBranchName];
|
||||
if (branch == null)
|
||||
{
|
||||
SendMessage("REPO: PR could not be fetched. Does it exist?");
|
||||
SendMessage("REPO: PR could not be fetched. Does it exist?", ChatMessageType.DeveloperInfo);
|
||||
return String.Format("PR #{0} could not be fetched. Does it exist?", PRNumber);
|
||||
}
|
||||
|
||||
@@ -600,7 +600,7 @@ namespace TGServerService
|
||||
}
|
||||
catch (Exception E)
|
||||
{
|
||||
SendMessage("REPO: PR merge failed!");
|
||||
SendMessage("REPO: PR merge failed!", ChatMessageType.DeveloperInfo);
|
||||
TGServerService.WriteWarning(String.Format("Failed to merge pull request #{0}: {1}", PRNumber, E.ToString()), TGServerService.EventID.RepoPRMergeFail);
|
||||
return E.ToString();
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace TGServerService
|
||||
DDWatchdogStarted = 2500,
|
||||
ChatSend = 2600,
|
||||
ChatBroadcast = 2700,
|
||||
ChatAdminBroadcast = 2800,
|
||||
//ChatAdminBroadcast = 2800,
|
||||
ChatDisconnectFail = 2900,
|
||||
TopicSent = 3000,
|
||||
TopicFailed = 3100,
|
||||
@@ -73,6 +73,8 @@ namespace TGServerService
|
||||
ServiceShutdownFail = 6100,
|
||||
WorldReboot = 6200,
|
||||
ServerUpdateApplied = 6300,
|
||||
ChatBroadcastFail = 6400,
|
||||
IRCLogModes = 6500,
|
||||
}
|
||||
|
||||
static TGServerService ActiveService; //So everyone else can write to our eventlog
|
||||
@@ -92,7 +94,13 @@ namespace TGServerService
|
||||
ActiveService.EventLog.WriteEntry(message, EventLogEntryType.Warning, (int)id);
|
||||
}
|
||||
|
||||
ServiceHost host; //the WCF host
|
||||
ServiceHost host; //the WCF host
|
||||
|
||||
void MigrateSettings(int oldVersion, int newVersion)
|
||||
{
|
||||
if (oldVersion == newVersion && newVersion == 0) //chat refactor
|
||||
Properties.Settings.Default.ChatProviderData = "NEEDS INITIALIZING"; //reset chat settings to be safe
|
||||
}
|
||||
|
||||
//you should seriously not add anything here
|
||||
//Use OnStart instead
|
||||
@@ -102,7 +110,12 @@ namespace TGServerService
|
||||
{
|
||||
if (Properties.Settings.Default.UpgradeRequired)
|
||||
{
|
||||
var newVersion = Properties.Settings.Default.SettingsVersion;
|
||||
Properties.Settings.Default.Upgrade();
|
||||
var oldVersion = Properties.Settings.Default.SettingsVersion;
|
||||
|
||||
MigrateSettings(oldVersion, newVersion);
|
||||
|
||||
Properties.Settings.Default.UpgradeRequired = false;
|
||||
Properties.Settings.Default.Save();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
|
||||
<Product Id="*" Name="TG Station Server" Language="1033" Version="3.0.85.4" Manufacturer="/tg/station 13" UpgradeCode="663badae-ddca-4aa9-8f3f-3b7b20332eac">
|
||||
<Product Id="*" Name="TG Station Server" Language="1033" Version="3.0.86.0" Manufacturer="/tg/station 13" UpgradeCode="663badae-ddca-4aa9-8f3f-3b7b20332eac">
|
||||
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
|
||||
|
||||
<MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
|
||||
|
||||
+234
-106
@@ -2,13 +2,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using System.ServiceModel;
|
||||
using System.Web.Script.Serialization;
|
||||
|
||||
namespace TGServiceInterface
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of chat provider
|
||||
/// </summary>
|
||||
public enum TGChatProvider
|
||||
public enum TGChatProvider : int
|
||||
{
|
||||
/// <summary>
|
||||
/// IRC chat provider
|
||||
@@ -17,7 +18,30 @@ namespace TGServiceInterface
|
||||
/// <summary>
|
||||
/// Discord chat provider
|
||||
/// </summary>
|
||||
Discord,
|
||||
Discord = 1,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supported irc permission modes
|
||||
/// </summary>
|
||||
public enum IRCMode : int
|
||||
{
|
||||
/// <summary>
|
||||
/// +
|
||||
/// </summary>
|
||||
Voice,
|
||||
/// <summary>
|
||||
/// %
|
||||
/// </summary>
|
||||
Halfop,
|
||||
/// <summary>
|
||||
/// @
|
||||
/// </summary>
|
||||
Op,
|
||||
/// <summary>
|
||||
/// ~
|
||||
/// </summary>
|
||||
Owner,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -28,6 +52,16 @@ namespace TGServiceInterface
|
||||
[KnownType(typeof(TGDiscordSetupInfo))]
|
||||
public class TGChatSetupInfo
|
||||
{
|
||||
const int AdminListIndex = 0;
|
||||
const int AdminModeIndex = 1;
|
||||
const int AdminChannelIndex = 2;
|
||||
const int DevChannelIndex = 3;
|
||||
const int WDChannelIndex = 4;
|
||||
const int GameChannelIndex = 5;
|
||||
const int ProviderIndex = 6;
|
||||
const int EnabledIndex = 7;
|
||||
protected const int BaseIndex = 8;
|
||||
protected readonly bool InitializeFields;
|
||||
/// <summary>
|
||||
/// Constructs a TGChatSetupInfo from optional past data
|
||||
/// </summary>
|
||||
@@ -35,10 +69,56 @@ namespace TGServiceInterface
|
||||
/// <param name="numFields">The number of fields in this chat provider</param>
|
||||
protected TGChatSetupInfo(TGChatSetupInfo baseInfo, int numFields)
|
||||
{
|
||||
DataFields = baseInfo != null ? baseInfo.DataFields : new List<string>(numFields);
|
||||
if (baseInfo == null)
|
||||
numFields += BaseIndex;
|
||||
InitializeFields = baseInfo == null || baseInfo.DataFields.Count != numFields;
|
||||
|
||||
if (InitializeFields)
|
||||
{
|
||||
DataFields = new List<string>(numFields);
|
||||
for (var I = 0; I < numFields; ++I)
|
||||
DataFields.Add(null);
|
||||
|
||||
AdminList = new List<string>();
|
||||
AdminChannels = new List<string>();
|
||||
DevChannels = new List<string>();
|
||||
GameChannels = new List<string>();
|
||||
WatchdogChannels = new List<string>();
|
||||
AdminsAreSpecial = false;
|
||||
Enabled = false;
|
||||
}
|
||||
else
|
||||
DataFields = baseInfo.DataFields;
|
||||
}
|
||||
|
||||
TGChatSetupInfo Specialize()
|
||||
{
|
||||
switch (Provider)
|
||||
{
|
||||
case TGChatProvider.IRC:
|
||||
return new TGIRCSetupInfo(this);
|
||||
case TGChatProvider.Discord:
|
||||
return new TGDiscordSetupInfo(this);
|
||||
default:
|
||||
throw new Exception("Invalid provider!");
|
||||
}
|
||||
}
|
||||
|
||||
//trims and adds the leading #
|
||||
protected virtual string SanitizeChannelName(string working)
|
||||
{
|
||||
return Specialize().SanitizeChannelName(working);
|
||||
}
|
||||
void SanitizeChannelNames(IList<string> working)
|
||||
{
|
||||
for (var I = 0; I < working.Count; ++I)
|
||||
|
||||
if (String.IsNullOrWhiteSpace(working[I]))
|
||||
{
|
||||
working.RemoveAt(I);
|
||||
--I;
|
||||
}
|
||||
else
|
||||
working[I] = SanitizeChannelName(working[I].Trim());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -46,17 +126,91 @@ namespace TGServiceInterface
|
||||
/// </summary>
|
||||
/// <param name="DeserializedData">The data</param>
|
||||
/// <param name="provider">The chat provider</param>
|
||||
public TGChatSetupInfo(IList<string> DeserializedData, TGChatProvider provider)
|
||||
public TGChatSetupInfo(IList<string> DeserializedData)
|
||||
{
|
||||
DataFields = DeserializedData;
|
||||
Provider = provider;
|
||||
}
|
||||
/// <summary>
|
||||
/// The list of admin entries
|
||||
/// </summary>
|
||||
public IList<string> AdminList
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[AdminListIndex]); }
|
||||
set { DataFields[AdminListIndex] = new JavaScriptSerializer().Serialize(value); }
|
||||
}
|
||||
/// <summary>
|
||||
/// If AdminList corresponds to a Provider specific recognization method
|
||||
/// </summary>
|
||||
public bool AdminsAreSpecial
|
||||
{
|
||||
get { return Convert.ToBoolean(DataFields[AdminModeIndex]); }
|
||||
set { DataFields[AdminModeIndex] = Convert.ToString(value); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The channels from which admin commands/messages can be sent/received
|
||||
/// </summary>
|
||||
public IList<string> AdminChannels
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[AdminChannelIndex]); }
|
||||
set
|
||||
{
|
||||
SanitizeChannelNames(value);
|
||||
DataFields[AdminChannelIndex] = new JavaScriptSerializer().Serialize(value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The channels to which repo and compile messages are sent
|
||||
/// </summary>
|
||||
public IList<string> DevChannels
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[DevChannelIndex]); }
|
||||
set
|
||||
{
|
||||
SanitizeChannelNames(value);
|
||||
DataFields[DevChannelIndex] = new JavaScriptSerializer().Serialize(value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The channels to which watchdog messages are sent
|
||||
/// </summary>
|
||||
public IList<string> WatchdogChannels
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[WDChannelIndex]); }
|
||||
set
|
||||
{
|
||||
SanitizeChannelNames(value);
|
||||
DataFields[WDChannelIndex] = new JavaScriptSerializer().Serialize(value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The channels to which game messages are sent
|
||||
/// </summary>
|
||||
public IList<string> GameChannels
|
||||
{
|
||||
get { return new JavaScriptSerializer().Deserialize<IList<string>>(DataFields[GameChannelIndex]); }
|
||||
set
|
||||
{
|
||||
SanitizeChannelNames(value);
|
||||
DataFields[GameChannelIndex] = new JavaScriptSerializer().Serialize(value);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// If this chat provider is enabled
|
||||
/// </summary>
|
||||
public bool Enabled
|
||||
{
|
||||
get { return Convert.ToBoolean(DataFields[EnabledIndex]); }
|
||||
set { DataFields[EnabledIndex] = Convert.ToString(value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type of provider
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public TGChatProvider Provider { get; protected set; }
|
||||
public TGChatProvider Provider
|
||||
{
|
||||
get { return (TGChatProvider)Convert.ToInt32(DataFields[ProviderIndex]); }
|
||||
set { DataFields[ProviderIndex] = Convert.ToString((int)value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raw access to the underlying data
|
||||
@@ -67,6 +221,7 @@ namespace TGServiceInterface
|
||||
|
||||
/// <summary>
|
||||
/// Chat provider for IRC
|
||||
/// Admin entries should be user nicknames in normal mode or required flags in special mode
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public class TGIRCSetupInfo : TGChatSetupInfo
|
||||
@@ -76,7 +231,8 @@ namespace TGServiceInterface
|
||||
const int NickIndex = 2;
|
||||
const int AuthTargetIndex = 3;
|
||||
const int AuthMessageIndex = 4;
|
||||
const int FieldsLen = 5;
|
||||
const int AuthLevelIndex = 5;
|
||||
const int FieldsLen = 6;
|
||||
|
||||
/// <summary>
|
||||
/// Construct IRC setup info from optional generic info. Defaults to TGS3 on rizons IRC server
|
||||
@@ -85,54 +241,78 @@ namespace TGServiceInterface
|
||||
public TGIRCSetupInfo(TGChatSetupInfo baseInfo = null) : base(baseInfo, FieldsLen)
|
||||
{
|
||||
Provider = TGChatProvider.IRC;
|
||||
if (baseInfo == null)
|
||||
if (InitializeFields)
|
||||
{
|
||||
Nickname = "TGS3";
|
||||
URL = "irc.rizon.net";
|
||||
Port = 6667;
|
||||
AuthTarget = "";
|
||||
AuthMessage = "";
|
||||
AdminsAreSpecial = true;
|
||||
AuthLevel = IRCMode.Op;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string SanitizeChannelName(string working)
|
||||
{
|
||||
if (working[0] != '#')
|
||||
return "#" + working;
|
||||
return working;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The port of the IRC server
|
||||
/// </summary>
|
||||
public ushort Port {
|
||||
get { return Convert.ToUInt16(DataFields[PortIndex]); }
|
||||
set { DataFields[PortIndex] = value.ToString(); }
|
||||
get { return Convert.ToUInt16(DataFields[BaseIndex + PortIndex]); }
|
||||
set { DataFields[BaseIndex + PortIndex] = value.ToString(); }
|
||||
}
|
||||
/// <summary>
|
||||
/// The URL of the IRC server
|
||||
/// </summary>
|
||||
public string URL
|
||||
{
|
||||
get { return DataFields[URLIndex]; }
|
||||
set { DataFields[URLIndex] = value; }
|
||||
get { return DataFields[BaseIndex + URLIndex]; }
|
||||
set { DataFields[BaseIndex + URLIndex] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The nickname of the IRC bot
|
||||
/// </summary>
|
||||
public string Nickname
|
||||
{
|
||||
get { return DataFields[NickIndex]; }
|
||||
set { DataFields[NickIndex] = value; }
|
||||
get { return DataFields[BaseIndex + NickIndex]; }
|
||||
set { DataFields[BaseIndex + NickIndex] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The target for sending authentication messages
|
||||
/// </summary>
|
||||
public string AuthTarget
|
||||
{
|
||||
get { return DataFields[AuthTargetIndex]; }
|
||||
set { DataFields[AuthTargetIndex] = value; }
|
||||
get { return DataFields[BaseIndex + AuthTargetIndex]; }
|
||||
set { DataFields[BaseIndex + AuthTargetIndex] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The authentication message
|
||||
/// </summary>
|
||||
public string AuthMessage
|
||||
{
|
||||
get { return DataFields[AuthMessageIndex]; }
|
||||
set { DataFields[AuthMessageIndex] = value; }
|
||||
get { return DataFields[BaseIndex + AuthMessageIndex]; }
|
||||
set { DataFields[BaseIndex + AuthMessageIndex] = value; }
|
||||
}
|
||||
/// <summary>
|
||||
/// The minimum mode required to use admin bot commands when in special auth mode
|
||||
/// </summary>
|
||||
public IRCMode AuthLevel
|
||||
{
|
||||
get { return (IRCMode)Convert.ToInt32(DataFields[BaseIndex + AuthLevelIndex]); }
|
||||
set { DataFields[BaseIndex + AuthLevelIndex] = Convert.ToString((int)value); }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Chat provider for Discord
|
||||
/// Admin entires should be user ids in normal mode or group ids in special mode
|
||||
/// </summary>
|
||||
[DataContract]
|
||||
public class TGDiscordSetupInfo : TGChatSetupInfo
|
||||
{
|
||||
@@ -145,8 +325,20 @@ namespace TGServiceInterface
|
||||
public TGDiscordSetupInfo(TGChatSetupInfo baseInfo = null) : base(baseInfo, FieldsLen)
|
||||
{
|
||||
Provider = TGChatProvider.Discord;
|
||||
if (baseInfo == null)
|
||||
BotToken = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
||||
if (InitializeFields)
|
||||
BotToken = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; //needless to say, this is fake
|
||||
}
|
||||
protected override string SanitizeChannelName(string working)
|
||||
{
|
||||
try
|
||||
{
|
||||
Convert.ToUInt64(working);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new Exception("Invalid Discord channel ID!");
|
||||
}
|
||||
return working;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -154,109 +346,45 @@ namespace TGServiceInterface
|
||||
/// </summary>
|
||||
public string BotToken
|
||||
{
|
||||
get { return DataFields[BotTokenIndex]; }
|
||||
set { DataFields[BotTokenIndex] = value; }
|
||||
get { return DataFields[BaseIndex + BotTokenIndex]; }
|
||||
set { DataFields[BaseIndex + BotTokenIndex] = value; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used internally
|
||||
/// </summary>
|
||||
[ServiceContract]
|
||||
public interface ITGChatBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Set the chat provider info
|
||||
/// </summary>
|
||||
/// <param name="info"></param>
|
||||
[OperationContract]
|
||||
string SetProviderInfo(TGChatSetupInfo info);
|
||||
|
||||
/// <summary>
|
||||
/// Set the channels to join
|
||||
/// </summary>
|
||||
/// <param name="channels">The names of the channels to join and broadcast to</param>
|
||||
/// <param name="adminchannel">The name of the channel which accepts admin commands. Need not be in the channels parameter</param>
|
||||
[OperationContract]
|
||||
void SetChannels(string[] channels = null, string adminchannel = null);
|
||||
|
||||
/// <summary>
|
||||
/// Checks connection status
|
||||
/// </summary>
|
||||
/// <returns>true if connected, false otherwise</returns>
|
||||
[OperationContract]
|
||||
bool Connected();
|
||||
|
||||
/// <summary>
|
||||
/// Reconnect to the chat service
|
||||
/// </summary>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
[OperationContract]
|
||||
string Reconnect();
|
||||
|
||||
/// <summary>
|
||||
/// Send a message to the chat service
|
||||
/// </summary>
|
||||
/// <param name="msg">The message to send</param>
|
||||
/// <param name="adminOnly">true if the message should only be sent to the admin channel, false otherwise</param>
|
||||
/// <returns></returns>
|
||||
[OperationContract]
|
||||
string SendMessage(string msg, bool adminOnly = false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Interface for handling chat bot
|
||||
/// </summary>
|
||||
[ServiceContract]
|
||||
public interface ITGChat : ITGChatBase
|
||||
public interface ITGChat
|
||||
{
|
||||
/// <summary>
|
||||
/// Set the chat provider info
|
||||
/// </summary>
|
||||
/// <param name="info">The info to set</param>
|
||||
[OperationContract]
|
||||
string SetProviderInfo(TGChatSetupInfo info);
|
||||
/// <summary>
|
||||
/// Returns the chat provider info
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <param name="providerType">The type of provider to get info for</param>
|
||||
/// <returns>The chat provider info for the selected provider</returns>
|
||||
[OperationContract]
|
||||
TGChatSetupInfo ProviderInfo();
|
||||
/// <summary>
|
||||
/// Get channels we are set to connect to, includes the admin channel
|
||||
/// </summary>
|
||||
/// <returns>An array of channels</returns>
|
||||
[OperationContract]
|
||||
string[] Channels();
|
||||
IList<TGChatSetupInfo> ProviderInfos();
|
||||
|
||||
/// <summary>
|
||||
/// Get the channel from which secure commands can be sent
|
||||
/// Checks connection status
|
||||
/// </summary>
|
||||
/// <returns>The name of the channel</returns>
|
||||
/// <param name="providerType">The type of provider to check if connected</param>
|
||||
/// <returns>true if connected, false otherwise</returns>
|
||||
[OperationContract]
|
||||
string AdminChannel();
|
||||
bool Connected(TGChatProvider providerType);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the configuration allows the IRC bot
|
||||
/// Reconnect to the chat service
|
||||
/// </summary>
|
||||
/// <returns>true if the bot is enabled, false otherwise</returns>
|
||||
/// <param name="providerType">The type of provider to reconnect</param>
|
||||
/// <returns>null on success, error message on failure</returns>
|
||||
[OperationContract]
|
||||
bool Enabled();
|
||||
|
||||
/// <summary>
|
||||
/// Enable or disable the chat provider
|
||||
/// </summary>
|
||||
/// <param name="enable">true to enable, false to disable</param>
|
||||
/// <returns>null on success, connection error message on failure</returns>
|
||||
[OperationContract]
|
||||
string SetEnabled(bool enable);
|
||||
|
||||
/// <summary>
|
||||
/// Print out the users who can use admin restricted commands over IRC from the admin channel
|
||||
/// </summary>
|
||||
/// <returns>A list of irc nicknames</returns>
|
||||
[OperationContract]
|
||||
string[] ListAdmins();
|
||||
|
||||
/// <summary>
|
||||
/// Set the users who can use admin restricted commands over IRC from the admin channel
|
||||
/// </summary>
|
||||
/// <param name="nicknames">The list of irc admin nicknames</param>
|
||||
[OperationContract]
|
||||
void SetAdmins(string[] nicknames);
|
||||
string Reconnect(TGChatProvider providerType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,5 +25,5 @@ using System.Runtime.InteropServices;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("3.0.85.4")]
|
||||
[assembly: AssemblyFileVersion("3.0.85.4")]
|
||||
[assembly: AssemblyVersion("3.0.86.0")]
|
||||
[assembly: AssemblyFileVersion("3.0.86.0")]
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="System.Runtime.Serialization" />
|
||||
<Reference Include="System.ServiceModel" />
|
||||
<Reference Include="System.Web.Extensions" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Byond.cs" />
|
||||
|
||||
Reference in New Issue
Block a user