添加项目文件。
29
AboutDialog/About1.xaml
Normal 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="关 于" Margin="20" FontSize="50" Foreground="OrangeRed"/>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock x:Name="info" Text=" 铃依登陆器 The best luancher 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>
|
||||||
28
AboutDialog/About1.xaml.cs
Normal 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
@ -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
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
35
Defender/EngineCacheSha.cs
Normal 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
@ -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
@ -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
@ -0,0 +1,7 @@
|
|||||||
|
namespace Zerolauncher.Manager
|
||||||
|
{
|
||||||
|
internal class ADManager
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
156
Manager/AccountManager.cs
Normal 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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
8
Manager/VersionManager.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Zerolauncher.Manager
|
||||||
|
{
|
||||||
|
class VersionManager
|
||||||
|
{
|
||||||
|
public static int GetMainVer() { return 10001; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
159
Manager/WebApiManager.cs
Normal 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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -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
@ -0,0 +1,3 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
</ResourceDictionary>
|
||||||
14
controls/MemberControl.xaml
Normal 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>
|
||||||
114
controls/MemberControl.xaml.cs
Normal 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
@ -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-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
|
||||||
|
7. 身份证号(15位、18位数字):^\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个月(01~09和1~12):^(0?[1-9]|1[0-2])$
|
||||||
|
14. 一个月的31天(01~09和1~31):^((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.一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
|
||||||
|
19. 4.这表示一个0或者一个可能为负的开头不为0的数字.让用户以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.1到3个数字,后面跟着任意个 逗号+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] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计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
@ -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
@ -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
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
dialog/DownloadControl.xaml
Normal 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>
|
||||||
104
dialog/DownloadControl.xaml.cs
Normal 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
@ -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
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
49
dialog/EditTeamControl.xaml
Normal 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>
|
||||||
45
dialog/EditTeamControl.xaml.cs
Normal 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请新建一个队伍后再放生这个吧~", "提示");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
18
dialog/UseAccDataTextAdd.xaml
Normal 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="文本格式:一行一个账号,如:
 服务器---区号---账号---密码---备注
服务器填代号:
 4399是0,7k7k是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>
|
||||||
70
dialog/UseAccDataTextAdd.xaml.cs
Normal 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/111.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
res/112.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
res/21.png
Normal file
|
After Width: | Height: | Size: 488 B |
BIN
res/22.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
res/24.png
Normal file
|
After Width: | Height: | Size: 566 B |
BIN
res/25.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
res/319145.jpg
Normal file
|
After Width: | Height: | Size: 214 KiB |
BIN
res/319163.jpg
Normal file
|
After Width: | Height: | Size: 474 KiB |
BIN
res/39376.jpg
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
res/39389.jpg
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
res/592342.jpg
Normal file
|
After Width: | Height: | Size: 583 KiB |
BIN
res/592343.jpg
Normal file
|
After Width: | Height: | Size: 643 KiB |
BIN
res/61.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
res/88657.jpg
Normal file
|
After Width: | Height: | Size: 420 KiB |
BIN
res/RulePic/0.png
Normal file
|
After Width: | Height: | Size: 75 KiB |
BIN
res/RulePic/1.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
res/RulePic/2.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
res/RulePic/3.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
res/RulePic/4.png
Normal file
|
After Width: | Height: | Size: 50 KiB |
BIN
res/about1.png
Normal file
|
After Width: | Height: | Size: 903 KiB |
BIN
res/btn_close1.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
res/btn_mini1.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
res/config.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
45
res/defaultUserData.json
Normal 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
|
After Width: | Height: | Size: 2.9 KiB |
BIN
res/player_ico.png
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
res/player_ico1.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
res/title.ico
Normal file
|
After Width: | Height: | Size: 270 KiB |
BIN
res/wp12470772-ddtank-wallpapers.jpg
Normal file
|
After Width: | Height: | Size: 194 KiB |
BIN
res/wp12470850-ddtank-wallpapers.jpg
Normal file
|
After Width: | Height: | Size: 216 KiB |