添加项目文件。

This commit is contained in:
1415ddfer 2024-03-07 21:04:59 +08:00
parent 7e1e6c3353
commit 9aa059996c
74 changed files with 3168 additions and 0 deletions

0
1.1 Normal file
View File

29
AboutDialog/About1.xaml Normal file
View File

@ -0,0 +1,29 @@
<Window x:Class="Zerolauncher.AboutDialog.About1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="About" Height="384" Width="700">
<Grid>
<Image Source="/res/about1.png" Stretch="Fill"/>
<DockPanel>
<TextBlock Text="关&#13;于" Margin="20" FontSize="50" Foreground="OrangeRed"/>
<StackPanel>
<TextBlock x:Name="info" Text=" 铃依登陆器&#13;&#13;The best luancher&#13; Power by DDF" Margin="30,150,30,30" HorizontalAlignment="Center" Foreground="#2e4e7e" FontSize="16"/>
<TextBlock Text="Context For Me" HorizontalAlignment="Center" Foreground="#FF81EB78"/>
<TextBlock HorizontalAlignment="Center">
<Hyperlink NavigateUri="https://github.com/1415ddfer/ZeroHelper" Click="Hyperlink_Click">
My GitHub
</Hyperlink>
</TextBlock>
<TextBlock HorizontalAlignment="Center">
<Hyperlink NavigateUri="http://www.example.com" Click="Hyperlink_Click_1">
ddfgame@foxmail.com
</Hyperlink>
</TextBlock>
</StackPanel>
<Label/>
</DockPanel>
</Grid>
</Window>

View File

@ -0,0 +1,28 @@
using System.Diagnostics;
using System.Windows;
using System.Windows.Documents;
namespace Zerolauncher.AboutDialog
{
/// <summary>
/// About1.xaml 的交互逻辑
/// </summary>
public partial class About1 : Window
{
public About1()
{
InitializeComponent();
}
private void Hyperlink_Click(object sender, RoutedEventArgs e)
{
Process.Start(new ProcessStartInfo("http://github.com/1415ddfer/ZeroHelper") { UseShellExecute = true });
}
private void Hyperlink_Click_1(object sender, RoutedEventArgs e)
{
MessageBox.Show("已拷贝到粘贴板", "提示");
Clipboard.SetDataObject("ddfgame@foxmail.com", true);
}
}
}

9
App.xaml Normal file
View File

@ -0,0 +1,9 @@
<Application x:Class="Zerolauncher.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Zerolauncher"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

25
App.xaml.cs Normal file
View File

@ -0,0 +1,25 @@
using Lierda.WPFHelper;
using System.Windows;
using Zerolauncher.Manager;
namespace Zerolauncher
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
LierdaCracker cracker = new LierdaCracker();
protected override void OnStartup(StartupEventArgs e)
{
cracker.Cracker(100);//垃圾回收间隔时间
base.OnStartup(e);
_ = UpDateManager.TakeQMessage();
DataStream.Load();
_ = WebApiManager.StartListener();
AccountManager.initLoadData();
}
}
}

View File

@ -0,0 +1,35 @@

using System.Text;
namespace Zerolauncher.Defender
{
class EngineCacheSha
{
const string key = "mysecretkey";
static string? sha;
public static int errorCode = 0;
public static void Put(string eSha)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < eSha.Length; i++)
{
sb.Append((char)(eSha[i] ^ key[i % key.Length]));
}
sha = sb.ToString();
}
public static string? Get()
{
if (sha == null) { return null; }
var sb = new StringBuilder();
for (int i = 0; i < sha.Length; i++)
{
sb.Append((char)(sha[i] ^ key[i % key.Length]));
}
return sb.ToString();
}
}
}

38
MainWindow.xaml Normal file
View File

@ -0,0 +1,38 @@
<Window x:Class="Zerolauncher.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:MyNamespace="clr-namespace:Zerolauncher.controls"
AllowsTransparency="True" WindowStyle="None" Background="Transparent"
Title="零蛋登陆器" Height="300" Width="500" MouseLeftButtonDown="Window_MouseLeftButtonDown">
<Grid>
<!-- 使用透明背景的PNG图片作为窗口的背景 -->
<Image Source="/res/1.png" Stretch="Fill"/>
<DockPanel Margin="5,2,5,3">
<DockPanel DockPanel.Dock="Top">
<DockPanel.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="controls/AirButton.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</DockPanel.Resources>
<MyNamespace:AirButton Background="Transparent" Height="21" Width="30" Click="Button_Click_3" DockPanel.Dock="Right" BorderBrush="Transparent" Style="{StaticResource ChangeButtonIsMouseOver}">
<Image Source="/res/btn_close1.png"/>
</MyNamespace:AirButton>
<MyNamespace:AirButton Background="Transparent" Height="21" Width="30" DockPanel.Dock="Right" BorderBrush="Transparent" Style="{StaticResource ChangeButtonIsMouseOver}">
<Image Source="/res/btn_mini1.png"/>
</MyNamespace:AirButton>
<MyNamespace:AirButton Background="Transparent" Height="20" Width="30" BorderBrush="Transparent" Style="{StaticResource ChangeButtonIsMouseOver}" Margin="5,0,0,0" Click="AirButton_Click">
<Image Source="/res/config.png"/>
</MyNamespace:AirButton>
<Label/>
</DockPanel>
<ScrollViewer x:Name="memberBG" VerticalScrollBarVisibility="Auto" Margin="10,3,10,10">
<WrapPanel Name="mLayout">
</WrapPanel>
</ScrollViewer>
</DockPanel>
</Grid>
</Window>

158
MainWindow.xaml.cs Normal file
View File

@ -0,0 +1,158 @@
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Zerolauncher.AboutDialog;
using Zerolauncher.controls;
using Zerolauncher.dialog;
using Zerolauncher.Manager;
namespace Zerolauncher
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public static MainWindow Instance { get; private set; }
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//实现窗口的拖动
DragMove();
}
public MainWindow()
{
InitializeComponent();
Instance = this;
memberBG.ContextMenu = CreateContextMenu();
int i = 0;
foreach (var account in AccountManager.accountsList)
{
var member = new MemberControl();
member.memberId = i++;
member.text.Content = ServicesStaticInfo.ServicesShortName[account.providerId] + "-" + account.nickName;
mLayout.Children.Add(member);
}
}
public void ReloadBtn()
{
//foreach (var btn in mLayout.Children.)
mLayout.Children.Clear();
int i = 0;
foreach (var account in AccountManager.accountsList)
{
var member = new MemberControl();
member.memberId = i++;
member.text.Content = ServicesStaticInfo.ServicesShortName[account.providerId] + "-" + account.nickName;
mLayout.Children.Add(member);
}
}
private ContextMenu CreateContextMenu()
{
ContextMenu contextMenu = new ContextMenu();
MenuItem addMemberItem = new MenuItem { Header = "添加账号" };
addMemberItem.Click += addMemberItem_Click;
contextMenu.Items.Add(addMemberItem);
MenuItem addMembersItem = new MenuItem { Header = "导入账号" };
contextMenu.Items.Add(addMembersItem);
addMembersItem.Click += addMembersItem_Click;
MenuItem addTeamItem = new MenuItem { Header = "新增队伍" };
contextMenu.Items.Add(addTeamItem);
addTeamItem.Click += addTeamItem_Click;
MenuItem editTeamItem = new MenuItem { Header = "编辑队伍" };
contextMenu.Items.Add(editTeamItem);
editTeamItem.Click += editTeamItem_Click;
MenuItem changeTeamItem = new MenuItem { Header = "切换队伍" };
contextMenu.Items.Add(changeTeamItem);
changeTeamItem.MouseEnter += (sender, args) =>
{
// 清空ContextMenu的items
changeTeamItem.Items.Clear();
// 假设你有一个字符串数组
string[] items = TeamManager.GetAllTeamName();
// 遍历字符串数组为每个元素创建一个MenuItem
for (int i = 0; i < items.Length; i++)
{
MenuItem menuItem = new MenuItem { Header = items[i] };
menuItem.Tag = i;
menuItem.Click += (sender, args) =>
{
// 输出被点击的item的index
MenuItem menuItem = sender as MenuItem;
int i = (int)menuItem.Tag;
Trace.WriteLine("Clicked item index: " + i);
AccountManager.reloadData(i);
ReloadBtn();
};
changeTeamItem.Items.Add(menuItem);
}
};
return contextMenu;
}
private void addMemberItem_Click(object sender, RoutedEventArgs e)
{
EditMemberDialog.CreateDailog(this, null);
}
private void addMembersItem_Click(object sender, RoutedEventArgs e)
{
AddMemebersDialog.CreateDailog(this);
}
private void addTeamItem_Click(object sender, RoutedEventArgs e)
{
EditTeamDialog.CreateDailog(this);
}
private void editTeamItem_Click(object sender, RoutedEventArgs e)
{
EditTeamDialog.CreateDailog(this, AccountManager.teamName);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// 创建新的按钮
Button newButton = new Button();
newButton.Content = "新按钮";
// 将新按钮添加到布局中
// 假设你的布局是一个名为"myLayout"的StackPanel
mLayout.Children.Add(newButton);
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
LoginManager.LoginTest();
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
LoginManager.GameTest();
}
private void Button_Click_3(object sender, RoutedEventArgs e)
{
WebApiManager.StopListener();
Close();
}
private void AirButton_Click(object sender, RoutedEventArgs e)
{
var ab = new About1();
ab.ShowDialog();
}
}
}

7
Manager/ADManager.cs Normal file
View File

@ -0,0 +1,7 @@
namespace Zerolauncher.Manager
{
internal class ADManager
{
}
}

156
Manager/AccountManager.cs Normal file
View File

@ -0,0 +1,156 @@

namespace Zerolauncher.Manager
{
internal class AccountManager
{
static int teamIndex=0;
public static string teamName = "";
public static List<Account> accountsList = new List<Account>();
public static void initLoadData()
{
teamIndex = DataStream.dataStream.teamIndex;
var group = DataStream.dataStream.Groups[teamIndex];
teamName = group.Name;
foreach (var acc in group.Accounts)
{
accountsList.Add(acc);
}
}
public static void reloadData(int index = -1)
{
if (index < 0) index = teamIndex;
var group = DataStream.dataStream.Groups[index];
if (teamIndex!=index)
{
teamIndex = index;
teamName = group.Name;
DataStream.dataStream.teamIndex = index;
DataStream.write();
}
accountsList.Clear();
foreach (var acc in group.Accounts)
{
accountsList.Add(acc);
}
}
public static void saveEdit()
{
DataStream.write();
MainWindow.Instance.ReloadBtn();
}
public static bool AddAccount(Account account)
{
if (TeamManager.Nick2Acc(account.nickName) != null)
{
return false;
}
var group = DataStream.dataStream.Groups[teamIndex];
group.Accounts.Add(account);
accountsList.Add(account);
DataStream.write();
MainWindow.Instance.ReloadBtn();
return true;
}
public static bool AddAccounts(Account account)
{
if (TeamManager.Nick2Acc(account.nickName) != null)
{
return false;
}
var group = DataStream.dataStream.Groups[teamIndex];
group.Accounts.Add(account);
accountsList.Add(account);
//DataStream.write(); 不写
//MainWindow.Instance.ReloadBtn(); 不更新
return true;
}
public static void MoveAccount(int memberId, int newIndex)
{
var group1 = DataStream.dataStream.Groups[newIndex];
group1.Accounts.Add(accountsList[memberId]);
var group = DataStream.dataStream.Groups[teamIndex];
group.Accounts.RemoveAt(memberId);
DataStream.write();
MainWindow.Instance.ReloadBtn();
}
public static void DeleteAccount(int index) {
var group = DataStream.dataStream.Groups[teamIndex];
group.Accounts.RemoveAt(index);
DataStream.write();
reloadData();
MainWindow.Instance.ReloadBtn();
}
public static void editTeamName(string teamName0)
{
teamName = teamName0;
var group = DataStream.dataStream.Groups[teamIndex];
group.Name = teamName;
DataStream.write();
}
public static bool DeleteTeam()
{
if (DataStream.dataStream.Groups.Count == 1)
{
return false;
}
DataStream.dataStream.Groups.RemoveAt(teamIndex);
DataStream.write();
reloadData(0);
MainWindow.Instance.ReloadBtn();
return true;
}
}
internal class TeamManager
{
public static string[] GetAllTeamName()
{
string[] names = new string[DataStream.dataStream.Groups.Count];
int i = 0;
foreach (var group in DataStream.dataStream.Groups)
{
names[i++] = group.Name;
}
return names;
}
public static void addTeam(string teamName)
{
var group = new Group { Name = teamName, Accounts = new List<Account> { } };
DataStream.dataStream.Groups.Add(group);
DataStream.write();
}
//运行时才能决定是否执行内联
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static Account? Nick2Acc(string nickName)
{
// find and return first take
foreach (var group in DataStream.dataStream.Groups)
{
foreach (var acc in group.Accounts)
{
if (acc.nickName.Equals(nickName)) return acc;
}
}
return null;
}
}
}

89
Manager/DataStream.cs Normal file
View File

@ -0,0 +1,89 @@
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Text;
using Newtonsoft.Json;
namespace Zerolauncher.Manager
{
class DataStream
{
private const string path = "user.data";
public static Data dataStream;
public static void Load()
{
if (File.Exists(path))
{
dataStream = JsonConvert.DeserializeObject<Data>(Encoding.UTF8.GetString(Decompress(File.ReadAllBytes(path))));
}
else
{
dataStream = JsonConvert.DeserializeObject<Data>(
"{\"teamIndex\":0,\"Groups\":[{\"Name\":\"队伍1\", \"Accounts\": [{\"providerId\":0,\"userName\":\"test\",\"userPWD\":\"test\",\"nickName\":\"测试账号\",\"serverId\":\"1\"}]}]}");
}
}
public static void write()
{
string? data = JsonConvert.SerializeObject(dataStream);
Trace.WriteLine(data);
if (data == null) return;
File.WriteAllBytes(path, CompressBytes(Encoding.UTF8.GetBytes(data)));
}
//压缩字节
//1.创建压缩的数据流
//2.设定compressStream为存放被压缩的文件流,并设定为压缩模式
//3.将需要压缩的字节写到被压缩的文件流
public static byte[] CompressBytes(byte[] bytes)
{
using (MemoryStream compressStream = new MemoryStream())
{
using (var zipStream = new GZipStream(compressStream, CompressionMode.Compress))
zipStream.Write(bytes, 0, bytes.Length);
return compressStream.ToArray();
}
}
//解压缩字节
//1.创建被压缩的数据流
//2.创建zipStream对象并传入解压的文件流
//3.创建目标流
//4.zipStream拷贝到目标流
//5.返回目标流输出字节
public static byte[] Decompress(byte[] bytes)
{
using (var compressStream = new MemoryStream(bytes))
{
using (var zipStream = new GZipStream(compressStream, CompressionMode.Decompress))
{
using (var resultStream = new MemoryStream())
{
zipStream.CopyTo(resultStream);
return resultStream.ToArray();
}
}
}
}
}
public class Account
{
public int providerId;
public string userName, userPWD, nickName, serverId;
}
class Group
{
public string Name;
public List<Account> Accounts;
}
struct Data
{
public int teamIndex;
public List<Group> Groups;
}
}

374
Manager/DownloadManager.cs Normal file
View File

@ -0,0 +1,374 @@
using System.Net;
using System.IO;
namespace Zerolauncher.Manager
{
public class DownloadManager
{
/// <summary>
/// 主线程
/// </summary>
private SynchronizationContext _mainThreadSynContext;
/// <summary>
/// 下载网址
/// </summary>
public string Url;
public event Action<Exception> OnError;
private static object errorlock = new object();
/// <summary>
/// 主要用于关闭线程
/// </summary>
private bool _isDownload = false;
public DownloadManager(string url)
{
// 主线程赋值
_mainThreadSynContext = SynchronizationContext.Current;
// 突破Http协议的并发连接数限制
ServicePointManager.DefaultConnectionLimit = 512;
Url = url;
}
/// <summary>
/// 查询文件大小
/// </summary>
/// <returns></returns>
public long GetFileSize()
{
HttpWebRequest request;
HttpWebResponse response;
try
{
request = (HttpWebRequest)WebRequest.CreateHttp(new Uri(Url));
request.Method = "HEAD";
response = (HttpWebResponse)request.GetResponse();
// 获得文件长度
long contentLength = response.ContentLength;
response.Close();
request.Abort();
return contentLength;
}
catch (Exception ex)
{
onError(ex);
// throw;
return -1;
}
}
/// <summary>
/// 异步查询文件大小
/// </summary>
/// <param name="onTrigger"></param>
public void GetFileSizeAsyn(Action<long> onTrigger = null)
{
ThreadStart threadStart = new ThreadStart(() =>
{
PostMainThreadAction<long>(onTrigger, GetFileSize());
});
Thread thread = new Thread(threadStart);
thread.Start();
}
/// <summary>
/// 多线程下载文件至本地
/// </summary>
/// <param name="threadCount">线程总数</param>
/// <param name="filePath">保存文件路径</param>
/// <param name="onDownloading">下载过程回调(已下载文件大小、总文件大小)</param>
/// <param name="onTrigger">下载完毕回调(下载文件数据)</param>
public void DownloadToFile(int threadCount, string filePath, Action<long, long> onDownloading = null, Action<byte[]> onTrigger = null)
{
_isDownload = true;
long csize = 0; //已下载大小
int ocnt = 0; //完成线程数
// 下载逻辑
GetFileSizeAsyn((size) =>
{
if (size == -1) return;
// 准备工作
var tempFilePaths = new string[threadCount];
var tempFileFileStreams = new FileStream[threadCount];
var dirPath = Path.GetDirectoryName(filePath);
var fileName = Path.GetFileName(filePath);
// 下载根目录不存在则创建
if (!Directory.Exists(dirPath))
{
Directory.CreateDirectory(dirPath);
}
// 查看下载临时文件是否可以继续断点续传
var fileInfos = new DirectoryInfo(dirPath).GetFiles(fileName + "*.temp");
if (fileInfos.Length != threadCount)
{
// 下载临时文件数量不相同,则清理
foreach (var info in fileInfos)
{
info.Delete();
}
}
// 创建下载临时文件,并创建文件流
for (int i = 0; i < threadCount; i++)
{
tempFilePaths[i] = filePath + i + ".temp";
if (!File.Exists(tempFilePaths[i]))
{
File.Create(tempFilePaths[i]).Dispose();
}
tempFileFileStreams[i] = File.OpenWrite(tempFilePaths[i]);
tempFileFileStreams[i].Seek(tempFileFileStreams[i].Length, System.IO.SeekOrigin.Current);
csize += tempFileFileStreams[i].Length;
}
// 单线程下载过程回调函数
Action<int, long, byte[], byte[]> t_onDownloading = (index, rsize, rbytes, data) =>
{
csize += rsize;
tempFileFileStreams[index].Write(rbytes, 0, (int)rsize);
PostMainThreadAction<long, long>(onDownloading, csize, size);
};
// 单线程下载完毕回调函数
Action<int, byte[]> t_onTrigger = (index, data) =>
{
// 关闭文件流
tempFileFileStreams[index].Close();
ocnt++;
if (ocnt >= threadCount)
{
// 将临时文件转为下载文件
if (!File.Exists(filePath))
{
File.Create(filePath).Dispose();
}
else
{
File.WriteAllBytes(filePath, new byte[] { });
}
FileStream fs = File.OpenWrite(filePath);
fs.Seek(fs.Length, System.IO.SeekOrigin.Current);
foreach (var tempPath in tempFilePaths)
{
var tempData = File.ReadAllBytes(tempPath);
fs.Write(tempData, 0, tempData.Length);
File.Delete(tempPath);
}
fs.Close();
PostMainThreadAction<byte[]>(onTrigger, File.ReadAllBytes(filePath));
}
};
// 分割文件尺寸,多线程下载
long[] sizes = SplitFileSize(size, threadCount);
for (int i = 0; i < sizes.Length; i = i + 2)
{
long from = sizes[i];
long to = sizes[i + 1];
// 断点续传
from += tempFileFileStreams[i / 2].Length;
if (from >= to)
{
t_onTrigger(i / 2, null);
continue;
}
_threadDownload(i / 2, from, to, t_onDownloading, t_onTrigger);
}
});
}
/// <summary>
/// 多线程下载文件至内存
/// </summary>
/// <param name="threadCount">线程总数</param>
/// <param name="onDownloading">下载过程回调(已下载文件大小、总文件大小)</param>
/// <param name="onTrigger">下载完毕回调(下载文件数据)</param>
public void DownloadToMemory(int threadCount, Action<long, long> onDownloading = null, Action<byte[]> onTrigger = null)
{
_isDownload = true;
long csize = 0; // 已下载大小
int ocnt = 0; // 完成线程数
byte[] cdata; // 已下载数据
// 下载逻辑
GetFileSizeAsyn((size) =>
{
cdata = new byte[size];
// 单线程下载过程回调函数
Action<int, long, byte[], byte[]> t_onDownloading = (index, rsize, rbytes, data) =>
{
csize += rsize;
PostMainThreadAction<long, long>(onDownloading, csize, size);
};
// 单线程下载完毕回调函数
Action<int, byte[]> t_onTrigger = (index, data) =>
{
long dIndex = (long)Math.Ceiling((double)(size * index / threadCount));
Array.Copy(data, 0, cdata, dIndex, data.Length);
ocnt++;
if (ocnt >= threadCount)
{
PostMainThreadAction<byte[]>(onTrigger, cdata);
}
};
// 分割文件尺寸,多线程下载
long[] sizes = SplitFileSize(size, threadCount);
for (int i = 0; i < sizes.Length; i = i + 2)
{
long from = sizes[i];
long to = sizes[i + 1];
_threadDownload(i / 2, from, to, t_onDownloading, t_onTrigger);
}
});
}
/// <summary>
/// 单线程下载
/// </summary>
/// <param name="index">线程ID</param>
/// <param name="from">下载起始位置</param>
/// <param name="to">下载结束位置</param>
/// <param name="onDownloading">下载过程回调线程ID、单次下载数据大小、单次下载数据缓存区、已下载文件数据</param>
/// <param name="onTrigger">下载完毕回调线程ID、下载文件数据</param>
private void _threadDownload(int index, long from, long to, Action<int, long, byte[], byte[]> onDownloading = null, Action<int, byte[]> onTrigger = null)
{
Thread thread = new Thread(new ThreadStart(() =>
{
try
{
var request = (HttpWebRequest)WebRequest.Create(new Uri(Url));
request.AddRange(from, to);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream ns = response.GetResponseStream();
byte[] rbytes = new byte[8 * 1024];
int rSize = 0;
MemoryStream ms = new MemoryStream();
while (true)
{
if (!_isDownload) return;
rSize = ns.Read(rbytes, 0, rbytes.Length);
if (rSize <= 0) break;
ms.Write(rbytes, 0, rSize);
if (onDownloading != null) onDownloading(index, rSize, rbytes, ms.ToArray());
}
ns.Close();
response.Close();
request.Abort();
if (ms.Length == (to - from) + 1)
{
if (onTrigger != null) onTrigger(index, ms.ToArray());
}
else
{
lock (errorlock)
{
if (_isDownload)
{
onError(new Exception("文件大小校验不通过"));
}
}
}
}
catch (Exception ex)
{
onError(ex);
}
}));
thread.Start();
}
public void Close()
{
_isDownload = false;
}
/// <summary>
/// 分割文件大小
/// </summary>
/// <returns></returns>
private long[] SplitFileSize(long size, int count)
{
long[] result = new long[count * 2];
for (int i = 0; i < count; i++)
{
long from = (long)Math.Ceiling((double)(size * i / count));
long to = (long)Math.Ceiling((double)(size * (i + 1) / count)) - 1;
result[i * 2] = from;
result[i * 2 + 1] = to;
}
return result;
}
private void onError(Exception ex)
{
Close();
PostMainThreadAction<Exception>(OnError, ex);
}
/// <summary>
/// 通知主线程回调
/// </summary>
private void PostMainThreadAction(Action action)
{
_mainThreadSynContext.Post(new SendOrPostCallback((o) =>
{
Action e = (Action)o.GetType().GetProperty("action").GetValue(o);
if (e != null) e();
}), new { action = action });
}
private void PostMainThreadAction<T>(Action<T> action, T arg1)
{
_mainThreadSynContext.Post(new SendOrPostCallback((o) =>
{
Action<T> e = (Action<T>)o.GetType().GetProperty("action").GetValue(o);
T t1 = (T)o.GetType().GetProperty("arg1").GetValue(o);
if (e != null) e(t1);
}), new { action = action, arg1 = arg1 });
}
public void PostMainThreadAction<T1, T2>(Action<T1, T2> action, T1 arg1, T2 arg2)
{
_mainThreadSynContext.Post(new SendOrPostCallback((o) =>
{
Action<T1, T2> e = (Action<T1, T2>)o.GetType().GetProperty("action").GetValue(o);
T1 t1 = (T1)o.GetType().GetProperty("arg1").GetValue(o);
T2 t2 = (T2)o.GetType().GetProperty("arg2").GetValue(o);
if (e != null) e(t1, t2);
}), new { action = action, arg1 = arg1, arg2 = arg2 });
}
public void PostMainThreadAction<T1, T2, T3>(Action<T1, T2, T3> action, T1 arg1, T2 arg2, T3 arg3)
{
_mainThreadSynContext.Post(new SendOrPostCallback((o) =>
{
Action<T1, T2, T3> e = (Action<T1, T2, T3>)o.GetType().GetProperty("action").GetValue(o);
T1 t1 = (T1)o.GetType().GetProperty("arg1").GetValue(o);
T2 t2 = (T2)o.GetType().GetProperty("arg2").GetValue(o);
T3 t3 = (T3)o.GetType().GetProperty("arg3").GetValue(o);
if (e != null) e(t1, t2, t3);
}), new { action = action, arg1 = arg1, arg2 = arg2, arg3 = arg3 });
}
public void PostMainThreadAction<T1, T2, T3, T4>(Action<T1, T2, T3, T4> action, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
{
_mainThreadSynContext.Post(new SendOrPostCallback((o) =>
{
Action<T1, T2, T3, T4> e = (Action<T1, T2, T3, T4>)o.GetType().GetProperty("action").GetValue(o);
T1 t1 = (T1)o.GetType().GetProperty("arg1").GetValue(o);
T2 t2 = (T2)o.GetType().GetProperty("arg2").GetValue(o);
T3 t3 = (T3)o.GetType().GetProperty("arg3").GetValue(o);
T4 t4 = (T4)o.GetType().GetProperty("arg4").GetValue(o);
if (e != null) e(t1, t2, t3, t4);
}), new { action = action, arg1 = arg1, arg2 = arg2, arg3 = arg3, arg4 = arg4 });
}
}
}

246
Manager/EngineManager.cs Normal file
View File

@ -0,0 +1,246 @@
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Windows;
using Zerolauncher.Defender;
namespace Zerolauncher.Manager
{
internal class EngineManager
{
private static Dictionary<string, SingleGame> mGame = new Dictionary<string, SingleGame>();
//运行时才能决定是否执行内联
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
private static string AccToKey(Account account)
{
return string.Format("{0}{1}{2}", account.providerId, account.serverId, account.userName);
}
public static bool CreateGame(Account account)
{
var key = AccToKey(account);
if (mGame.ContainsKey(key)) { return false; }
if (EngineCacheSha.errorCode != 0) {
switch (EngineCacheSha.errorCode)
{
case 1:
MessageBox.Show("发生网络错误==EMS。\n 请检查网络", "错误", MessageBoxButton.OKCancel, MessageBoxImage.Error);
break;
case 2:
MessageBox.Show("发生游戏服务错误==EMS。\n 请联系管理员", "错误", MessageBoxButton.OKCancel, MessageBoxImage.Error);
break;
default:
MessageBox.Show("发生未知错误==EMS。\n 请联系管理员", "错误", MessageBoxButton.OKCancel, MessageBoxImage.Error);
break;
}
return false;
}
try
{
mGame[key] = new SingleGame(account);
}catch (Exception _ex)
{
MessageBox.Show("发生错误!\n如重复发生此错误\n请重新下载登陆器文件或联系管理员。", "错误", MessageBoxButton.OKCancel, MessageBoxImage.Error);
return false;
}
return true;
}
public static bool CreateGame(int memberId)
{
var account = AccountManager.accountsList[memberId];
var key = AccToKey(account);
if (mGame.ContainsKey(key)) { return false; }
mGame[key] = new SingleGame(account);
return true;
}
public static int CheckGameState(Account account)
{
var key = AccToKey(account);
if (mGame.ContainsKey(key)) { return mGame[key].mHandle; }
return -1;
}
public static short TurnGameSizeMini(Account account)
{
var key = AccToKey(account);
if (mGame.ContainsKey(key))
{
var game = mGame[key];
if (game.mHandle != 0)
{
game.Send(StaticHandleS.MiniSize);
return 2;
}
return 1;
}
return 0;
}
public static short TurnGameSizeNormal(Account account)
{
var key = AccToKey(account);
if (mGame.ContainsKey(key))
{
var game = mGame[key];
if (game.mHandle != 0)
{
game.Send(StaticHandleS.NormalSize);
return 2;
}
return 1;
}
return 0;
}
public static bool ExitGame(Account account)
{
var key = AccToKey(account);
if (!mGame.ContainsKey(key)) { return false; }
mGame[key].Send(StaticHandleS.CloseGame);
return true;
}
public static void OnGameExit(Account account)
{
mGame.Remove(AccToKey(account));
}
public static bool CheckEmpy()
{
return mGame.Count == 0;
}
}
class SingleGame
{
Process process;
string? restartUrl;
public int mHandle;
public Account account;
public SingleGame(Account acc)
{
restartUrl = null;
this.account = acc;
mHandle = 0;
process = EngineShell.CheckEngineSafe();
process.OutputDataReceived += Handle;
process.Exited += Process_Exited;
process.Start();
process.BeginOutputReadLine(); // 开始异步读取
}
private void CreateProcess()
{
process = EngineShell.CheckEngineSafe();
process.OutputDataReceived += Handle;
process.Exited += Process_Exited;
process.Start();
process.BeginOutputReadLine(); // 开始异步读取
}
private void Process_Exited(object? sender, EventArgs e)
{
Trace.WriteLine(
$"Exit time : {process.ExitTime}\n" +
$"Exit code : {process.ExitCode}\n" +
$"Elapsed time : {Math.Round((process.ExitTime - process.StartTime).TotalMilliseconds)}");
Trace.WriteLine($"进程已退出:{account.nickName}");
if ( restartUrl == null )
{
EngineManager.OnGameExit(account);
return;
}
CreateProcess();
}
private void Handle(object sender, DataReceivedEventArgs e)
{
var lines = e.Data == null? [""] : e.Data.Split(" ");
switch (lines[0])
{
case StaticHandleC.StartDone:
if(restartUrl == null)
{
Send($"{StaticHandleS.ShowWindow} {ServicesStaticInfo.ServicesName[account.providerId]}-{account.nickName}");
_ = LoginManager.DoLogin(this);
}
else
{
Send($"{StaticHandleS.ShowWindow} {ServicesStaticInfo.ServicesName[account.providerId]}-{account.nickName}");
Send($"{StaticHandleS.GameSa} {restartUrl}");
restartUrl = null;
}
break;
case StaticHandleC.GameDone:
mHandle = int.Parse(lines[1]);
break;
case StaticHandleC.BrowserDone:
restartUrl = lines[1];
Send(StaticHandleS.CloseGame);
break;
}
}
public bool Send(string msg)
{
if(process.HasExited) { return false; }
process.StandardInput.WriteLine(msg);
return true;
}
}
public class FileReadException : Exception
{
public FileReadException(string message) : base(message)
{
}
}
class EngineShell
{
static bool is_check = false;
const string engine_file = @"ZeroEngine.exe";
public static Process CheckEngineSafe()
{
if (is_check && EngineManager.CheckEmpy())
{
string? now_bit;
using (SHA256 sha256 = SHA256.Create())
{
using (FileStream fileStream = File.OpenRead(engine_file))
{
byte[] hashBytes = sha256.ComputeHash(fileStream);
now_bit = BitConverter.ToString(hashBytes).Replace("-", string.Empty);
}
}
if (EngineCacheSha.Get() != now_bit)
{
throw new FileReadException("无法读取文件内容");
}
}
is_check = true;
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = engine_file,
Arguments = StaticHandleA.GameMode,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardInput = true,
RedirectStandardOutput = true
},
EnableRaisingEvents = true
};
return process;
}
}
}

201
Manager/HashHelper.cs Normal file
View File

@ -0,0 +1,201 @@
using System.Text;
namespace Zerolauncher.Manager
{
/// <summary>
/// 提供用于计算指定文件哈希值的方法
/// <example>例如计算文件的MD5值:
/// <code>
/// String hashMd5=HashHelper.ComputeMD5("MyFile.txt");
/// </code>
/// </example>
/// <example>例如计算文件的CRC32值:
/// <code>
/// String hashCrc32 = HashHelper.ComputeCRC32("MyFile.txt");
/// </code>
/// </example>
/// <example>例如计算文件的SHA1值:
/// <code>
/// String hashSha1 =HashHelper.ComputeSHA1("MyFile.txt");
/// </code>
/// </example>
/// </summary>
public sealed class HashHelper
{
/// <summary>
/// 计算指定文件的MD5值
/// </summary>
/// <param name="fileName">指定文件的完全限定名称</param>
/// <returns>返回值的字符串形式</returns>
public static String ComputeMD5(String fileName)
{
String hashMD5 = String.Empty;
//检查文件是否存在,如果文件存在则进行计算,否则返回空值
if (System.IO.File.Exists(fileName))
{
using (System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
//计算文件的MD5值
System.Security.Cryptography.MD5 calculator = System.Security.Cryptography.MD5.Create();
Byte[] buffer = calculator.ComputeHash(fs);
calculator.Clear();
//将字节数组转换成十六进制的字符串形式
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < buffer.Length; i++)
{
stringBuilder.Append(buffer[i].ToString("x2"));
}
hashMD5 = stringBuilder.ToString();
}//关闭文件流
}//结束计算
return hashMD5;
}//ComputeMD5
/// <summary>
/// 计算指定文件的CRC32值
/// </summary>
/// <param name="fileName">指定文件的完全限定名称</param>
/// <returns>返回值的字符串形式</returns>
public static String ComputeCRC32(String fileName)
{
String hashCRC32 = String.Empty;
//检查文件是否存在,如果文件存在则进行计算,否则返回空值
if (System.IO.File.Exists(fileName))
{
using (System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
//计算文件的CSC32值
Crc32 calculator = new Crc32();
Byte[] buffer = calculator.ComputeHash(fs);
calculator.Clear();
//将字节数组转换成十六进制的字符串形式
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < buffer.Length; i++)
{
stringBuilder.Append(buffer[i].ToString("x2"));
}
hashCRC32 = stringBuilder.ToString();
}//关闭文件流
}
return hashCRC32;
}//ComputeCRC32
/// <summary>
/// 计算指定文件的SHA1值
/// </summary>
/// <param name="fileName">指定文件的完全限定名称</param>
/// <returns>返回值的字符串形式</returns>
public static String ComputeSHA1(String fileName)
{
String hashSHA1 = String.Empty;
//检查文件是否存在,如果文件存在则进行计算,否则返回空值
if (System.IO.File.Exists(fileName))
{
using (System.IO.FileStream fs = new System.IO.FileStream(fileName, System.IO.FileMode.Open, System.IO.FileAccess.Read))
{
//计算文件的SHA1值
System.Security.Cryptography.SHA1 calculator = System.Security.Cryptography.SHA1.Create();
Byte[] buffer = calculator.ComputeHash(fs);
calculator.Clear();
//将字节数组转换成十六进制的字符串形式
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < buffer.Length; i++)
{
stringBuilder.Append(buffer[i].ToString("x2"));
}
hashSHA1 = stringBuilder.ToString();
}//关闭文件流
}
return hashSHA1;
}//ComputeSHA1
}//end class: HashHelper
/// <summary>
/// 提供 CRC32 算法的实现
/// </summary>
public class Crc32 : System.Security.Cryptography.HashAlgorithm
{
public const UInt32 DefaultPolynomial = 0xedb88320;
public const UInt32 DefaultSeed = 0xffffffff;
private UInt32 hash;
private UInt32 seed;
private UInt32[] table;
private static UInt32[] defaultTable;
public Crc32()
{
table = InitializeTable(DefaultPolynomial);
seed = DefaultSeed;
Initialize();
}
public Crc32(UInt32 polynomial, UInt32 seed)
{
table = InitializeTable(polynomial);
this.seed = seed;
Initialize();
}
public override void Initialize()
{
hash = seed;
}
protected override void HashCore(byte[] buffer, int start, int length)
{
hash = CalculateHash(table, hash, buffer, start, length);
}
protected override byte[] HashFinal()
{
byte[] hashBuffer = UInt32ToBigEndianBytes(~hash);
this.HashValue = hashBuffer;
return hashBuffer;
}
public static UInt32 Compute(byte[] buffer)
{
return ~CalculateHash(InitializeTable(DefaultPolynomial), DefaultSeed, buffer, 0, buffer.Length);
}
public static UInt32 Compute(UInt32 seed, byte[] buffer)
{
return ~CalculateHash(InitializeTable(DefaultPolynomial), seed, buffer, 0, buffer.Length);
}
public static UInt32 Compute(UInt32 polynomial, UInt32 seed, byte[] buffer)
{
return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length);
}
private static UInt32[] InitializeTable(UInt32 polynomial)
{
if (polynomial == DefaultPolynomial && defaultTable != null)
{
return defaultTable;
}
UInt32[] createTable = new UInt32[256];
for (int i = 0; i < 256; i++)
{
UInt32 entry = (UInt32)i;
for (int j = 0; j < 8; j++)
{
if ((entry & 1) == 1)
entry = (entry >> 1) ^ polynomial;
else
entry = entry >> 1;
}
createTable[i] = entry;
}
if (polynomial == DefaultPolynomial)
{
defaultTable = createTable;
}
return createTable;
}
private static UInt32 CalculateHash(UInt32[] table, UInt32 seed, byte[] buffer, int start, int size)
{
UInt32 crc = seed;
for (int i = start; i < size; i++)
{
unchecked
{
crc = (crc >> 8) ^ table[buffer[i] ^ crc & 0xff];
}
}
return crc;
}
private byte[] UInt32ToBigEndianBytes(UInt32 x)
{
return new byte[] { (byte)((x >> 24) & 0xff), (byte)((x >> 16) & 0xff), (byte)((x >> 8) & 0xff), (byte)(x & 0xff) };
}
}//end class: Crc32
}

146
Manager/LoginManager.cs Normal file
View File

@ -0,0 +1,146 @@
using System.Diagnostics;
using System.Net;
using System.Net.Http;
namespace Zerolauncher.Manager
{
internal class LoginManager
{
//private static readonly HttpClient client = new HttpClient();
public static async Task SendPostRequest()
{
var client = new HttpClient();
client.DefaultRequestVersion = HttpVersion.Version20;
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower;
var values = new Dictionary<string, string>
{
{ "thing1", "hello" },
{ "thing2", "world" }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("http://www.example.com/recepticle.aspx", content);
var responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseString);
}
public static async Task LoginTest()
{
var client = new HttpClient();
client.DefaultRequestVersion = HttpVersion.Version20;
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower;
var values = new Dictionary<string, string>
{
{ "thing1", "hello" },
{ "thing2", "world" }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("http://www.example.com/recepticle.aspx", content);
var responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseString);
}
public static void GameTest()
{
//Account account = new Account
//{
// userName = "b1783488228",
// userPWD = "565656",
// serverId = "179"
//};
//SingleGame game = new SingleGame(account);
}
public static async Task DoLogin(SingleGame game)
{
var client = new HttpClient();
string? need_web = null;
client.Timeout = TimeSpan.FromSeconds(10);
switch (game.account.providerId)
{
case 0:
{
var values = new Dictionary<string, string>
{
{ "loginFrom", "uframe" },
{ "postLoginHandler", "default" },
{ "layoutSelfAdapting", "true" },
{ "externalLogin", "qq" },
{ "displayMode", "popup" },
{ "layout", "vertical" },
{ "appId", "www_home" },
{ "mainDivId", "popup_login_div" },
{ "includeFcmInfo", "false" },
{ "userNameLabel", "4399用户名" },
{ "userNameTip", "请输入4399用户名" },
{ "welcomeTip", "欢迎回到4399" },
{ "username", game.account.userName },
{ "password", game.account.userPWD }
};
var content = new FormUrlEncodedContent(values);
HttpResponseMessage? response = null;
try
{
response = await client.PostAsync("http://ptlogin.4399.com/ptlogin/login.do?v=1", content);
}
catch (Exception ex)
{
game.Send($"{StaticHandleS.HintText} 网络发生错误,类型:{ex.GetType().Name},消息:{ex.Message}");
need_web = $"http://web.4399.com/stat/togame.php?target=ddt&server_id=S{game.account.serverId}";
break;
}
var responseString = await response.Content.ReadAsStringAsync();
// eventHandles.__errorCallback('密码错误');
if (responseString.Contains("eventHandles.__errorCallback"))
{
game.Send($"{StaticHandleS.HintText} 登录异常:{responseString.Split("eventHandles.__errorCallback('")[1].Split("'")[0]}");
need_web = $"http://web.4399.com/stat/togame.php?target=ddt&server_id=S{game.account.serverId}";
break;
}
if(!game.Send($"{StaticHandleS.HintText} 登录成功,开始解析iframe")) return;
}
{
HttpResponseMessage? response = null;
try
{
response = await client.PostAsync("http://web.4399.com/stat/togame.php?target=ddt&server_id=S" + game.account.serverId, null);
}
catch (Exception ex)
{
game.Send($"{StaticHandleS.HintText} 网络发生错误,类型:{ex.GetType().Name},消息:{ex.Message}");
need_web = $"http://web.4399.com/stat/togame.php?target=ddt&server_id=S{game.account.serverId}";
break;
}
var responseString = await response.Content.ReadAsStringAsync();
if (!responseString.Contains("name=\"game_box\""))
{
game.Send($"{StaticHandleS.HintText} 解析异常:服务器返回数据不正确");
need_web = $"http://web.4399.com/stat/togame.php?target=ddt&server_id=S{game.account.serverId}";
break;
}
responseString = responseString.Split("name=\"game_box\"")[1].Split("src=\"")[1].Split("\"")[0];
response = await client.PostAsync(responseString, null);
responseString = await response.Content.ReadAsStringAsync();
responseString = "http://" + response.RequestMessage.RequestUri.ToString().Split("/")[2] + "/" + responseString.Split("movie\" value='")[1].Split("'")[0];
Trace.WriteLine(responseString);
game.Send($"{StaticHandleS.GameSa} {responseString}");
}
break;
default:
game.Send($"{StaticHandleS.HintText} 错误。未适配的运营商:{game.account.serverId}");
break;
}
client.Dispose();
if (need_web == null) return;
for (int i = 6; i > 0; i--)
{
await Task.Delay(1000);
if (!game.Send($"{StaticHandleS.HintText} 自动登录失败,将在{i}后启用网页登录,关闭窗口取消")) { return; }
}
game.Send($"{StaticHandleS.UseBrowser} {need_web}");
}
}
}

77
Manager/SpaceEncoder.cs Normal file
View File

@ -0,0 +1,77 @@
using System.Text;
namespace Zerolauncher.Manager
{
class SpaceEncoder
{
const int mini_index = 48;
const int max_index = 70;
const int sec_index = 60;
static readonly List<char> map = [
(char)8192,
(char)8194,
(char)8196,
(char)8197,
(char)8198,
(char)8199,
(char)8200,
(char)8201,
(char)8202,
(char)8239,
(char)8287,
(char)32
];
public static string? Encode(string hex)
{
StringBuilder sb = new StringBuilder();
foreach (char c in hex)
{
if (mini_index > c && max_index < c)
{
return null;
}
if (c < sec_index)
{
sb.Append(map[c - mini_index]);
}
else
{
sb.Append(map[11]);
sb.Append(map[c - sec_index]);
}
}
return sb.ToString();
}
public static string? Decode(string hex, out int counter)
{
StringBuilder sb = new StringBuilder();
bool double_char = false;
counter = 0;
foreach (char c in hex)
{
counter++;
if (!map.Contains(c)) return null;
if (c != map[11])
{
int j = map.FindIndex(item => item.Equals(c));
if (double_char)
{
int k = j + sec_index;
if (k > max_index) return null;
sb.Append((char)k);
double_char = false;
}
else sb.Append((char)(j + mini_index));
}
else
{
if (double_char) return null;
double_char = true;
}
}
return sb.ToString();
}
}
}

129
Manager/UpDateManager.cs Normal file
View File

@ -0,0 +1,129 @@
using System.IO;
using System.Net;
using System.Net.Http;
using Zerolauncher.Defender;
namespace Zerolauncher.Manager
{
class UpDateManager
{
public static async Task TakeQMessage()
{
var client = new HttpClient();
client.DefaultRequestVersion = HttpVersion.Version20;
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower;
client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (iPad; U; CPU OS 6_0 like Mac OS X; zh-CN; iPad2)");
HttpResponseMessage response;
try
{
client.Timeout = TimeSpan.FromMinutes(3);
response = await client.GetAsync($"https://sharechain.qq.com/13111bbd6ffbffa3057878431bef103e");
}catch (Exception _ex)
{
EngineCacheSha.errorCode = 1;
return;
}
var responseString = await response.Content.ReadAsStringAsync();
responseString = responseString.Split("<div class=\"note-content\">")[1].Split("</article>")[0].Replace("</div>", "").Replace("\n", "").Replace("\t", "").Replace("\r", "").Replace("'", "");
var arr = responseString.Split("<div>").Last();
if (arr.Length < 90)
{
EngineCacheSha.errorCode = 2;
return;
}
int count;
var sha = SpaceEncoder.Decode(arr[..86], out count);
if (sha == null)
{
//Console.WriteLine($"faile: {count}");
EngineCacheSha.errorCode = 2;
return;
}
EngineCacheSha.Put(sha);
}
public async Task GetTask()
{
var client = new HttpClient();
client.DefaultRequestVersion = HttpVersion.Version20;
client.DefaultVersionPolicy = HttpVersionPolicy.RequestVersionOrLower;
client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (iPad; U; CPU OS 6_0 like Mac OS X; zh-CN; iPad2)");
var response = await client.GetAsync("https://sharechain.qq.com/13111bbd6ffbffa3057878431bef103e");
var responseString = await response.Content.ReadAsStringAsync();
if (responseString.Contains("<div class=\"note-content\">"))
{
responseString = responseString.Split("<div class=\"note-content\">")[1].Split("</article>")[0].Replace("</div>", "").Replace("\n", "").Replace(" ", "").Replace("\t", "").Replace("\r", "").Replace("'", "");
Console.WriteLine(responseString.Replace("<div>", "\n"));
var arr = responseString.Split("<div>");
int main_version, engine_version, sa_version;
if (int.TryParse(arr[0], out main_version) && int.TryParse(arr[1], out engine_version))
{
}
}
// todo open faile update dialog
}
public static void DownLoad(string Url, string FileName)
{
bool Value = false;
WebResponse response = null;
Stream stream = null;
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Url);
response = request.GetResponse();
stream = response.GetResponseStream();
if (!response.ContentType.ToLower().StartsWith("text/"))
{
Value = SaveBinaryFile(response, FileName);
}
}
catch (Exception err)
{
string aa = err.ToString();
}
}
private static bool SaveBinaryFile(WebResponse response, string FileName)
{
bool Value = true;
byte[] buffer = new byte[1024];
try
{
if (File.Exists(FileName))
File.Delete(FileName);
Stream outStream = File.Create(FileName);
Stream inStream = response.GetResponseStream();
int l;
do
{
l = inStream.Read(buffer, 0, buffer.Length);
if (l > 0)
outStream.Write(buffer, 0, l);
}
while (l > 0);
outStream.Close();
inStream.Close();
}
catch
{
Value = false;
}
return Value;
}
}
}

View File

@ -0,0 +1,8 @@
namespace Zerolauncher.Manager
{
class VersionManager
{
public static int GetMainVer() { return 10001; }
}
}

159
Manager/WebApiManager.cs Normal file
View File

@ -0,0 +1,159 @@
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Text;
namespace Zerolauncher.Manager
{
internal class WebApiManager
{
static HttpListener listener = new HttpListener();
static CancellationTokenSource cts = new CancellationTokenSource();
public static async Task StartListener()
{
listener.Prefixes.Add("http://127.0.0.1:7233/");
listener.Start();
Trace.WriteLine("Listening...");
while (!cts.Token.IsCancellationRequested)
{
HttpListenerContext context = await listener.GetContextAsync();
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
var raw = request.RawUrl;
ResponesBody? rb = null;
if (raw != null && raw.Contains("?"))
{
var lines = raw.Split("?");
var args = request.QueryString;
var nick = args["name"];
if (nick != null)
{
var acc = TeamManager.Nick2Acc(nick);
if (acc != null)
{
switch (lines[0])
{
case "/CloseGame":
{
if (EngineManager.ExitGame(acc))
{
rb = new ResponesBody(1, 0, $"Account [{nick}] successful to close.");
}
else
{
rb = new ResponesBody($"Account [{nick}] is unluacher.");
break;
}
}
break;
case "/ToNormalSize":
{
switch (EngineManager.TurnGameSizeNormal(acc))
{
case 2:
rb = new ResponesBody(1, 0, $"Account [{nick}] now is normal size.");
break;
case 1:
rb = new ResponesBody(0, 0, $"Account [{nick}] is loading, please wait.");
break;
case 0:
rb = new ResponesBody($"Account [{nick}] is unluacher.");
break;
}
}
break;
case "/ToMiniSize":
{
switch (EngineManager.TurnGameSizeMini(acc))
{
case 2:
rb = new ResponesBody(1, 0, $"Account [{nick}] now is mini size.");
break;
case 1:
rb = new ResponesBody(0, 0, $"Account [{nick}] is loading, please wait.");
break;
case 0:
rb = new ResponesBody($"Account [{nick}] is unluacher.");
break;
}
}
break;
case "/LoginGame":
{
if (EngineManager.CreateGame(acc))
{
rb = new ResponesBody(0, 0, $"Account [{nick}] successful to start.");
}
else
{
int hwnd = EngineManager.CheckGameState(acc);
if (hwnd <= 0)
{
rb = new ResponesBody(0, 0, $"Account [{nick}] is loading, please wait.");
}
else
{
rb = new ResponesBody(1, hwnd, $"Account [{nick}] now is running.");
}
}
}
break;
default:
rb = new ResponesBody($"commad [{lines[0]}] undefind.");
break;
}
}
else
{
rb = new ResponesBody($"Account [{nick}] undefind.");
}
}
else
{
rb = new ResponesBody("args is missing.");
}
}
if (rb == null)
{
rb = new ResponesBody();
}
byte[] buffer = Encoding.UTF8.GetBytes(rb.Encode());
response.ContentLength64 = buffer.Length;
Stream output = response.OutputStream;
await output.WriteAsync(buffer, 0, buffer.Length);
output.Close();
}
listener.Stop();
}
public static void StopListener() { cts.Cancel(); }
}
class ResponesBody
{
public int status;
public int hwnd;
public string message;
public ResponesBody(string message)
{
this.status = -1;
this.hwnd = 0;
this.message = message;
}
public ResponesBody(int status=-1, int hwnd=0, string message= "Hello, World!")
{
this.status = status;
this.hwnd = hwnd;
this.message = message;
}
public string Encode()
{
return $"{{\"state\": {status}, \"hwnd\": {hwnd}, \"message\": \"{message}\"}}";
}
}
}

9
ServicesStaticInfo.cs Normal file
View File

@ -0,0 +1,9 @@
namespace Zerolauncher
{
class ServicesStaticInfo
{
public static string[] ServicesName = ["4399大区", "7k7k大区", "第七大道"];
public static string[] ServicesShortName = ["43", "7k", "7d"];
}
}

27
StaticHandleProtol.cs Normal file
View File

@ -0,0 +1,27 @@
namespace Zerolauncher
{
class StaticHandleS
{
public const string ShowWindow = "a0";
public const string HintText = "b0";
public const string MiniSize = "c0";
public const string NormalSize = "d0";
public const string UseBrowser = "e0";
public const string GameSa = "f0";
public const string CloseGame = "g0";
}
class StaticHandleC
{
public const string StartDone = "0a";
public const string BrowserDone = "0b";
public const string StartGame = "0c";
public const string GameDone = "0d";
}
class StaticHandleA
{
public const string GameMode = "0a";
public const string UpdateMode = "0b";
}
}

57
Zerolauncher.csproj Normal file
View File

@ -0,0 +1,57 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<ApplicationIcon>res\title.ico</ApplicationIcon>
<Obfuscate>true</Obfuscate>
<ConfuserReplaceOutput>true</ConfuserReplaceOutput>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DebugType>full</DebugType>
</PropertyGroup>
<ItemGroup>
<None Remove="res\1.png" />
<None Remove="res\2.png" />
<None Remove="res\25.png" />
<None Remove="res\39376.jpg" />
<None Remove="res\about1.png" />
<None Remove="res\btn_close1.png" />
<None Remove="res\btn_mini1.png" />
<None Remove="res\config.png" />
<None Remove="res\del.png" />
<None Remove="res\player_ico1.png" />
</ItemGroup>
<ItemGroup>
<Content Include="res\title.ico" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Lierda.WPFHelper" Version="1.0.3" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<Resource Include="res\1.png" />
<Resource Include="res\2.png" />
<Resource Include="res\25.png" />
<Resource Include="res\39376.jpg" />
<Resource Include="res\about1.png" />
<Resource Include="res\btn_close1.png" />
<Resource Include="res\btn_mini1.png" />
<Resource Include="res\config.png" />
<Resource Include="res\del.png" />
<Resource Include="res\player_ico1.png" />
</ItemGroup>
</Project>

25
Zerolauncher.sln Normal file
View File

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34408.163
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zerolauncher", "Zerolauncher.csproj", "{C6930B95-44F3-4B41-90A6-20BA34560BF7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C6930B95-44F3-4B41-90A6-20BA34560BF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C6930B95-44F3-4B41-90A6-20BA34560BF7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C6930B95-44F3-4B41-90A6-20BA34560BF7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C6930B95-44F3-4B41-90A6-20BA34560BF7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {89B100BA-83CE-4B02-8537-22B5A520DFCE}
EndGlobalSection
EndGlobal

68
controls/AirButton.cs Normal file
View File

@ -0,0 +1,68 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace Zerolauncher.controls
{
/// <summary>
/// 按照步骤 1a 或 1b 操作,然后执行步骤 2 以在 XAML 文件中使用此自定义控件。
///
/// 步骤 1a) 在当前项目中存在的 XAML 文件中使用该自定义控件。
/// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
/// 元素中:
///
/// xmlns:MyNamespace="clr-namespace:Zerolauncher.controls"
///
///
/// 步骤 1b) 在其他项目中存在的 XAML 文件中使用该自定义控件。
/// 将此 XmlNamespace 特性添加到要使用该特性的标记文件的根
/// 元素中:
///
/// xmlns:MyNamespace="clr-namespace:Zerolauncher.controls;assembly=Zerolauncher.controls"
///
/// 您还需要添加一个从 XAML 文件所在的项目到此项目的项目引用,
/// 并重新生成以避免编译错误:
///
/// 在解决方案资源管理器中右击目标项目,然后依次单击
/// “添加引用”->“项目”->[浏览查找并选择此项目]
///
///
/// 步骤 2)
/// 继续操作并在 XAML 文件中使用控件。
///
/// <MyNamespace:AirButton/>
///
/// </summary>
public class AirButton : Button
{
static AirButton()
{
//DefaultStyleKeyProperty.OverrideMetadata(typeof(AirButton), new FrameworkPropertyMetadata(typeof(AirButton)));
}
protected override void OnMouseEnter(MouseEventArgs e)
{
// 不执行任何操作
}
protected override void OnMouseLeave(MouseEventArgs e)
{
// 不执行任何操作
}
protected override void OnMouseDown(MouseButtonEventArgs e)
{
base.OnMouseDown(e);
this.RenderTransform = new TranslateTransform(3, 3);
}
protected override void OnMouseUp(MouseButtonEventArgs e)
{
base.OnMouseUp(e);
this.RenderTransform = new TranslateTransform(0, 0);
}
}
}

20
controls/AirButton.xaml Normal file
View File

@ -0,0 +1,20 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="ChangeButtonIsMouseOver" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border" BorderThickness="0" BorderBrush="Black" Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.55" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

3
controls/AirTextBox.xaml Normal file
View File

@ -0,0 +1,3 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</ResourceDictionary>

View File

@ -0,0 +1,14 @@
<UserControl x:Class="Zerolauncher.controls.MemberControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="75" d:DesignWidth="60" Margin="5">
<Grid>
<DockPanel>
<Image Name="icon" DockPanel.Dock="Top" Source="/res/player_ico1.png" Width="60" Height="60"/>
<Label Name="text" DockPanel.Dock="Bottom" Content="43-测试账号" FontSize="9" Padding="0"/>
</DockPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,114 @@
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using Zerolauncher.dialog;
using Zerolauncher.Manager;
namespace Zerolauncher.controls
{
/// <summary>
/// MemberControl.xaml 的交互逻辑
/// </summary>
public partial class MemberControl : UserControl
{
public int memberId { get; set; }
private bool isMouseDown;
public MemberControl()
{
InitializeComponent();
isMouseDown = false;
// 鼠标按下事件
MouseDown += (s, e) =>
{
RenderTransform = new TranslateTransform(3, 3);
isMouseDown = true;
};
// 鼠标松开事件
MouseUp += (s, e) =>
{
if (!isMouseDown) return;
RenderTransform = new TranslateTransform(0, 0);
if (e.ChangedButton == MouseButton.Right) return;
if (!EngineManager.CreateGame(memberId)) MessageBox.Show("账号已启动!请勿重复启动", "提示");
};
// 鼠标离开事件
MouseLeave += (s, e) =>
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
RenderTransform = new TranslateTransform(0, 0);
isMouseDown = false;
}
};
// 鼠标捕获丢失事件
LostMouseCapture += (s, e) =>
{
RenderTransform = new TranslateTransform(0, 0);
isMouseDown = false;
};
ContextMenu = CreateContextMenu();
}
private ContextMenu CreateContextMenu()
{
ContextMenu contextMenu = new ContextMenu();
MenuItem editItem = new MenuItem { Header = "编辑" };
editItem.Click += editItem_Click;
contextMenu.Items.Add(editItem);
MenuItem delItem = new MenuItem { Header = "删除" };
delItem.Click += delItem_Click;
contextMenu.Items.Add(delItem);
MenuItem changeTeamItem = new MenuItem { Header = "移动到" };
contextMenu.Items.Add(changeTeamItem);
changeTeamItem.MouseEnter += (sender, args) =>
{
// 清空ContextMenu的items
changeTeamItem.Items.Clear();
// 假设你有一个字符串数组
string[] items = TeamManager.GetAllTeamName();
// 遍历字符串数组为每个元素创建一个MenuItem
for (int i = 0; i < items.Length; i++)
{
MenuItem menuItem = new MenuItem { Header = items[i] };
menuItem.Tag = i;
menuItem.Click += (sender, args) =>
{
// 输出被点击的item的index
MenuItem menuItem = sender as MenuItem;
int i = (int)menuItem.Tag;
Trace.WriteLine("Clicked item index: " + i);
AccountManager.MoveAccount(memberId, i);
};
changeTeamItem.Items.Add(menuItem);
}
};
return contextMenu;
}
private void delItem_Click(object sender, RoutedEventArgs e)
{
AccountManager.DeleteAccount(memberId);
}
private void editItem_Click(object sender, RoutedEventArgs e)
{
Trace.WriteLine("edit member " + memberId.ToString());
EditMemberDialog.CreateDailog(MainWindow.Instance, memberId);
}
}
}

167
controls/TextBoxRule.cs Normal file
View File

@ -0,0 +1,167 @@
using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows.Controls;
/// <summary>
/// 不能为空验证
/// </summary>
public class NotNullValidationRule : ValidationRule
{
public NotNullValidationRule()
{
ValidatesOnTargetUpdated = true;
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (string.IsNullOrEmpty(value as string) || string.IsNullOrWhiteSpace(value as string))
{
return new ValidationResult(false, "不能为空!");
}
return ValidationResult.ValidResult;
}
}
/// <summary>
/// 自定义正则表达式验证
/// </summary>
/*
1. ^[0-9]*$
2. n位的数字^\d{n}$
3. n位的数字^\d{n,}$
4. m-n位的数字^\d{m,n}$
5. ^(0|[1-9][0-9]*)$
6. ^([1-9][0-9]*)+(.[0-9]{1,2})?$
7. 1-2^(\-)?\d+(\.\d{1,2})?$
8. ^(\-|\+)?\d+(\.\d+)?$
9. ^[0-9]+(.[0-9]{2})?$
10. 1~3^[0-9]+(.[0-9]{1,3})?$
11. ^[1-9]\d*$ ^([1-9][0-9]*){1,3}$ ^\+?[1-9][0-9]*$
12. ^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$
13. ^\d+$ ^[1-9]\d*|0$
14. ^-[1-9]\d*|0$ ^((-\d+)|(0+))$
15. ^\d+(\.\d+)?$ ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
16. ^((-\d+(\.\d+)?)|(0+(\.0+)?))$ ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
17. ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
18. ^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
19. ^(-?\d+)(\.\d+)?$ ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$
1. ^[\u4e00-\u9fa5]{0,}$
2. ^[A-Za-z0-9]+$ ^[A-Za-z0-9]{4,40}$
3. 3-20^.{3,20}$
4. 26^[A-Za-z]+$
5. 26^[A-Z]+$
6. 26^[a-z]+$
7. 26^[A-Za-z0-9]+$
8. 26线^\w+$ ^\w{3,20}$
9. 线^[\u4E00-\u9FA5A-Za-z0-9_]+$
10. 线^[\u4E00-\u9FA5A-Za-z0-9]+$ ^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
11. ^%&',;=?$\"等字符:[^%&',;=?$\x22]+ 12 禁止输入含有~的字符:[^~\x22]+
1. Email地址^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
2. [a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
3. InternetURL[a-zA-z]+://[^\s]* 或 ^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
4. ^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
5. ("XXX-XXXXXXX""XXXX-XXXXXXXX""XXX-XXXXXXX""XXX-XXXXXXXX""XXXXXXX""XXXXXXXX)^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$
6. (0511-4405222021-87888822)\d{3}-\d{8}|\d{4}-\d{7}
7. (1518)^\d{15}|\d{18}$
8. (x结尾)^([0-9]){7,18}(x|X)?$ ^\d{8,18}|[0-9x]{8,18}|[0-9X]{8,18}?$
9. (5-16线)^[a-zA-Z][a-zA-Z0-9_]{4,15}$
10. (6~18线)^[a-zA-Z]\w{5,17}$
11. (使8-10)^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
12. ^\d{4}-\d{1,2}-\d{1,2}
13. 12(0109112)^(0?[1-9]|1[0-2])$
14. 31(0109131)^((0?[1-9])|((1|2)[0-9])|30|31)$
15.
16. 1.:"10000.00" "10,000.00", "分" "10000" "10,000"^[1-9][0-9]*$
17. 2.0,,"0",^(0|[1-9][0-9]*)$
18. 3.00.^(0|-?[1-9][0-9]*)$
19. 4.00.0.,.^[0-9]+(.[0-9]+)?$
20. 5.,1,"10.", "10" "10.2" ^[0-9]+(.[0-9]{2})?$
21. 6.,,^[0-9]+(.[0-9]{1,2})?$
22. 7..,^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
23 8.13, +3,,^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
24. ,"+""*"(,?),,
25. xml文件^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
26. [\u4e00-\u9fa5]
27. [^\x00-\xff] ((2ASCII字符计1))
28. \n\s*\r ()
29. HTML标记的正则表达式<(\S*?)[^>]*>.*?</\1>|<.*? /> ()
30. ^\s*|\s*$(^\s*)|(\s*$) (())
31. QQ号[1-9][0-9]{4,} (QQ号从10000开始)
32. [1-9]\d{5}(?!\d) (6)
33. IP地址\d+\.\d+\.\d+\.\d+ (IP地址时有用)
34. IP地址((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))
*/
public class CustomRegularValidationRule : ValidationRule
{
public CustomRegularValidationRule()
{
ValidatesOnTargetUpdated = true;
}
public string RegularString { get; set; } // 正则表达式规则
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
string str = value as string;
if (!string.IsNullOrWhiteSpace(str))
{
// 检查输入的字符串是否符合当前正则规范
if (!Regex.IsMatch(str, RegularString))
{
return new ValidationResult(false, "内容格式不正确");
}
}
return ValidationResult.ValidResult;
}
}
/// <summary>
/// 长度限制
/// </summary>
class LengthLimitValidationRule : ValidationRule
{
public LengthLimitValidationRule()
{
ValidatesOnTargetUpdated = true;
}
public double Minimum { get; set; }
public double Maximum { get; set; }
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
if (value == null) return ValidationResult.ValidResult;
double number = value.ToString().Length;
if (number > Maximum || number < Minimum)
{
return new ValidationResult(false, string.Format("值长度限制在 {0} 到 {1}", Minimum, Maximum));
}
return ValidationResult.ValidResult;
}
}
/// <summary>
/// ip规则验证
/// </summary>
public class IPAddressRule : ValidationRule
{
public IPAddressRule()
{
ValidatesOnTargetUpdated = true;
}
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
string IPAddress = value as string;
if (!string.IsNullOrWhiteSpace(IPAddress))
{
string IPAddressFormartRegex = @"^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$";
// 检查输入的字符串是否符合IP地址格式
if (!Regex.IsMatch(IPAddress, IPAddressFormartRegex))
{
return new ValidationResult(false, "IP地址格式不正确");
}
}
return ValidationResult.ValidResult;
}
}

35
dialog/BaseDialog.xaml Normal file
View File

@ -0,0 +1,35 @@
<Window x:Class="Zerolauncher.dialog.BaseDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:MyNamespace="clr-namespace:Zerolauncher.controls"
AllowsTransparency="True" WindowStyle="None" Background="Transparent"
Title="零蛋消息" Height="220" Width="360" MouseLeftButtonDown="Window_MouseLeftButtonDown">
<Window.Resources>
<Storyboard x:Key="BlinkAnimation">
<DoubleAnimation Storyboard.TargetProperty="Opacity"
From="1.0" To="0.5" Duration="0:0:0.5"
AutoReverse="True" RepeatBehavior="1" />
</Storyboard>
</Window.Resources>
<Grid>
<!-- 使用透明背景的PNG图片作为窗口的背景 -->
<Image x:Name="pic_bg" Source="/res/2.png" Stretch="Fill"/>
<DockPanel Margin="5">
<DockPanel DockPanel.Dock="Top">
<DockPanel.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../controls/AirButton.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</DockPanel.Resources>
<MyNamespace:AirButton Background="Transparent" Height="21" Width="30" Click="AirButton_Click" DockPanel.Dock="Right" BorderBrush="Transparent" Style="{StaticResource ChangeButtonIsMouseOver}">
<Image Source="/res/btn_close1.png"/>
</MyNamespace:AirButton>
<Label/>
</DockPanel>
<Grid Name="mControl" Margin="5"/>
</DockPanel>
</Grid>
</Window>

40
dialog/BaseDialog.xaml.cs Normal file
View File

@ -0,0 +1,40 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Zerolauncher.dialog
{
/// <summary>
/// BaseDialog.xaml 的交互逻辑
/// </summary>
public partial class BaseDialog : Window
{
//Storyboard storyboard;
public BaseDialog(UserControl control)
{
InitializeComponent();
//storyboard = FindResource("BlinkAnimation") as Storyboard;
mControl.Children.Add(control);
}
//protected override void OnDeactivated(EventArgs e)
//{
// base.OnDeactivated(e);
// // 当窗口失去焦点时,开始播放闪烁动画
// storyboard.Begin(this);
//}
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// 实现窗口的拖动
DragMove();
}
private void AirButton_Click(object sender, RoutedEventArgs e)
{
Close();
}
}
}

128
dialog/DialogHelper.cs Normal file
View File

@ -0,0 +1,128 @@
using System.Windows;
namespace Zerolauncher.dialog
{
class EditMemberDialog
{
static BaseDialog? baseDialog;
static EditMember? editControl;
public static int? member;
public static void CreateDailog(Window p, int? memberId)
{
if (editControl != null || baseDialog != null)
{
return;
}
member = memberId;
editControl = new EditMember();
baseDialog = new BaseDialog(editControl);
baseDialog.ShowDialog();
baseDialog = null;
editControl = null;
member = null;
}
public static void Close()
{
if (baseDialog != null)
{
baseDialog.Close();
}
}
}
class EditTeamDialog
{
static BaseDialog? baseDialog;
static EditTeamControl? editControl;
public static bool CreateDailog(Window p, string? oldTeamName=null)
{
if (editControl != null || baseDialog != null)
{
return false;
}
if (oldTeamName != null)
{
editControl = new EditTeamControl(true);
editControl.edit_name.Text = oldTeamName;
}
else
{
editControl = new EditTeamControl(false);
editControl.btn_del.Visibility = Visibility.Hidden;
}
baseDialog = new BaseDialog(editControl);
baseDialog.ShowDialog();
baseDialog = null;
editControl = null;
return true;
}
public static void Close()
{
if (baseDialog != null)
{
baseDialog.Close();
}
}
}
class AddMemebersDialog
{
static BaseDialog? baseDialog;
static UseAccDataTextAdd? editControl;
public static void CreateDailog(Window p)
{
if (editControl != null || baseDialog != null)
{
return;
}
editControl = new UseAccDataTextAdd();
baseDialog = new BaseDialog(editControl);
baseDialog.ShowDialog();
baseDialog = null;
editControl = null;
}
public static void Close()
{
if (baseDialog != null)
{
baseDialog.Close();
}
}
}
class UpdateDialog
{
static BaseDialog? baseDialog;
static DownloadControl? editControl;
public static void CreateDailog(Window p)
{
if (editControl != null || baseDialog != null)
{
return;
}
editControl = new DownloadControl();
baseDialog = new BaseDialog(editControl);
baseDialog.ShowDialog();
baseDialog = null;
editControl = null;
}
public static void Close()
{
if (baseDialog != null)
{
baseDialog.Close();
}
}
}
}

View File

@ -0,0 +1,14 @@
<UserControl x:Class="Zerolauncher.dialog.DownloadControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="169" d:DesignWidth="290">
<StackPanel Margin="5">
<Image Source="/res/39376.jpg" Height="100"/>
<TextBlock Text="零蛋正在更新装备..." Foreground="PaleGoldenrod" HorizontalAlignment="Center" Margin="5"/>
<ProgressBar Name="pbDown" HorizontalAlignment="Center" Height="10" Width="200" Value="50"/>
<Label Name="label1" Content="0 kb/s--50%" Foreground="BurlyWood" HorizontalAlignment="Center"/>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,104 @@
using System.IO;
using System.Net.Http;
using System.Windows.Controls;
namespace Zerolauncher.dialog
{
/// <summary>
/// DownloadControl.xaml 的交互逻辑
/// </summary>
public partial class DownloadControl : UserControl
{
const string cache_dir = "./.cache/auto.cache";
public DownloadControl()
{
InitializeComponent();
}
private void OnError(Exception ex)
{
// UnityEngine.Debug.Log("捕获异常 >>> " + ex);
}
public async Task Download(string fileUrl)
{
using (HttpClient client = new HttpClient())
{
// 获取文件大小
HttpResponseMessage responseHead = await client.SendAsync(new HttpRequestMessage(HttpMethod.Head, fileUrl));
long? contentLength = responseHead.Content.Headers.ContentLength;
Console.WriteLine($"文件大小:{contentLength} 字节");
// 计算块大小
int blockSize = 1024 * 1024; // 1MB
int blockCount = (int)Math.Ceiling((double)contentLength / blockSize);
// 创建SemaphoreSlim以限制同时进行的下载任务的数量
SemaphoreSlim semaphore = new SemaphoreSlim(4); // 最多允许4个并发下载任务
using (FileStream fileStream = new FileStream(cache_dir, FileMode.Create, FileAccess.Write, FileShare.None, blockSize, true))
{
// 创建任务列表
Task[] tasks = new Task[blockCount];
for (int i = 0; i < blockCount; i++)
{
int blockNumber = i;
tasks[i] = Task.Run(async () =>
{
await semaphore.WaitAsync(); // 等待获取许可
try
{
// 计算当前块的范围
var start = blockNumber * blockSize;
var end = (blockNumber == blockCount - 1) ? contentLength - 1 : start + blockSize - 1;
// 设置请求头,请求指定范围的数据
var request = new HttpRequestMessage { RequestUri = new Uri(fileUrl), Method = HttpMethod.Get };
request.Headers.Range = new System.Net.Http.Headers.RangeHeaderValue(start, end);
// 下载当前块
using (HttpResponseMessage response = await client.SendAsync(request))
{
response.EnsureSuccessStatusCode();
byte[] buffer = await response.Content.ReadAsByteArrayAsync();
await fileStream.WriteAsync(buffer, 0, buffer.Length);
}
// 显示下载进度
double percent = (double)(blockNumber + 1) / blockCount * 100;
Console.WriteLine($"已下载:{percent:F2}%");
}
finally
{
semaphore.Release(); // 释放许可
}
});
}
// 等待所有任务完成
await Task.WhenAll(tasks);
}
}
Console.WriteLine("下载完成!");
}
private void OnUpdate(long size, long count)
{
}
private void OnDone(byte[] data)
{
}
private void OnDestroy()
{
}
}
}

122
dialog/EditMember.xaml Normal file
View File

@ -0,0 +1,122 @@
<UserControl x:Class="Zerolauncher.dialog.EditMember"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="169" d:DesignWidth="290">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="1" Grid.RowSpan="2" Margin="2">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="btn_diy" Content="自定义图片"/>
<Button x:Name="btn_clut" Content="截取游戏" Grid.Row="1"/>
<Image Grid.Column="1" Grid.RowSpan="2" Source="/res/player_ico1.png"/>
</Grid>
<DockPanel Grid.ColumnSpan="1" Margin="2">
<Label Content="运营商:" Foreground="White"/>
<ComboBox Name="cb_pid"/>
</DockPanel>
<TextBox Name="edit_sid" Grid.Row="1" Margin="10,3,50,3" SelectionTextBrush="#4CFFFFFF">
<TextBox.Resources>
<VisualBrush x:Key="HelpBrush" TileMode="None" Opacity="0.7" Stretch="None" AlignmentX="Left">
<VisualBrush.Visual>
<TextBlock FontStyle="Italic" Text="请输入区服" Foreground="Cyan"/>
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Resources>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Background" Value="{StaticResource HelpBrush}"/>
</Trigger>
<Trigger Property="Text" Value="">
<Setter Property="Background" Value="{StaticResource HelpBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<TextBox Name="edit_acc" Grid.Row="2" Grid.ColumnSpan="2" Margin="10,2,50,2" SelectionTextBrush="#07FFFFFF">
<TextBox.Resources>
<VisualBrush x:Key="HelpBrush" TileMode="None" Opacity="0.7" Stretch="None" AlignmentX="Left">
<VisualBrush.Visual>
<TextBlock FontStyle="Italic" Text="请输入账号" Foreground="Cyan"/>
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Resources>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Background" Value="{StaticResource HelpBrush}"/>
</Trigger>
<Trigger Property="Text" Value="">
<Setter Property="Background" Value="{StaticResource HelpBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<PasswordBox Name="edit_pwd" Grid.Row="3" Grid.ColumnSpan="2" Margin="10,2,50,2" PasswordChanged="PasswordBox_PasswordChanged" >
<PasswordBox.Resources>
<VisualBrush x:Key="HelpBrush" TileMode="None" Opacity="0.7" Stretch="None" AlignmentX="Left">
<VisualBrush.Visual>
<TextBlock FontStyle="Italic" Text="请输入密码" Foreground="Cyan"/>
</VisualBrush.Visual>
</VisualBrush>
</PasswordBox.Resources>
<PasswordBox.Style>
<Style TargetType="PasswordBox">
<Setter Property="Background" Value="{StaticResource HelpBrush}"/>
</Style>
</PasswordBox.Style>
</PasswordBox>
<TextBox Name="edit_nick" Grid.Row="4" Grid.ColumnSpan="2" Margin="10,2,50,2">
<TextBox.Resources>
<VisualBrush x:Key="HelpBrush" TileMode="None" Opacity="0.7" Stretch="None" AlignmentX="Left">
<VisualBrush.Visual>
<TextBlock FontStyle="Italic" Text="请输入昵称重复昵称脚本调用只取1" Foreground="Red"/>
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Resources>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Background" Value="{StaticResource HelpBrush}"/>
</Trigger>
<Trigger Property="Text" Value="">
<Setter Property="Background" Value="{StaticResource HelpBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<DockPanel Grid.Row="5" Grid.Column="1" Margin="2">
<Button DockPanel.Dock="Right" Background="Transparent" Click="Button_Click" BorderBrush="Transparent">
<Image Source="/res/25.png"/>
</Button>
<Label/>
</DockPanel>
</Grid>
</UserControl>

80
dialog/EditMember.xaml.cs Normal file
View File

@ -0,0 +1,80 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using Zerolauncher.Manager;
namespace Zerolauncher.dialog
{
/// <summary>
/// EditMember.xaml 的交互逻辑
/// </summary>
public partial class EditMember : UserControl
{
private Dictionary<int, string> _services;
public EditMember()
{
_services = new Dictionary<int, string>();
int i = 0;
foreach (string serviceName in ServicesStaticInfo.ServicesName)
{
_services[i++] = serviceName;
}
InitializeComponent();
cb_pid.ItemsSource = _services;
if(EditMemberDialog.member != null)
{
int index = (int)EditMemberDialog.member;
var acc = AccountManager.accountsList[index];
cb_pid.SelectedIndex = acc.providerId;
edit_sid.Text = acc.serverId;
edit_acc.Text = acc.userName;
edit_pwd.Password = acc.userPWD;
edit_nick.Text = acc.nickName;
}
}
private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
VisualBrush helpBrush = passwordBox.Resources["HelpBrush"] as VisualBrush;
if (passwordBox.Password.Length > 0)
{
passwordBox.Background = new SolidColorBrush(Color.FromRgb(255, 255, 255));
}
else
{
passwordBox.Background = helpBrush;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if (string.IsNullOrEmpty(cb_pid.Text) || string.IsNullOrEmpty(edit_sid.Text) || string.IsNullOrEmpty(edit_acc.Text) || string.IsNullOrEmpty(edit_pwd.Password) || string.IsNullOrEmpty(edit_nick.Text))
{
MessageBox.Show("所有选项均不能为空!", "提示");
return;
}
if (EditMemberDialog.member == null)
{
AccountManager.AddAccount(new Account { providerId = cb_pid.SelectedIndex, serverId = edit_sid.Text, userName = edit_acc.Text, userPWD = edit_pwd.Password, nickName = edit_nick.Text });
EditMemberDialog.Close();
return;
}
int index = (int)EditMemberDialog.member;
var acc = AccountManager.accountsList[index];
acc.providerId = cb_pid.SelectedIndex;
acc.serverId = edit_sid.Text;
acc.userName = edit_acc.Text;
acc.userPWD = edit_pwd.Password;
acc.nickName = edit_nick.Text;
AccountManager.saveEdit();
EditMemberDialog.Close();
return;
}
}
}

View File

@ -0,0 +1,49 @@
<UserControl x:Class="Zerolauncher.dialog.EditTeamControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="169" d:DesignWidth="290">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Name="edit_name" Grid.Row="2" Margin="10,2,50,2" >
<TextBox.Resources>
<VisualBrush x:Key="HelpBrush" TileMode="None" Opacity="0.3" Stretch="None" AlignmentX="Left">
<VisualBrush.Visual>
<TextBlock FontStyle="Italic" Text="请输入队伍昵称" Foreground="#FFFFFDDD"/>
</VisualBrush.Visual>
</VisualBrush>
</TextBox.Resources>
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Background" Value="{StaticResource HelpBrush}"/>
</Trigger>
<Trigger Property="Text" Value="">
<Setter Property="Background" Value="{StaticResource HelpBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<DockPanel Grid.Row="5" Margin="2">
<Button DockPanel.Dock="Right" Background="Transparent" Click="Button_Click" BorderBrush="Transparent">
<Image Source="/res/25.png"/>
</Button>
<Button x:Name="btn_del" DockPanel.Dock="Left" Background="Transparent" Click="Button_Click_1" BorderBrush="Transparent">
<Image Source="/res/del.png"/>
</Button>
<Label/>
</DockPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,45 @@
using System.Windows;
using System.Windows.Controls;
using Zerolauncher.Manager;
namespace Zerolauncher.dialog
{
/// <summary>
/// EditTeamControl.xaml 的交互逻辑
/// </summary>
public partial class EditTeamControl : UserControl
{
bool isEditModle;
public EditTeamControl(bool isEditModle)
{
InitializeComponent();
this.isEditModle = isEditModle;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
if(string.IsNullOrEmpty(edit_name.Text))
{
MessageBox.Show("昵称不能为空!", "提示");
return;
}
if (isEditModle) AccountManager.editTeamName(edit_name.Text); else TeamManager.addTeam(edit_name.Text);
EditTeamDialog.Close();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
MessageBoxResult result = MessageBox.Show("即将放生此队伍以及队伍里所有的账号\n将会为你带来114点功德\n您确定要执行此操作吗", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Warning, MessageBoxResult.Cancel);
if (result == MessageBoxResult.OK)
{
if (!AccountManager.DeleteTeam())
{
MessageBox.Show("少爷这已经是最后一个队伍了!\n请新建一个队伍后再放生这个吧~", "提示");
}
}
}
}
}

View File

@ -0,0 +1,18 @@
<UserControl x:Class="Zerolauncher.dialog.UseAccDataTextAdd"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="169" d:DesignWidth="290">
<DockPanel Margin="5">
<TextBlock DockPanel.Dock="Top" Margin="5" Text="文本格式:一行一个账号,如:&#x0a; 服务器---区号---账号---密码---备注&#x0a;服务器填代号:&#x0a; 4399是07k7k是1第七大道是2" Foreground="#FFB44242"/>
<DockPanel DockPanel.Dock="Bottom">
<Button DockPanel.Dock="Right" Content="选择文件" Click="Button_Click"/>
<TextBox Name="input_split" DockPanel.Dock="Right" Text="---" Width="100"/>
<TextBlock DockPanel.Dock="Right" Text="分隔符:" Foreground="#FFEE9595"/>
<Label/>
</DockPanel>
<Label/>
</DockPanel>
</UserControl>

View File

@ -0,0 +1,70 @@
using Microsoft.Win32;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using Zerolauncher.Manager;
namespace Zerolauncher.dialog
{
/// <summary>
/// UseAccDataTextAdd.xaml 的交互逻辑
/// </summary>
public partial class UseAccDataTextAdd : UserControl
{
public UseAccDataTextAdd()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//创建一个打开文件式的对话框
OpenFileDialog ofd = new OpenFileDialog();
//设置这个对话框的起始打开路径
ofd.InitialDirectory = @"C:\";
//设置打开的文件的类型,注意过滤器的语法
ofd.Filter = "账号文本|*.txt|其他格式|*.";
//调用ShowDialog()方法显示该对话框,该方法的返回值代表用户是否点击了确定按钮
if (ofd.ShowDialog() == true)
{
string[] lines = File.ReadAllLines(ofd.FileName, Encoding.UTF8);
for (int i = 0; i < lines.Length; i++)
{
var accTexts = lines[i].Split(input_split.Text);
if (accTexts.Length != 5)
{
MessageBox.Show($"文本在{i}行非法!\n{lines[i]}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
var acc = new Account { };
if (!int.TryParse(accTexts[0], out acc.providerId))
{
MessageBox.Show($"输入的服务器代号错误!在{i}行\n错误[{lines[i]}]无法转换成服务器代号", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
if(0 < acc.providerId || acc.providerId > ServicesStaticInfo.ServicesName.Length)
{
MessageBox.Show($"输入的服务器代号错误!在{i}行\n错误[{acc.providerId}]不是有效的服务器代号", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
acc.serverId = accTexts[1];
acc.userName = accTexts[2];
acc.userPWD = accTexts[3];
acc.nickName = accTexts[4];
if (!AccountManager.AddAccounts(acc))
{
MessageBox.Show($"文本在{i}行出错!\n警告[{acc.nickName}]昵称冲突,将跳过添加此账号", "Warring", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
MessageBox.Show("添加完成!", "提示");
AccountManager.saveEdit();
AddMemebersDialog.Close();
}
else
{
MessageBox.Show("没有选择文件");
}
}
}
}

BIN
res/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 718 KiB

BIN
res/111.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
res/112.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
res/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB

BIN
res/21.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 488 B

BIN
res/22.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
res/24.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

BIN
res/25.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
res/319145.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 KiB

BIN
res/319163.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 KiB

BIN
res/39376.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
res/39389.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
res/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

BIN
res/5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 971 B

BIN
res/592342.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 583 KiB

BIN
res/592343.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 643 KiB

BIN
res/61.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
res/88657.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 KiB

BIN
res/RulePic/0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
res/RulePic/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
res/RulePic/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
res/RulePic/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
res/RulePic/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
res/about1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 903 KiB

BIN
res/btn_close1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
res/btn_mini1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
res/config.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

45
res/defaultUserData.json Normal file
View File

@ -0,0 +1,45 @@
{
"time": "Tue May 30 03:14:24 2023",
"pluginAcc": {"user": null, "pwd": null},
"lastTeamIndex": 0,
"teamAcc": [
{
"name": "队伍1",
"member": [
{
"nickName": "示范账号",
"user": "test",
"pwd": "test",
"providerId": 0,
"serverId": "179"
}
]
}
],
"serverList": {
"time": "Tue May 30 03:14:24 2023",
"Services": [
{
"name": "4399游戏",
"nick": "43",
"postUrl": "http://ptlogin.4399.com/ptlogin/login.do?v=1",
"loginBody": "loginFrom=uframe&postLoginHandler=default&layoutSelfAdapting=true&externalLogin=qq&displayMode=popup&layout=vertical&appId=www_home&mainDivId=popup_login_div&includeFcmInfo=false&userNameLabel=4399用户名&userNameTip=请输入4399用户名&welcomeTip=欢迎回到4399&username=%1&password=%2",
"gameUrl": "http://web.4399.com/stat/togame.php?target=ddt&server_id=S%1"
},
{
"name": "7k7k游戏",
"nick": "7k",
"postUrl": "http://zc.7k7k.com/post_login",
"loginBody": "username=%1&password=%2&rf=http://www.7k7k.com/#bottom",
"gameUrl": "http://web.7k7k.com/games/togame.php?target=ddt_7&server_id=%1"
},
{
"name": "7道",
"nick": "7道",
"postUrl": "http://zc.7k7k.com/post_login",
"loginBody": "username=%1&password=%2",
"gameUrl": "http://web.7k7k.com/games/togame.php?target=ddt_7&server_id=1"
}
]
}
}

BIN
res/del.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
res/player_ico.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
res/player_ico1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
res/title.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 KiB