多人游戏数据传输

This commit is contained in:
ZouJin 2024-03-17 00:41:20 +08:00
parent 2037ff22c8
commit ea7088060f
8 changed files with 220 additions and 39 deletions

View File

@ -505,6 +505,10 @@ namespace VPet_Simulator.Core
bool petgridcrlf = true;
int nodisplayLoop = 0;
/// <summary>
/// 显示过的动画
/// </summary>
public event Action<GraphInfo> GraphDisplayHandler;
/// <summary>
/// 显示动画 (自动多层切换)
/// </summary>
/// <param name="graph">动画</param>
@ -540,6 +544,7 @@ namespace VPet_Simulator.Core
// Dispatcher.Invoke(() => Say(graph.GraphType.ToString()));
//}
DisplayType = graph.GraphInfo;
GraphDisplayHandler?.Invoke(graph.GraphInfo);
var PetGridTag = Dispatcher.Invoke(() => PetGrid.Tag);
var PetGrid2Tag = Dispatcher.Invoke(() => PetGrid2.Tag);
if (PetGridTag == graph)
@ -652,6 +657,9 @@ namespace VPet_Simulator.Core
}
}
/// <summary>
/// 显示夹层动画
/// </summary>

View File

@ -0,0 +1,62 @@
using LinePutScript;
using LinePutScript.Converter;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VPet_Simulator.Windows.Interface;
/// <summary>
/// 多人模式传输的消息
/// </summary>
public struct MPMessage
{
/// <summary>
/// 消息类型
/// </summary>
public enum MSGType
{
/// <summary>
/// 聊天消息 (string)
/// </summary>
Message,
/// <summary>
/// 显示动画 (graphinfo)
/// </summary>
DispayGraph,
/// <summary>
/// 摸身体
/// </summary>
TouchHead,
/// <summary>
/// 摸头
/// </summary>
TouchBody,
/// <summary>
/// 喂食
/// </summary>
Feed,
}
/// <summary>
/// 消息类型
/// </summary>
public MSGType Type;
/// <summary>
/// 消息内容
/// </summary>
public string Content;
/// <summary>
/// 操作来自者 (也可能是自己)
/// </summary>
public ulong From;
/// <summary>
/// 被操作者 (显示动画用)
/// </summary>
public ulong To;
public static string ConverTo(MPMessage data) => LPSConvert.SerializeObject(data).ToString();
public static MPMessage ConverTo(string data) => LPSConvert.DeserializeObject<MPMessage>(new LPS(data));
}

View File

@ -5,7 +5,7 @@
xmlns:ll="clr-namespace:LinePutScript.Localization.WPF;assembly=LinePutScript.Localization.WPF"
xmlns:pu="clr-namespace:Panuon.WPF.UI;assembly=Panuon.WPF.UI" Background="{x:Null}" WindowStyle="None"
SizeToContent="Height" xmlns:local="clr-namespace:VPet_Simulator.Windows" mc:Ignorable="d" ShowInTaskbar="False"
ResizeMode="NoResize" Title="MWFriends" Width="250" pu:WindowXCaption.Height="0">
ResizeMode="NoResize" Title="MWFriends" Width="250" pu:WindowXCaption.Height="0" Closed="WindowX_Closed">
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="-1" />
</WindowChrome.WindowChrome>

View File

@ -30,9 +30,10 @@ public partial class MPFriends : WindowX
public Lobby lb;
MainWindow mw;
public Friend friend;
public winMutiPlayer wmp;
public GameCore Core { get; set; } = new GameCore();
public List<Food> Foods { get; } = new List<Food>();
public ImageResources ImageSources { get; }
public ImageResources ImageSources { get; } = new ImageResources();
public List<PetLoader> Pets { get; set; } = new List<PetLoader>();
public ILine OnMod { get; set; }
@ -44,8 +45,9 @@ public partial class MPFriends : WindowX
return OnMod.Find(ModName.ToLower()) != null;
}
public MPFriends(MainWindow mw, Lobby lb, Friend friend)
public MPFriends(winMutiPlayer wmp, MainWindow mw, Lobby lb, Friend friend)
{
this.wmp = wmp;
this.mw = mw;
this.lb = lb;
this.friend = friend;
@ -206,23 +208,14 @@ public partial class MPFriends : WindowX
Main.Resources = Application.Current.Resources;
Main.MsgBar.This.Resources = Application.Current.Resources;
Main.ToolBar.Resources = Application.Current.Resources;
Main.ToolBar.LoadClean();
Main.ToolBar.LoadClean();
LoadingText.Content = "正在加载游戏\n该步骤可能会耗时比较长\n请耐心等待".Translate();
Main.PlayVoiceVolume = mw.Set.VoiceVolume;
Main.PlayVoiceVolume = mw.Set.VoiceVolume;
DisplayGrid.Child = Main;
Task.Run(async () =>
{
while (Main.IsWorking)
{
Thread.Sleep(100);
}
await Dispatcher.InvokeAsync(() => LoadingText.Visibility = Visibility.Collapsed);
});
Main.SetMoveMode(mw.Set.AllowMove, mw.Set.SmartMove, mw.Set.SmartMoveInterval * 1000);
Main.SetLogicInterval(1500);
if (mw.Set.MessageBarOutside)
@ -239,8 +232,30 @@ public partial class MPFriends : WindowX
new Point(pin[(gdbe)"px"], pin[(gdbe)"py"]), new Size(pin[(gdbe)"sw"], pin[(gdbe)"sh"])
, DisplayPinch, true));
}
SteamMatchmaking.OnLobbyMemberDataChanged += SteamMatchmaking_OnLobbyMemberDataChanged;
SteamMatchmaking.OnLobbyMemberLeave += SteamMatchmaking_OnLobbyMemberLeave;
Loaded = true;
LoadingText.Content = "{0}的{1}".Translate(friend.Name, Core.Save.Name);
LoadingText.Background = Function.ResourcesBrush(Function.BrushType.DARKPrimaryTransA);
LoadingText.VerticalAlignment = VerticalAlignment.Top;
}));
}
public new bool Loaded = false;
private void SteamMatchmaking_OnLobbyMemberLeave(Lobby lobby, Friend friend)
{
if (lobby.Id == lb.Id && friend.Id == this.friend.Id)
Quit();
}
private void SteamMatchmaking_OnLobbyMemberDataChanged(Lobby lobby, Friend friend)
{
if (lobby.Id == lb.Id && friend.Id == this.friend.Id)
{
Core.Save = GameSave_VPet.Load(new Line(lb.GetMemberData(friend, "save")));
}
}
/// <summary>
/// 显示捏脸情况
/// </summary>
@ -297,4 +312,23 @@ public partial class MPFriends : WindowX
Main.DisplayCEndtoNomal("pinch");
}
}
private void WindowX_Closed(object sender, EventArgs e)
{
wmp.MPFriends.Remove(this);
Loaded = false;
}
/// <summary>
/// 播放关闭动画并关闭,如果10秒后还未关闭则强制关闭
/// </summary>
public void Quit()
{
Main.Display(GraphType.Shutdown, AnimatType.Single, () => Dispatcher.Invoke(Close));
Task.Run(() =>
{
Thread.Sleep(5000);
if (Loaded)
Dispatcher.Invoke(Close);
});
}
}

View File

@ -1,11 +1,23 @@
<UserControl x:Class="VPet_Simulator.Windows.MPUserControl"
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"
xmlns:local="clr-namespace:VPet_Simulator.Windows"
mc:Ignorable="d" Margin="5" Width="360" Height="200" >
<Border x:Class="VPet_Simulator.Windows.MPUserControl" CornerRadius="5" BorderThickness="3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:pu="https://opensource.panuon.com/wpf-ui"
xmlns:ll="clr-namespace:LinePutScript.Localization.WPF;assembly=LinePutScript.Localization.WPF"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:VPet_Simulator.Windows"
mc:Ignorable="d" Margin="5" Width="360" Height="100" Background="{DynamicResource SecondaryLight}"
BorderBrush="{DynamicResource Secondary}">
<Grid>
<Image x:Name="uimg" HorizontalAlignment="Left" Source="/Res/TopLogo2019.PNG" Margin="4" />
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" Margin="110,0,0,0"
Foreground="{DynamicResource DARKPrimaryDarker}" FontSize="16">
<Run Text="{ll:Str 访客}" />: <Run x:Name="rPetName" Text="萝莉斯" FontSize="20" FontWeight="Bold" />
<LineBreak />
<Run Text="{ll:Str 来自}" />: <Run x:Name="hostName" Text="XXX" FontWeight="Bold" /><LineBreak />
<Run x:Name="info" Text="Lv 15" />
</TextBlock>
<Button Style="{DynamicResource ThemedButtonStyle}" HorizontalAlignment="Right" Content="{ll:Str 重置位置}"
VerticalAlignment="Top" Margin="10"/>
<Button Style="{DynamicResource ThemedButtonStyle}" HorizontalAlignment="Right" Content="{ll:Str 还没想好}"
VerticalAlignment="Bottom" Margin="10" />
</Grid>
</UserControl>
</Border>

View File

@ -1,7 +1,10 @@
using System;
using Steamworks;
using Steamworks.Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@ -11,16 +14,39 @@ using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VPet_Simulator.Windows.Interface;
namespace VPet_Simulator.Windows;
/// <summary>
/// MPUserControl.xaml 的交互逻辑
/// </summary>
public partial class MPUserControl : UserControl
public partial class MPUserControl : Border
{
public MPUserControl()
Friend friend => mpf.friend;
winMutiPlayer wmp;
MPFriends mpf;
Lobby lb => mpf.lb;
public MPUserControl(winMutiPlayer wmp, MPFriends mpf)
{
InitializeComponent();
this.wmp = wmp;
this.mpf = mpf;
Task.Run(LoadInfo);
}
public void LoadInfo()
{
//加载lobby传过来的数据
while (!mpf.Loaded)
{
Thread.Sleep(500);
}
Dispatcher.Invoke(async () =>
{
rPetName.Text = mpf.Core.Save.Name;
hostName.Text = friend.Name;
var img = await friend.GetMediumAvatarAsync();
uimg.Source = winMutiPlayer.ConvertToImageSource(img);
info.Text = "Lv " + mpf.Core.Save.Level;
});
}
}

View File

@ -12,7 +12,7 @@
Source="/Res/TopLogo2019.PNG" />
<TextBlock HorizontalAlignment="Left" VerticalAlignment="Top" Margin="120,20,0,0"
Foreground="{DynamicResource DARKPrimaryDarker}">
<Run Text="萝莉斯" FontSize="24" FontWeight="Bold" /> <Run Text="{ll:Str 的访客表}" />
<Run x:Name="hostPet" Text="萝莉斯" FontSize="24" FontWeight="Bold" /> <Run Text="{ll:Str 的访客表}" />
<LineBreak />
<Run Text="{ll:Str 主持人}" />: <Run x:Name="hostName" Text="XXX" /><LineBreak />
<Run Text="{ll:Str 访客表ID}" />:
@ -22,7 +22,7 @@
Foreground="{DynamicResource DARKPrimaryDarker}" Padding="0" />
<TabControl x:Name="tabControl" HorizontalAlignment="Left" Margin="15,115,15,15">
<TabItem Header="{ll:Str 访客列表}">
<StackPanel Background="{DynamicResource SecondaryLighter}" />
<StackPanel x:Name="MUUCList" Background="{DynamicResource SecondaryLighter}" />
</TabItem>
<TabItem Header="{ll:Str 消息日志}">
<TextBox x:Name="tbLog" Margin="0" BorderThickness="0" Background="{DynamicResource DARKPrimaryTrans4}"

View File

@ -1,13 +1,16 @@
using LinePutScript;
using LinePutScript.Converter;
using LinePutScript.Localization.WPF;
using Panuon.WPF.UI;
using Steamworks;
using Steamworks.Data;
using Steamworks.ServerList;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@ -17,6 +20,8 @@ using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using VPet_Simulator.Core;
using VPet_Simulator.Windows.Interface;
namespace VPet_Simulator.Windows;
/// <summary>
@ -29,7 +34,7 @@ public partial class winMutiPlayer : Window
/// <summary>
/// 好友宠物模块
/// </summary>
List<MPFriends> mFriends = new List<MPFriends>();
public List<MPFriends> MPFriends = new List<MPFriends>();
public winMutiPlayer(MainWindow mw, ulong? lobbyid = null)
{
InitializeComponent();
@ -66,8 +71,13 @@ public partial class winMutiPlayer : Window
swAllowJoin.Visibility = Visibility.Visible;
ShowLobbyInfo();
}
public static BitmapFrame ConvertToImageSource(Steamworks.Data.Image image)
public static ImageSource ConvertToImageSource(Steamworks.Data.Image? img)
{
if (img == null)
{
return new BitmapImage(new Uri("pack://application:,,,/Res/vpeticon.png"));
}
var image = img.Value;
int stride = (int)((image.Width * 32 + 7) / 8); // 32 bits per pixel
// Convert RGBA to BGRA
for (int i = 0; i < image.Data.Length; i += 4)
@ -103,21 +113,50 @@ public partial class winMutiPlayer : Window
lb.SetMemberData("petgraph", mw.Set.PetGraph);
SteamMatchmaking.OnLobbyDataChanged += SteamMatchmaking_OnLobbyDataChanged;
SteamMatchmaking.OnLobbyMemberDataChanged += SteamMatchmaking_OnLobbyMemberDataChanged;
SteamMatchmaking.OnLobbyMemberJoined += SteamMatchmaking_OnLobbyMemberJoined;
hostName.Text = lb.Owner.Name;
lbLid.Text = lb.Id.Value.ToString("x");
Steamworks.Data.Image? img = await lb.Owner.GetMediumAvatarAsync();
if (img.HasValue)
HostHead.Source = ConvertToImageSource(img.Value);
//给自己动画添加绑定
mw.Main.GraphDisplayHandler += Main_GraphDisplayHandler;
if (lb.Owner.Id == SteamClient.SteamId)
{
HostHead.Source = ConvertToImageSource(img.Value);
hostPet.Text = mw.GameSavesData.GameSave.Name;
Title = "{0}的访客表".Translate(mw.GameSavesData.GameSave.Name);
}
else
//获取成员列表
foreach (var v in lb.Members)
{
HostHead.Source = new BitmapImage(new Uri("pack://application:,,,/Res/vpeticon.png"));
if (v.Id == SteamClient.SteamId) continue;
var mpf = new MPFriends(this, mw, lb, v);
MPFriends.Add(mpf);
mpf.Show();
var mpuc = new MPUserControl(this, mpf);
MUUCList.Children.Add(mpuc);
if (v.Id == lb.Owner.Id)
_ = Task.Run(() =>
{
//加载lobby传过来的数据
while (!mpf.Loaded)
{
Thread.Sleep(500);
}
Dispatcher.Invoke(() =>
{
Title = "{0}的访客表".Translate(mpf.Core.Save.Name);
hostPet.Text = mpf.Core.Save.Name;
});
});
}
}
private void Main_GraphDisplayHandler(GraphInfo info)
{
lb.SendChatString(MPMessage.ConverTo(new MPMessage() { Type = MPMessage.MSGType.DispayGraph, Content = LPSConvert.SerializeObject(info).ToString() }));
}
private void SteamMatchmaking_OnLobbyMemberJoined(Lobby lobby, Friend friend)
{
if (lobby.Id == lb.Id)
@ -146,11 +185,11 @@ public partial class winMutiPlayer : Window
{
SteamMatchmaking.OnLobbyDataChanged -= SteamMatchmaking_OnLobbyDataChanged;
SteamMatchmaking.OnLobbyMemberDataChanged -= SteamMatchmaking_OnLobbyMemberDataChanged;
lb.SetMemberData("leave", DateTime.Now.ToString());
mw.Main.GraphDisplayHandler -= Main_GraphDisplayHandler;
lb.Leave();
foreach (var item in mFriends)
for (int i = 0; i < MPFriends.Count; i++)
{
item.Close();
MPFriends[i].Quit();
}
mw.winMutiPlayer = null;
}