关于30HB服务器激活码的实现

前言:

私服的运营并不被官方认可,因此应该保持低调。然而,有些人为了谋取利益,不顾一切地公开贩卖私服,这种行为虽然这些私服可能会带来短暂的高人气,但长期来看,它们加速了服务器的关闭,对游戏的稳定性和持久性造成了负面影响。而且对于玩家来说,本来是免费的东西,却被收取了高额的费用,这无疑是对玩家利益和游戏体验的损害。我们应当持批判态度并加强打击力度,避免玩家陷入利益陷阱和风险损失之中。

我们也想了很多办法,踢也踢了,骂也骂了,但效果甚微。倒卖依旧我行我素,你骂他坏,他笑你蠢,你拿他没办法。

这些方法可以说是亡羊补牢,治标不治本,无法从根本上解决问题。所以得从源头上寻找解决办法。

这篇文章通过激活码的方式,尝试限制倒卖行为的发展。通过为每个玩家提供独特的激活码,能够追踪和管理玩家的账号行为,确保私服资源的正规使用和限制倒卖行为的传播。这种方法能够从源头上遏制问题,为游戏的稳定性和持久性提供保障。

正文:

怎么启用激活码?

在命令类(HB_CheatMessage)内的账号找回命令(/findacc),可以看到该命令把AccountRetrieving设置为true了。然后报错后重进后就来的了输入解锁码界面。很明显,这个界面就是我们需要的。

既然是登陆后弹出的,我们来的登陆认证类(Authentication)。可以找到

if (this.player_level.Avatar.AccountRetrieving)
{
	new Authentication_Failed(this.Device)
	{
		ErrorCode = 13
	}.Send();
	return;
}

很明显,这个代码就是我们需要的,启用激活码功能。

怎么改激活码功能?

首先我们先确定我们需要什么功能:

1、新号需要输入激活码才能通过验证

2、老号无需激活码直接通过验证。

3、保留找回账号功能

下面是我的代码:

using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq;
using UCS.Core;
using UCS.Core.Network;
using UCS.Helpers;
using UCS.Helpers.Binary;
using UCS.Logic;
using UCS.Logic.Enums;
using UCS.Packets.Messages.Server;
using UCS.Utilities.Sodium;

namespace UCS.Packets.Messages.Client
{
	// Token: 0x020000D9 RID: 217
	internal class UnlockAccountMessage : Message
	{
		// Token: 0x06000457 RID: 1111 RVA: 0x000308C0 File Offset: 0x0002EAC0
		public UnlockAccountMessage(Device device, Reader reader) : base(device, reader)
		{
			try
			{
				this.Device.PlayerState = State.LOGGED;
			}
			catch (Exception ex)
			{
				Console.WriteLine("在设置玩家状态时出现错误: " + ex.Message);
			}
		}

		// Token: 0x06000458 RID: 1112 RVA: 0x0003090C File Offset: 0x0002EB0C
		internal override void Decrypt()
		{
			try
			{
				this.Device.Keys.SNonce.Increment(2);
				byte[] array = Sodium.Decrypt(new byte[16].Concat(this.Reader.ReadBytes(this.Length)).ToArray<byte>(), this.Device.Keys.SNonce, this.Device.Keys.PublicKey);
				if (array != null)
				{
					this.Reader = new Reader(array);
					this.Length = (int)this.Reader.BaseStream.Length;
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine("解密消息时出现错误: " + ex.Message);
			}
		}

		// Token: 0x06000459 RID: 1113 RVA: 0x000309C8 File Offset: 0x0002EBC8
		internal override void Decode()
		{
			try
			{
				this.UserID = this.Reader.ReadInt64();
				this.UserToken = this.Reader.ReadString();
				this.UnlockCode = this.Reader.ReadString();
			}
			catch (Exception ex)
			{
				Console.WriteLine("解码消息时出现错误: " + ex.Message);
			}
		}

		// Token: 0x0600045A RID: 1114 RVA: 0x00030A34 File Offset: 0x0002EC34
		internal override void Process()
		{
			if (this.UserID > 0L && !(this.UserToken == string.Empty) && this.UserID <= ObjectManager.m_vAvatarSeed && ResourcesManager.GetPlayer(this.UserID, "testtesttoken").Avatar.AccountRetrieving)
			{
				Logger.WriteDebug(string.Format("UserID: {0}", this.UserID));
				Logger.WriteDebug("UserToken: " + this.UserToken);
				Logger.WriteDebug("UnlockCode: " + this.UnlockCode);
				Console.WriteLine(this.UserID + "正在找回账号");
				Console.WriteLine("UserToken: " + this.UserToken);
				Console.WriteLine("UnlockCode: " + this.UnlockCode);
				long userID = this.UserID;
				long accountRetrieving_PlayerID = ResourcesManager.GetPlayer(this.UserID, "testtesttoken").Avatar.AccountRetrieving_PlayerID;
				Level player = ResourcesManager.GetPlayer(accountRetrieving_PlayerID, "testtesttoken");
				if (ResourcesManager.IsPlayerOnline(accountRetrieving_PlayerID))
				{
					new UnlockAccountFailedMessage(this.Device)
					{
						ErrorCode = 1
					}.Send();
				}
				else
				{
					string text = player.Avatar.LastUserToken.Substring(0, 12);
					Console.WriteLine(accountRetrieving_PlayerID + "的token: " + text);
					while (text.Length < 12)
					{
						text += "A";
					}
					if (this.UnlockCode.Equals(text))
					{
						new UnlockAccountOkMessage(this.Device)
						{
							UserID = accountRetrieving_PlayerID,
							UserToken = player.Avatar.LastUserToken
						}.Send();
						Console.WriteLine(this.UserID + "成功找回账号");
						return;
					}
					new UnlockAccountFailedMessage(this.Device)
					{
						ErrorCode = 1
					}.Send();
					Console.WriteLine(this.UserID + "输入的Token不正确");
				}
				ResourcesManager.ModifyPlayer(userID, "testtesttoken", delegate(Level p)
				{
					p.Avatar.AccountRetrieving_PlayerID = 0L;
					p.Avatar.AccountRetrieving = false;
				});
				Console.WriteLine("已为" + this.UserID + "恢复原本id");
				return;
			}
			bool flag = Regex.IsMatch(this.UnlockCode, "^[a-zA-Z]+$");
			if (flag)
			{
				JArray unlockCodeArray = this.GetUnlockCodeArray(this.UnlockCode);
				if (this.IsUnlockCodeInArray(unlockCodeArray))
				{
					goto IL_3BF;
				}
			}
			else
			{
				if (Regex.IsMatch(this.UnlockCode, "^[0-9]+$"))
				{
					JArray jarray = this.GetUnlockCode2Array();
					if (this.IsUnlockCodeInArray(jarray))
					{
						jarray = new JArray(from code in jarray
						where code.ToString().ToLower() != this.UnlockCode
						select code);
						Random random = new Random();
						string value = new string((from s in Enumerable.Repeat<string>("0123456789", 12)
						select s[random.Next(s.Length)]).ToArray<char>());
						jarray.Add(value);
						this.SaveUnlockCode2Array(jarray);
						goto IL_3BF;
					}
				}
				bool flag2 = false;
				JArray adminUnlockCodeArray = this.GetAdminUnlockCodeArray();
				foreach (JToken jtoken in adminUnlockCodeArray)
				{
					JObject jobject = (JObject)jtoken;
					string value2 = jobject["unlockcode"].ToString();
					if (this.UnlockCode.Equals(value2))
					{
						int num = (int)jobject["count"];
						if (num > 0)
						{
							jobject["count"] = num - 1;
							this.SaveAdminUnlockCodeArray(adminUnlockCodeArray);
							flag2 = true;
							break;
						}
					}
				}
				if (flag2)
				{
					goto IL_3BF;
				}
			}
			new UnlockAccountFailedMessage(this.Device)
			{
				ErrorCode = 1
			}.Send();
			return;
			IL_3BF:
			try
			{
				JArray jarray2;
				if (this.UserID <= 0L || this.UserToken == string.Empty || this.UserID > ObjectManager.m_vAvatarSeed)
				{
					if (flag)
					{
						jarray2 = this.GetUnlockCodeArray(this.UnlockCode);
						jarray2 = new JArray(from t in jarray2
						where t.ToString().ToLower() != this.UnlockCode.ToLower()
						select t);
						this.SaveUnlockCodeArray(this.UnlockCode, jarray2);
					}
					this.NewUser();
					jarray2 = this.GetUnlockCodeArray(this.UserToken);
					jarray2.Add(this.UserToken.Substring(0, 12));
					this.SaveUnlockCodeArray(this.UserToken, jarray2);
					new UnlockAccountOkMessage(this.Device)
					{
						UserID = this.UserID,
						UserToken = this.UserToken
					}.Send();
					return;
				}
				jarray2 = this.GetUnlockCodeArray(this.UserToken);
				jarray2.Add(this.UserToken.Substring(0, 12));
				this.SaveUnlockCodeArray(this.UserToken, jarray2);
				new UnlockAccountOkMessage(this.Device)
				{
					UserID = this.UserID,
					UserToken = this.UserToken
				}.Send();
				return;
			}
			catch (Exception ex)
			{
				Console.WriteLine("处理消息时出现错误: " + ex.Message);
			}
			new UnlockAccountFailedMessage(this.Device)
			{
				ErrorCode = 1
			}.Send();
		}

		// Token: 0x0600045B RID: 1115 RVA: 0x00030F94 File Offset: 0x0002F194
		private void NewUser()
		{
			try
			{
				File.Copy("Gamefiles/starting_pp.json", string.Format("Saves/pp/{0}.json", ObjectManager.m_vAvatarSeed + 1L));
				this.player_level = ObjectManager.CreateAvatar;
				this.player_level.Avatar.UserID = ObjectManager.m_vAvatarSeed;
				this.player_level.Avatar.AvatarName = string.Format("海洋军阀-{0}", this.player_level.Avatar.UserID);
				if (string.IsNullOrEmpty(this.UserToken))
				{
					for (int i = 0; i < 12; i++)
					{
						char c = (char)Resources.Random.Next(65, 90);
						ClientAvatar avatar = this.player_level.Avatar;
						avatar.UserToken += c.ToString();
					}
				}
				this.player_level.Avatar.Password = this.player_level.Avatar.UserToken;
				this.player_level.Avatar.AccountRetrieving_UnlockCode = true;
				this.player_level.Avatar.InitializeAccountCreationDate();
				this.UserID = this.player_level.Avatar.UserID;
				this.UserToken = this.player_level.Avatar.UserToken;
				File.WriteAllText(string.Format("Saves/pp/{0}.json", this.player_level.Avatar.UserID), this.player_level.Avatar.SaveTOJSONHBVer);
			}
			catch (Exception ex)
			{
				Console.WriteLine("创建新用户时出现错误: " + ex.Message);
			}
		}

		// Token: 0x0600045C RID: 1116 RVA: 0x00031134 File Offset: 0x0002F334
		private bool IsUnlockCodeInArray(JArray qqArray)
		{
			bool result;
			try
			{
				if (qqArray != null)
				{
					string lowerCaseUnlockCode = this.UnlockCode.ToLower();
					result = qqArray.Any((JToken t) => t.ToString().ToLower() == lowerCaseUnlockCode);
				}
				else
				{
					result = false;
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine("检查解锁码是否在数组中时出现错误: " + ex.Message);
				result = false;
			}
			return result;
		}

		// Token: 0x0600045D RID: 1117 RVA: 0x000311A0 File Offset: 0x0002F3A0
		private JArray GetUnlockCode2Array()
		{
			JArray result;
			try
			{
				result = (JArray)JObject.Parse(File.ReadAllText("Config/UnlockCode2.json"))["UnlockCode"];
			}
			catch (Exception ex)
			{
				Console.WriteLine("读取 UnlockCode2.json 文件时出现错误: " + ex.Message);
				result = new JArray();
			}
			return result;
		}

		// Token: 0x0600045E RID: 1118 RVA: 0x00031200 File Offset: 0x0002F400
		private void SaveUnlockCode2Array(JArray jarray)
		{
			try
			{
				JObject jobject = new JObject();
				jobject["UnlockCode"] = jarray;
				File.WriteAllText("Config/UnlockCode2.json", jobject.ToString());
			}
			catch (Exception ex)
			{
				Console.WriteLine("保存 UnlockCode2.json 文件时出现错误: " + ex.Message);
			}
		}

		// Token: 0x0600045F RID: 1119 RVA: 0x0003125C File Offset: 0x0002F45C
		private JArray GetAdminUnlockCodeArray()
		{
			JArray result;
			try
			{
				result = (JArray)JObject.Parse(File.ReadAllText("Config/IsAdminUnlockCode.json"))["UnlockCode"];
			}
			catch (Exception ex)
			{
				Console.WriteLine("读取 IsAdminUnlockCode.json 文件时出现错误: " + ex.Message);
				result = new JArray();
			}
			return result;
		}

		// Token: 0x06000460 RID: 1120 RVA: 0x000312BC File Offset: 0x0002F4BC
		private void SaveAdminUnlockCodeArray(JArray jarray)
		{
			try
			{
				JObject jobject = new JObject();
				jobject["UnlockCode"] = jarray;
				File.WriteAllText("Config/IsAdminUnlockCode.json", jobject.ToString());
			}
			catch (Exception ex)
			{
				Console.WriteLine("保存 IsAdminUnlockCode.json 文件时出现错误: " + ex.Message);
			}
		}

		// Token: 0x06000463 RID: 1123 RVA: 0x00031318 File Offset: 0x0002F518
		private JArray GetUnlockCodeArray(string UnlockCode)
		{
			JArray result;
			try
			{
				if (!string.IsNullOrEmpty(UnlockCode))
				{
					char c = char.ToLower(UnlockCode[0]);
					string path = string.Format("Config/UnlockCode/{0}.json", c);
					if (!File.Exists(path))
					{
						Directory.CreateDirectory(Path.GetDirectoryName(path));
						File.WriteAllText(path, "{\"UnlockCode\": []}");
					}
					result = (JArray)JObject.Parse(File.ReadAllText(path))["UnlockCode"];
				}
				else
				{
					result = null;
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine("读取 UnlockCode 对应字母文件时出现错误: " + ex.Message);
				result = null;
			}
			return result;
		}

		// Token: 0x06000464 RID: 1124 RVA: 0x000313B8 File Offset: 0x0002F5B8
		private void SaveUnlockCodeArray(string UnlockCode, JArray jarray)
		{
			try
			{
				if (!string.IsNullOrEmpty(UnlockCode))
				{
					char c = char.ToLower(UnlockCode[0]);
					string path = string.Format("Config/UnlockCode/{0}.json", c);
					JObject jobject = new JObject();
					jobject["UnlockCode"] = jarray;
					File.WriteAllText(path, jobject.ToString());
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine("保存 UnlockCode 对应字母文件时出现错误: " + ex.Message);
			}
		}

		// Token: 0x04000416 RID: 1046
		internal long UserID;

		// Token: 0x04000417 RID: 1047
		internal string UserToken;

		// Token: 0x04000418 RID: 1048
		internal string UnlockCode;

		// Token: 0x04000419 RID: 1049
		public Level player_level;
	}
}

我把创建新号功能,移植到了这里。为的是记录当前账号的UserID和UserToken。不然就需要先创建账号,再启用激活码。这样会创建大量无意义的玩家存档,造成资源浪费。

怎么登陆验证?

既然激活码有了,怎么识别哪些号需要使用激活码,哪些号不要使用激活码?

下面是我的登陆认证代码

using System;
using System.IO;
using System.Linq;
using System.Net;
using Newtonsoft.Json.Linq;
using UCS.Core;
using UCS.Core.Crypto;
using UCS.Core.Network;
using UCS.Core.Settings;
using UCS.Helpers.Binary;
using UCS.Helpers.List;
using UCS.Logic;
using UCS.Logic.Enums;
using UCS.Logic.Manager;
using UCS.Packets.Messages.Server;
using UCS.Utilities.Blake2B;
using UCS.Utilities.Sodium;

namespace UCS.Packets.Messages.Client
{
	// Token: 0x020000D6 RID: 214
	internal class Authentication : Message
	{
		// Token: 0x06000447 RID: 1095 RVA: 0x00006835 File Offset: 0x00004A35
		public Authentication(Device device, Reader reader) : base(device, reader)
		{
			this.Device.PlayerState = State.LOGIN;
		}

		// Token: 0x06000448 RID: 1096 RVA: 0x0002FB04 File Offset: 0x0002DD04
		internal override void Decrypt()
		{
			byte[] array = this.Reader.ReadBytes(this.Length);
			this.Device.Keys.PublicKey = array.Take(32).ToArray<byte>();
			Logger.WriteDebug("Device.Keys.PublicKey: " + this.Device.Keys.PublicKey.ToList<byte>().BytesToHexa());
			Blake2BHasher blake2BHasher = new Blake2BHasher();
			blake2BHasher.Update(this.Device.Keys.PublicKey);
			blake2BHasher.Update(Key.PublicKey);
			this.Device.Keys.RNonce = blake2BHasher.Finish();
			array = Sodium.Decrypt(array.Skip(32).ToArray<byte>(), this.Device.Keys.RNonce, Key.PrivateKey, this.Device.Keys.PublicKey);
			this.Device.Keys.SNonce = array.Skip(24).Take(24).ToArray<byte>();
			Logger.WriteDebug("decrypted Buffer 前24字节: " + array.Take(24).ToList<byte>().BytesToHexa());
			Logger.WriteDebug("decrypted Buffer 全部内容: " + array.ToList<byte>().BytesToHexa());
			Logger.WriteDebug("Device.Keys.SNonce: " + this.Device.Keys.SNonce.ToList<byte>().BytesToHexa());
			this.Reader = new Reader(array.Skip(48).ToArray<byte>());
			Logger.WriteDebug("LoginMessage Data: " + array.Skip(48).ToList<byte>().BytesToHexa());
			this.Length = array.Length;
		}

		// Token: 0x06000449 RID: 1097 RVA: 0x0002FCA8 File Offset: 0x0002DEA8
		internal override void Decode()
		{
			this.UserID = this.Reader.ReadInt64();
			this.UserToken = this.Reader.ReadString();
			this.MajorVersion = this.Reader.ReadInt32();
			this.ContentVersion = this.Reader.ReadInt32();
			this.MinorVersion = this.Reader.ReadInt32();
			this.MasterHash = this.Reader.ReadString();
			this.UDID = this.Reader.ReadString();
			this.OpenUDID = this.Reader.ReadString();
			this.DeviceModel = this.Reader.ReadString();
			this.Reader.ReadString();
			this.Region = this.Reader.ReadString();
			this.AdvertisingGUID = this.Reader.ReadString();
			this.OSVersion = this.Reader.ReadString();
			this.Reader.ReadString();
			Logger.WriteDebug("=== Authentication 10101 ===");
			Logger.WriteDebug(string.Format("UserID -> {0}", this.UserID));
			Logger.WriteDebug("UserToken -> " + this.UserToken);
			Logger.WriteDebug(string.Format("MajorVersion -> {0}", this.MajorVersion));
			Logger.WriteDebug(string.Format("ContentVersion -> {0}", this.ContentVersion));
			Logger.WriteDebug(string.Format("MinorVersion -> {0}", this.MinorVersion));
			Logger.WriteDebug("MasterHash -> " + this.MasterHash);
			Logger.WriteDebug("UDID -> " + this.UDID);
			Logger.WriteDebug("OpenUDID -> " + this.OpenUDID);
			Logger.WriteDebug("DeviceModel -> " + this.DeviceModel);
			Logger.WriteDebug("Region -> " + this.Region);
			Logger.WriteDebug("AdvertisingGUID -> " + this.AdvertisingGUID);
			Logger.WriteDebug("OSVersion -> " + this.OSVersion);
			Logger.WriteDebug("=== Authentication END ===");
		}

		// Token: 0x0600044A RID: 1098 RVA: 0x0002FEC0 File Offset: 0x0002E0C0
		internal override void Process()
		{
			if (Settings.MaintenanceTimeLeft != 0)
			{
				long num = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
				if ((long)Settings.MaintenanceTimeLeft > num)
				{
					new Authentication_Failed(this.Device)
					{
						ErrorCode = 10,
						RemainingTime = (int)((long)Settings.MaintenanceTimeLeft - num)
					}.Send();
				}
			}
			if (Settings.ClientVersion != string.Format("{0}.{1}", this.MajorVersion, this.MinorVersion))
			{
				new Authentication_Failed(this.Device)
				{
					ErrorCode = 8,
					UpdateURL = Settings.UpdateURL
				}.Send();
				return;
			}
			if (!Settings.UsePatch && !this.MasterHash.Equals(Settings.CurrentSha))
			{
				new Authentication_Failed(this.Device)
				{
					ErrorCode = 8,
					UpdateURL = Settings.UpdateURL
				}.Send();
				return;
			}
			if (Settings.UsePatch && !this.MasterHash.Equals(Settings.PatchSha))
			{
				string text = new WebClient().DownloadString(Settings.PatchURL + "/" + Settings.PatchSha + "/fingerprint.json");
				Logger.Write("Patching client...");
				Logger.WriteDebug("PatchURL: " + Settings.PatchURL);
				Logger.WriteDebug("PatchSha: " + Settings.PatchSha);
				Logger.WriteDebug("PatchFingerprint: " + text);
				new Authentication_Failed(this.Device)
				{
					ErrorCode = 7,
					ContentUrl = Settings.PatchURL,
					ResourceFingerprintData = text
				}.Send();
				return;
			}
			Logger.WriteDebug("checking client...");
			this.LogUser();
		}

		// Token: 0x0600044B RID: 1099 RVA: 0x0003005C File Offset: 0x0002E25C
		private void LogUser()
		{
			if (this.UserID <= 0L || this.UserToken == string.Empty || this.UserID > ObjectManager.m_vAvatarSeed)
			{
				new Authentication_Failed(this.Device)
				{
					ErrorCode = 13
				}.Send();
				return;
			}
			this.player_level = new Level(this.UserID, this.UserToken);
			Logger.WriteDebug("Log in,not register!");
			if (this.player_level != null)
			{
				if (this.UserID > 0L)
				{
					this.player_level.Avatar.UserID = this.UserID;
					Logger.WriteDebug("玩家的UserID设为Authentication的UserID");
				}
				this.player_level.Tick();
				this.player_level.Avatar.IPAddress = this.Device.IPAddress;
				Logger.WriteDebug("Player IPAddress: " + this.player_level.Avatar.IPAddress);
				if (this.player_level.Avatar.AccountBanned)
				{
					if (this.player_level.Avatar.AccountBanTime == 0L)
					{
						new Authentication_Failed(this.Device)
						{
							ErrorCode = 11,
							Reason = "因为不合适的玩家行为,您的账号现已被永久封禁!" + ((this.player_level.Avatar.AccountBanReason.Length > 0) ? ("\n理由:" + this.player_level.Avatar.AccountBanReason) : "")
						}.Send();
						return;
					}
					long localTimeStamp = TimeManager.getLocalTimeStamp();
					long accountBanTime = this.player_level.Avatar.AccountBanTime;
					long num = accountBanTime - localTimeStamp;
					int[] timeInterval = TimeManager.getTimeInterval(num);
					if (num >= 0L)
					{
						new Authentication_Failed(this.Device)
						{
							ErrorCode = 11,
							Reason = string.Format("因为不合适的玩家行为,您的账号现已被封禁!\n当前时间:{0}\n解封时间:{1}\n距离解封还有 {2} 天 {3} 小时 {4} 分钟 {5} 秒{6}", new object[]
							{
								TimeManager.getDateTimeByTimeStamp(localTimeStamp),
								TimeManager.getDateTimeByTimeStamp(accountBanTime),
								timeInterval[0],
								timeInterval[1],
								timeInterval[2],
								timeInterval[3],
								(this.player_level.Avatar.AccountBanReason.Length > 0) ? ("\n理由:" + this.player_level.Avatar.AccountBanReason) : ""
							})
						}.Send();
						return;
					}
					this.player_level.Avatar.UnbanPlayer();
				}
				else
				{
					if (this.player_level.Avatar.AccountRetrieving)
					{
						new Authentication_Failed(this.Device)
						{
							ErrorCode = 13
						}.Send();
						return;
					}
					char c = char.ToLower(this.UserToken[0]);
					string path = string.Format("Config/UnlockCode/{0}.json", c);
					if (!File.Exists(path))
					{
						Directory.CreateDirectory(Path.GetDirectoryName(path));
						File.WriteAllText(path, "{\"UnlockCode\": []}");
					}
					this._JObjectUnlockCode = JObject.Parse(File.ReadAllText(path));
					JArray jarray = (JArray)this._JObjectUnlockCode["UnlockCode"];
					if (!this.player_level.Avatar.AccountRetrieving_UnlockCode)
					{
						jarray.Add(this.UserToken.Substring(0, 12));
						this._JObjectUnlockCode["UnlockCode"] = jarray;
						File.WriteAllText(path, this._JObjectUnlockCode.ToString());
						this.player_level.Avatar.AccountRetrieving_UnlockCode = true;
					}
					else if (!this.IsUnlockCodeInArray(jarray, this.UserToken.Substring(0, 12)) && this.player_level.Avatar.AccountRetrieving_UnlockCode)
					{
						new Authentication_Failed(this.Device)
						{
							ErrorCode = 13
						}.Send();
						return;
					}
					if (!this.player_level.Avatar.LastUserToken.Equals("missing LastUserToken") && !this.player_level.Avatar.LastUserToken.Equals(this.UserToken))
					{
						new Authentication_Failed(this.Device)
						{
							ErrorCode = 11,
							Reason = "UserToken错误。你的Token(" + this.UserToken + ")与服务器记录上一次的Token不一致。"
						}.Send();
						return;
					}
					if (ResourcesManager.IsPlayerOnline(this.player_level.Avatar.UserID))
					{
						new ForceDisconnectMessage(ResourcesManager.m_vInMemoryLevels[this.player_level.Avatar.UserID].Client);
						try
						{
							ResourcesManager.LogPlayerOut(ResourcesManager.m_vInMemoryLevels[this.player_level.Avatar.UserID]);
						}
						catch (Exception arg)
						{
							Logger.Write(string.Format("因为异常{0},无法ResourcesManager.LogPlayerOut该玩家,也许已经登出了吧。", arg));
						}
						Logger.Write(string.Format("玩家 {0} 在其他设备登录,原设备自动登出。", this.player_level.Avatar.UserID));
					}
				}
				ResourcesManager.LogPlayerIn(this.player_level, this.Device);
				Logger.WriteDebug("Successfully log in!");
				Logger.Write(string.Format("玩家 {0} ({1}) 加入了游戏。", this.player_level.Avatar.UserID, this.player_level.Client.IPAddress));
				this.Device.Player.Avatar.PlayerStatisticsAddOne("game_join");
				this.Device.Player.Avatar.LastIPAddress = this.Device.IPAddress;
				this.Device.Player.Avatar.LastUserToken = this.UserToken;
				new Authentication_OK(this.Device)
				{
					ServerMajorVersion = this.MajorVersion,
					ServerBuild = this.MinorVersion,
					ContentVersion = this.ContentVersion
				}.Send();
				this.Device.Player.homeBaseManager.jsonObject = this.Device.CheckArtifact(this.Device.Player.homeBaseManager.jsonObject);
				new OwnHomeDataMessage(this.Device).Send();
				new AllianceStreamMessage(this.Device).Send();
				new MegabaseEventInfoMessage(this.Device)
				{
					CurrentStage = this.Device.Player.Avatar.MegacrabCurrentStage
				}.Send();
				new IntelMessage(this.Device)
				{
					IntelCount = 250,
					IntelCapacity = 1000
				}.Send();
				new CoopMissionDataMessage(this.Device).Send();
				if (File.Exists("Config/notice.txt"))
				{
					string text = File.ReadAllText("Config/notice.txt");
					text += string.Format("\n下面是你的账号信息,请不要轻易告知他人\n你的玩家ID:{0}\n你的密码:使用“/me”查看(默认为Token)\n你的Token:{1}\n请截图保存你的信息。\n复制存档:/saves <id> <密码>\n找回账号:/findacc <id>", new object[]
					{
						this.Device.Player.Avatar.UserID,
						this.Device.Player.Avatar.UserToken
					});
					this.Device.SendCommandFeedback(text);
				}
				return;
			}
			new Authentication_Failed(this.Device)
			{
				ErrorCode = 114514,
				Reason = "请删除应用数据后重试。"
			}.Send();
		}

		// Token: 0x0600044C RID: 1100 RVA: 0x00030740 File Offset: 0x0002E940
		private void NewUser()
		{
			Logger.WriteDebug(string.Format("Authentication.NewUser ({0})", ObjectManager.m_vAvatarSeed));
			File.Copy("Gamefiles/starting_pp.json", string.Format("Saves/pp/{0}.json", ObjectManager.m_vAvatarSeed + 1L));
			this.player_level = ObjectManager.CreateAvatar;
			this.player_level.Avatar.UserID = ObjectManager.m_vAvatarSeed;
			this.player_level.Avatar.AvatarName = string.Format("海洋军阀-{0}", this.player_level.Avatar.UserID);
			if (string.IsNullOrEmpty(this.UserToken))
			{
				for (int i = 0; i < 12; i++)
				{
					char c = (char)Resources.Random.Next(65, 90);
					ClientAvatar avatar = this.player_level.Avatar;
					avatar.UserToken += c.ToString();
				}
			}
			this.player_level.Avatar.Password = this.player_level.Avatar.UserToken;
			Logger.WriteDebug(string.Format("New Player Created! PlayerID: {0}   UserToken: {1}", this.player_level.Avatar.UserID, this.player_level.Avatar.UserToken));
			this.player_level.Avatar.InitializeAccountCreationDate();
		}

		// Token: 0x0600044D RID: 1101 RVA: 0x00030888 File Offset: 0x0002EA88
		private bool IsUnlockCodeInArray(JArray qqArray, string usertoken)
		{
			if (qqArray != null)
			{
				string lowerCaseUnlockCode = usertoken.ToLower();
				return qqArray.Any((JToken t) => t.ToString().ToLower() == lowerCaseUnlockCode);
			}
			return false;
		}

		// Token: 0x040003FB RID: 1019
		public string AdvertisingGUID;

		// Token: 0x040003FC RID: 1020
		public bool Android;

		// Token: 0x040003FD RID: 1021
		public string AndroidDeviceID;

		// Token: 0x040003FE RID: 1022
		public int ContentVersion;

		// Token: 0x040003FF RID: 1023
		public string DeviceModel;

		// Token: 0x04000400 RID: 1024
		public string FacebookDistributionID;

		// Token: 0x04000401 RID: 1025
		public bool IsAdvertisingTrackingEnabled;

		// Token: 0x04000402 RID: 1026
		public Level player_level;

		// Token: 0x04000403 RID: 1027
		public int LocaleKey;

		// Token: 0x04000404 RID: 1028
		public string MacAddress;

		// Token: 0x04000405 RID: 1029
		public int MajorVersion;

		// Token: 0x04000406 RID: 1030
		public string MasterHash;

		// Token: 0x04000407 RID: 1031
		public int MinorVersion;

		// Token: 0x04000408 RID: 1032
		public string OpenUDID;

		// Token: 0x04000409 RID: 1033
		public string OSVersion;

		// Token: 0x0400040A RID: 1034
		public string Region;

		// Token: 0x0400040B RID: 1035
		public uint Seed;

		// Token: 0x0400040C RID: 1036
		public string UDID;

		// Token: 0x0400040D RID: 1037
		public long UserID;

		// Token: 0x0400040E RID: 1038
		public string UserToken;

		// Token: 0x0400040F RID: 1039
		public string VendorGUID;

		// Token: 0x04000410 RID: 1040
		public string PatchFingerprint;

		// Token: 0x04000411 RID: 1041
		private JObject _JObjectUnlockCode;

		// Token: 0x020000D7 RID: 215
		public class AccountInfo
		{
			// Token: 0x1700006E RID: 110
			// (get) Token: 0x0600044E RID: 1102 RVA: 0x0000684B File Offset: 0x00004A4B
			// (set) Token: 0x0600044F RID: 1103 RVA: 0x00006853 File Offset: 0x00004A53
			public bool AccountBanned { get; set; }

			// Token: 0x1700006F RID: 111
			// (get) Token: 0x06000450 RID: 1104 RVA: 0x0000685C File Offset: 0x00004A5C
			// (set) Token: 0x06000451 RID: 1105 RVA: 0x00006864 File Offset: 0x00004A64
			public long AccountBanTime { get; set; }

			// Token: 0x17000070 RID: 112
			// (get) Token: 0x06000452 RID: 1106 RVA: 0x0000686D File Offset: 0x00004A6D
			// (set) Token: 0x06000453 RID: 1107 RVA: 0x00006875 File Offset: 0x00004A75
			public string AccountBanReason { get; set; }
		}
	}
}

可以看到,新号必定要激活码。

老号通过这个代码记录token和更改身份信息

下面这个代码用于检验账号,避免一码多用。如果有人用了他的token创建了账号,那么会被这代码封禁这个账号。


关于30HB服务器激活码的实现
http://localhost:8090/archives/guan-yu-30hbfu-wu-qi-ji-huo-ma-de-shi-xian
作者
Administrator
发布于
2025年04月05日
许可协议