diff --git a/AutoRegister/AutoRegister.csproj b/AutoRegister/AutoRegister.csproj
index 4b7609e..4915f80 100644
--- a/AutoRegister/AutoRegister.csproj
+++ b/AutoRegister/AutoRegister.csproj
@@ -40,7 +40,7 @@
bin\Debug\BCrypt.Net.dll
- ..\lib\OTAPI.dll
+ bin\Debug\OTAPI.dll
@@ -50,10 +50,10 @@
- ..\lib\TerrariaServer.exe
+ bin\Debug\TerrariaServer.exe
- ..\lib\TShockAPI.dll
+ bin\Debug\TShockAPI.dll
diff --git a/AutoRegister/Plugin.cs b/AutoRegister/Plugin.cs
index 09dbde1..753eb68 100644
--- a/AutoRegister/Plugin.cs
+++ b/AutoRegister/Plugin.cs
@@ -1,15 +1,12 @@
using System;
using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.CompilerServices;
using Terraria;
-using Terraria.Localization;
using TerrariaApi.Server;
using TShockAPI;
using TShockAPI.DB;
-using TShockAPI.Hooks;
-using static TShockAPI.GetDataHandlers;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.Xna.Framework;
namespace AutoRegister
{
@@ -19,6 +16,7 @@ namespace AutoRegister
[ApiVersion(2, 1)]
public class Plugin : TerrariaPlugin
{
+ #region Plugin Info
///
/// The name of the plugin.
///
@@ -27,18 +25,21 @@ public class Plugin : TerrariaPlugin
///
/// The version of the plugin in its current state.
///
- public override Version Version => new Version(1, 0, 1);
+ public override Version Version => System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
///
/// The author(s) of the plugin.
///
- public override string Author => "brian91292";
+ public override string Author => "brian91292 & moisterrific";
///
/// A short, one-line, description of the plugin's purpose.
///
- public override string Description => "A Tshock plugin to automatically register a new server-side character if one doesn't already exist for a user.";
+ public override string Description => "A TShock plugin to automatically register a user account for new players.";
+ #endregion
+
+ #region Hooks and stuff
///
/// The plugin's constructor
/// Set your plugin's order (optional) and any other constructor logic here
@@ -47,14 +48,6 @@ public Plugin(Main game) : base(game)
{
}
-
- public static void Log(string msg,
- [CallerMemberName] string member = "",
- [CallerLineNumber] int line = 0)
- {
- Console.WriteLine($"AutoRegister::{member}({line}): {msg}");
- }
-
///
/// Performs plugin initialization logic.
/// Add your hooks, config file read/writes, etc here
@@ -64,25 +57,53 @@ public override void Initialize()
ServerApi.Hooks.ServerJoin.Register(this, OnServerJoin);
ServerApi.Hooks.NetGreetPlayer.Register(this, OnGreetPlayer, 420);
}
+ #endregion
+
+ private readonly Dictionary tmpPasswords = new Dictionary();
+
+ private static readonly string result = GenerateRandomAlphanumericString();
- private Dictionary tmpPasswords = new Dictionary();
///
/// Tell the player their password if the account was newly generated
///
///
- void OnGreetPlayer(GreetPlayerEventArgs args)
+ async void OnGreetPlayer(GreetPlayerEventArgs args)
{
+ var tsConfig = TShock.Config.Settings;
var player = TShock.Players[args.Who];
-
- if (tmpPasswords.TryGetValue(player.Name + player.UUID + player.IP, out string newPass))
- {
+ string cmd = TShock.Config.Settings.CommandSpecifier;
+ string red = TShockAPI.Utils.RedHighlight;
+ string green = TShockAPI.Utils.GreenHighlight;
+ string blue = TShockAPI.Utils.BoldHighlight;
+
+ if (tsConfig.DisableUUIDLogin && !tsConfig.DisableLoginBeforeJoin)
+ return;
+
+ // Need to put a slight delay otherwise the player might miss these important messages
+ // Because the messages always come before TShock MOTD
+ await Task.Delay(1000);
+ if (tmpPasswords.TryGetValue(result, out string password))
+ {
try
{
- player.SendSuccessMessage($"New server-side character created successfully! Your password is \"{newPass}\".");
- player.SendSuccessMessage($"Contact an admin if you lose access to this account, or forget your password.");
+ player.SendMessage($"Your account \"{player.Name.Color(blue)}\" has been auto-registered.", Color.White);
+ player.SendMessage($"Your randomly generated password is {password.Color(green)}", Color.White);
+ if (TShock.Config.Settings.DisableUUIDLogin)
+ player.SendMessage($"Please sign in using {cmd}login {password.Color(green)}", Color.White);
+ player.SendMessage($"You can change this at any time by using {cmd}password {password.Color(green)} \"{"new password".Color(red)}\"", Color.White);
}
- catch { }
- tmpPasswords.Remove(player.Name + player.UUID + player.IP);
+ catch
+ {
+ player.SendErrorMessage("Failed to retrieve your randomly generated password, please contact your server administrator.");
+ TShock.Log.ConsoleError("AutoRegister returned an error.");
+ }
+ tmpPasswords.Remove(result);
+ }
+ else if (!player.IsLoggedIn)
+ {
+ player.SendErrorMessage($"Your account \"{player.Name}\" could not be auto-registered!");
+ player.SendErrorMessage("This name has already been registered by another player.");
+ player.SendErrorMessage("Please try again using a different name.");
}
}
@@ -92,32 +113,67 @@ void OnGreetPlayer(GreetPlayerEventArgs args)
///
void OnServerJoin(JoinEventArgs args)
{
- if (TShock.ServerSideCharacterConfig.Enabled)
+ var tsConfig = TShock.Config.Settings;
+
+ // Problem: if DisableUUIDLogin = true AND DisableLoginBeforeJoin = false
+ // The player will be greeted with a screen asking for their account password before they can enter the server
+ // so they won't ever see their randomly generated password in the chat
+ // bruh
+ if (tsConfig.DisableUUIDLogin && !tsConfig.DisableLoginBeforeJoin)
+ {
+ TShock.Log.ConsoleError("AutoRegister will not work when DisableUUIDLogin is true AND DisableLoginBeforeJoin is false!");
+ return;
+ }
+
+ // Whether this plugin should be disabled if the server doesn't require login is up for debate
+ // but for now I'll leave it like this
+ if (!tsConfig.RequireLogin)
+ {
+ TShock.Log.ConsoleError("AutoRegister will not work when RequireLogin is set to false via config!");
+ return;
+ }
+
+ if (tsConfig.RequireLogin || Main.ServerSideCharacter)
{
var player = TShock.Players[args.Who];
- // Get the user using a combo of their UUID/name, as this is what's required for uuid login to function it seems
- var users = TShock.Users.GetUsers().Where(u => u.UUID == player.UUID && u.Name == player.Name);
- if (users.Count() == 0)
+ if (TShock.UserAccounts.GetUserAccountByName(player.Name) == null && player.Name != TSServerPlayer.AccountName)
{
- Log($"Creating new user for {player.Name}...");
-
- // If the user didn't exist, generate a password for them then create a new user based on their uuid/username
- tmpPasswords[player.Name + player.UUID + player.IP] = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Substring(0, 10);
- TShock.Users.AddUser(new User(
+ tmpPasswords[result] =
+ Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Substring(0, 10).Replace('l', 'L')
+ .Replace('1', '7').Replace('I', 'i').Replace('O', 'o').Replace('0', 'o');
+ TShock.UserAccounts.AddUserAccount(new UserAccount(
player.Name,
- BCrypt.Net.BCrypt.HashPassword(tmpPasswords[player.Name + player.UUID + player.IP].Trim()),
+ BCrypt.Net.BCrypt.HashPassword(tmpPasswords[result].Trim(), tsConfig.BCryptWorkFactor),
player.UUID,
- TShock.Config.DefaultRegistrationGroupName,
+ tsConfig.DefaultRegistrationGroupName,
DateTime.UtcNow.ToString("s"),
DateTime.UtcNow.ToString("s"),
""));
- Log("Success!");
+ TShock.Log.ConsoleInfo($"Auto-registered an account for \"{player.Name}\" ({player.IP})");
}
+ else
+ TShock.Log.ConsoleInfo($"Unable to auto-register \"{player.Name}\" ({player.IP}) because an account with this name already exists.");
}
}
+ // To-Do: switch to using a cryptographically secure pseudorandom number instead of this
+ ///
+ /// Generates a random alphanumeric string.
+ ///
+ /// The desired length of the string
+ /// The string which has been generated
+ public static string GenerateRandomAlphanumericString(int length = 10)
+ {
+ const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+
+ var random = new Random();
+ var randomString = new string(Enumerable.Repeat(chars, length)
+ .Select(s => s[random.Next(s.Length)]).ToArray());
+ return randomString;
+ }
+
///
/// Performs plugin cleanup logic
/// Remove your hooks and perform general cleanup here
diff --git a/AutoRegister/Properties/AssemblyInfo.cs b/AutoRegister/Properties/AssemblyInfo.cs
index a5f62b7..73b5ca9 100644
--- a/AutoRegister/Properties/AssemblyInfo.cs
+++ b/AutoRegister/Properties/AssemblyInfo.cs
@@ -8,9 +8,9 @@
[assembly: AssemblyTitle("AutoRegister")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("brian91292")]
+[assembly: AssemblyCompany("brian91292 & moisterrific")]
[assembly: AssemblyProduct("AutoRegister")]
-[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -32,5 +32,5 @@
// 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("1.0.1.0")]
-[assembly: AssemblyFileVersion("1.0.1.0")]
+[assembly: AssemblyVersion("1.3.2.0")]
+[assembly: AssemblyFileVersion("1.3.2.0")]
diff --git a/AutoRegister/references/BCrypt.Net.dll b/AutoRegister/references/BCrypt.Net.dll
new file mode 100644
index 0000000..c0eed4a
Binary files /dev/null and b/AutoRegister/references/BCrypt.Net.dll differ
diff --git a/AutoRegister/references/OTAPI.dll b/AutoRegister/references/OTAPI.dll
new file mode 100644
index 0000000..275526d
Binary files /dev/null and b/AutoRegister/references/OTAPI.dll differ
diff --git a/AutoRegister/references/TShockAPI.dll b/AutoRegister/references/TShockAPI.dll
new file mode 100644
index 0000000..d632637
Binary files /dev/null and b/AutoRegister/references/TShockAPI.dll differ
diff --git a/AutoRegister/references/TerrariaServer.exe b/AutoRegister/references/TerrariaServer.exe
new file mode 100644
index 0000000..233d9cc
Binary files /dev/null and b/AutoRegister/references/TerrariaServer.exe differ
diff --git a/README.md b/README.md
index 769db6e..3e0b76a 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,22 @@
-# Mod Info
-AutoRegister is a TShock plugin created to automatically register new users on SSC enabled servers.
+# Plugin Info
+AutoRegister is a plugin created to automatically register new players on TShock servers requiring login.
-# How it works
-When a new user joins a server AutoRegister checks to see if there is already a user present with their name/uuid. If there isn't, a new user is automatically created for them. The password which is generated is then posted in chat for them to either save, or change.
\ No newline at end of file
+## Overview
+### How it works
+When a new user joins a server, AutoRegister checks to see if there is an existing user with their name/UUID in the database. If there isn't, a new user account is automatically created for the new player. The randomly generated password is then posted in the chat for them to save or change.
+
+### Features
+- Enables seamless onboarding of new players on login required servers. No more players getting confused and bombarding the host with "Why am I stoned/frozen/webbed/stuck?" questions.
+- Automatically register a new account with a randomly generated password if an account by the player's name does not exist in the database.
+- Users will be notified in the chat of their newly AutoRegistered account and randomly generated password, which they can change later.
+- If an account by the same name as the new player already exist in the database, he/she will be notified in the chat to try a different username.
+- Automatic registration success or failure is present in the same way as TShock for improved clarity and cohesion.
+- Writes to server console and logs if a new user was successfully registered.
+- Compatible with PC TShock 4.5.3
+
+## Installation Guide
+1. Copy and paste AutoRegister.dll into your ServerPlugins folder. That's it.
+2. If the server is running, restart it. Otherwise start the server.
+
+## Source
+[AutoRegister](https://tshock.co/xf/index.php?resources/autoregister.234/)